line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Kephra::CommandList;
|
2
|
|
|
|
|
|
|
our $VERSION = '0.15';
|
3
|
|
|
|
|
|
|
|
4
|
1
|
|
|
1
|
|
1590
|
use strict;
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
37
|
|
5
|
1
|
|
|
1
|
|
7
|
use warnings;
|
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
113
|
|
6
|
1
|
|
|
1
|
|
6
|
use YAML::Tiny();
|
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
254
|
|
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
my %list; # the real commandlist
|
10
|
|
|
|
|
|
|
my @keymap; # maps numerical key code to cmd call ref
|
11
|
0
|
0
|
|
0
|
0
|
|
sub data { if (ref $_[0] eq 'HASH') { %list = %{$_[0]} } else { \%list } }
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
12
|
0
|
|
|
0
|
0
|
|
sub clear { %list = () }
|
13
|
0
|
|
|
0
|
0
|
|
sub file { Kephra::Config::filepath( _config()->{file}) }
|
14
|
0
|
|
|
0
|
|
|
sub _config{ Kephra::API::settings()->{app}{commandlist} }
|
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
#sub load_cache { %list = %{ YAML::Tiny::LoadFile( $_[0] ) }}
|
17
|
|
|
|
|
|
|
#sub store_cache { YAML::Tiny::DumpFile( \%list ) }
|
18
|
|
|
|
|
|
|
# @hash1{keys %hash2} = values %hash2;
|
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
# refactor commandlist definition & localisation data into a format that can be
|
22
|
|
|
|
|
|
|
# evaled and used by gui parts
|
23
|
|
|
|
|
|
|
sub load {
|
24
|
0
|
|
|
0
|
0
|
|
my $cmd_list_def = Kephra::Config::File::load_from_node_data( _config() );
|
25
|
0
|
0
|
|
|
|
|
$cmd_list_def = Kephra::Config::Default::commandlist() unless $cmd_list_def;
|
26
|
0
|
|
|
|
|
|
assemble_data($cmd_list_def);
|
27
|
|
|
|
|
|
|
}
|
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
sub assemble_data {
|
31
|
0
|
|
|
0
|
0
|
|
my $cmd_list_def = shift;
|
32
|
1
|
|
|
1
|
|
5
|
no strict;
|
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
263
|
|
33
|
0
|
|
|
|
|
|
local ($leaf_type, $cmd_id, $target_leafe);
|
34
|
|
|
|
|
|
|
# copy data of a hash structures into specified commandlist leafes
|
35
|
0
|
|
|
|
|
|
for my $key ( qw{call enable enable_event state state_event key icon} ) {
|
36
|
0
|
|
|
|
|
|
_copy_values_of_nested_list($cmd_list_def->{$key}, $key);
|
37
|
|
|
|
|
|
|
}
|
38
|
0
|
|
|
|
|
|
my $l18n = Kephra::Config::Localisation::strings();
|
39
|
0
|
|
|
|
|
|
_copy_values_of_nested_list($l18n->{commandlist}{label},'label');
|
40
|
0
|
|
|
|
|
|
_copy_values_of_nested_list($l18n->{commandlist}{help}, 'help');
|
41
|
0
|
|
|
|
|
|
numify_key_code( keys %list );
|
42
|
0
|
|
|
|
|
|
undef $leaf_type;
|
43
|
0
|
|
|
|
|
|
undef $cmd_id;
|
44
|
0
|
|
|
|
|
|
undef $target_leafe;
|
45
|
|
|
|
|
|
|
}
|
46
|
|
|
|
|
|
|
|
47
|
0
|
|
|
0
|
0
|
|
sub eval_data { eval_cmd_data( keys %list ) }
|
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
sub _copy_values_of_nested_list {
|
50
|
0
|
|
|
0
|
|
|
my $root_node = shift; # source
|
51
|
1
|
|
|
1
|
|
6
|
no strict;
|
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
93
|
|
52
|
0
|
|
|
|
|
|
$target_leafe = shift;
|
53
|
0
|
0
|
|
|
|
|
_parse_and_copy_node($root_node, '') if ref $root_node eq 'HASH';
|
54
|
|
|
|
|
|
|
}
|
55
|
|
|
|
|
|
|
sub _parse_and_copy_node {
|
56
|
0
|
|
|
0
|
|
|
my ($parent_node, $parent_id) = @_;
|
57
|
1
|
|
|
1
|
|
5
|
no strict;
|
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
1538
|
|
58
|
0
|
|
|
|
|
|
for ( keys %$parent_node ){
|
59
|
0
|
|
|
|
|
|
$cmd_id = $parent_id . $_;
|
60
|
0
|
|
|
|
|
|
$leaf_type = ref $parent_node->{$_};
|
61
|
0
|
0
|
|
|
|
|
if (not $leaf_type) {
|
|
|
0
|
|
|
|
|
|
62
|
0
|
0
|
|
|
|
|
$list{$cmd_id}{$target_leafe} = $parent_node->{$_}
|
63
|
|
|
|
|
|
|
if $parent_node->{$_};
|
64
|
|
|
|
|
|
|
} elsif ($leaf_type eq 'HASH'){
|
65
|
0
|
|
|
|
|
|
_parse_and_copy_node($parent_node->{$_}, $cmd_id . '-')
|
66
|
|
|
|
|
|
|
}
|
67
|
|
|
|
|
|
|
}
|
68
|
|
|
|
|
|
|
}
|
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
sub numify_key_code {
|
72
|
0
|
|
|
0
|
0
|
|
my @cmd = @_;
|
73
|
0
|
|
|
|
|
|
my ($item_data, $rest, $kcode, $kname, $i, $char); #rawdata, keycode
|
74
|
0
|
|
|
|
|
|
my $k18n = Kephra::Config::Localisation::strings()->{key};
|
75
|
0
|
|
|
|
|
|
my $shift = $k18n->{meta}{shift}. '+';
|
76
|
0
|
|
|
|
|
|
my $alt = $k18n->{meta}{alt} . '+';
|
77
|
0
|
|
|
|
|
|
my $ctrl = $k18n->{meta}{ctrl} . '+';
|
78
|
0
|
|
|
|
|
|
my %keycode_map = (
|
79
|
|
|
|
|
|
|
back => &Wx::WXK_BACK, tab => &Wx::WXK_TAB, enter => &Wx::WXK_RETURN,
|
80
|
|
|
|
|
|
|
esc => &Wx::WXK_ESCAPE, space => &Wx::WXK_SPACE,
|
81
|
|
|
|
|
|
|
plus => 43, minus => 45, sharp => 47, tilde => 92,
|
82
|
|
|
|
|
|
|
del=> &Wx::WXK_DELETE, ins => &Wx::WXK_INSERT,
|
83
|
|
|
|
|
|
|
pgup => &Wx::WXK_PAGEUP, pgdn => &Wx::WXK_PAGEDOWN,
|
84
|
|
|
|
|
|
|
home => &Wx::WXK_HOME, end => &Wx::WXK_END,
|
85
|
|
|
|
|
|
|
left => &Wx::WXK_LEFT, up => &Wx::WXK_UP,
|
86
|
|
|
|
|
|
|
right => &Wx::WXK_RIGHT, down => &Wx::WXK_DOWN,
|
87
|
|
|
|
|
|
|
f1 => &Wx::WXK_F1, f2 => &Wx::WXK_F2, f3 => &Wx::WXK_F3, f4 => &Wx::WXK_F4,
|
88
|
|
|
|
|
|
|
f5 => &Wx::WXK_F5, f6 => &Wx::WXK_F6, f7 => &Wx::WXK_F7, f8 => &Wx::WXK_F8,
|
89
|
|
|
|
|
|
|
f9 => &Wx::WXK_F9,f10 => &Wx::WXK_F10,f11 => &Wx::WXK_F11,f12 => &Wx::WXK_F12,
|
90
|
|
|
|
|
|
|
numpad_enter => &Wx::WXK_NUMPAD_ENTER
|
91
|
|
|
|
|
|
|
);
|
92
|
0
|
|
|
|
|
|
for (@cmd){
|
93
|
0
|
|
|
|
|
|
$item_data = $list{$_};
|
94
|
0
|
0
|
|
|
|
|
next unless exists $item_data->{key};
|
95
|
0
|
|
|
|
|
|
$rest = $item_data->{key};
|
96
|
0
|
|
|
|
|
|
$kname = '';
|
97
|
0
|
|
|
|
|
|
$kcode = 0;
|
98
|
0
|
|
|
|
|
|
while (){
|
99
|
0
|
|
|
|
|
|
$i = index $rest, '+';
|
100
|
0
|
0
|
|
|
|
|
last unless $i > 0;
|
101
|
0
|
|
|
|
|
|
$char = lc substr $rest, 0, 1;
|
102
|
0
|
0
|
|
|
|
|
if ($char eq 's') {$kname .= $shift; $kcode += 1000}
|
|
0
|
0
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
103
|
0
|
|
|
|
|
|
elsif ($char eq 'c') {$kname .= $ctrl; $kcode += 2000}
|
|
0
|
|
|
|
|
|
|
104
|
0
|
|
|
|
|
|
elsif ($char eq 'a') {$kname .= $alt; $kcode += 4000}
|
105
|
0
|
|
|
|
|
|
$rest = substr $rest, $i + 1;
|
106
|
|
|
|
|
|
|
}
|
107
|
0
|
0
|
|
|
|
|
$kname .= exists $k18n->{$rest}
|
108
|
|
|
|
|
|
|
? $k18n->{$rest}
|
109
|
|
|
|
|
|
|
: ucfirst $rest;
|
110
|
0
|
|
|
|
|
|
$item_data->{key} = $kname;
|
111
|
0
|
0
|
|
|
|
|
$kcode += length($rest) == 1
|
112
|
|
|
|
|
|
|
? ord uc $rest
|
113
|
|
|
|
|
|
|
: $keycode_map{$rest};
|
114
|
0
|
|
|
|
|
|
$item_data->{keycode} = $kcode;
|
115
|
|
|
|
|
|
|
}
|
116
|
|
|
|
|
|
|
}
|
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
sub eval_cmd_data {
|
119
|
0
|
|
|
0
|
0
|
|
my @cmd = @_;
|
120
|
0
|
|
|
|
|
|
my ($item_data, $ico_path);
|
121
|
0
|
|
|
|
|
|
for (@cmd){
|
122
|
0
|
|
|
|
|
|
my $item_data = $list{$_};
|
123
|
0
|
|
|
|
|
|
$item_data->{sub} = $item_data->{call};
|
124
|
0
|
0
|
|
|
|
|
$item_data->{sub} =~ tr/()&;/ /d if $item_data->{sub};
|
125
|
0
|
|
|
|
|
|
for my $node_type (qw(call state enable)) {
|
126
|
0
|
0
|
|
|
|
|
$item_data->{$node_type} = eval 'sub {'.$item_data->{$node_type}.'}'
|
127
|
|
|
|
|
|
|
if $item_data->{$node_type};
|
128
|
|
|
|
|
|
|
}
|
129
|
0
|
0
|
0
|
|
|
|
if ($item_data->{call} and $item_data->{key}){
|
130
|
0
|
|
|
|
|
|
$keymap[$item_data->{keycode}] = $item_data->{call};
|
131
|
|
|
|
|
|
|
}
|
132
|
0
|
0
|
|
|
|
|
next unless $item_data->{icon};
|
133
|
0
|
|
|
|
|
|
$item_data->{icon} = Kephra::Config::icon_bitmap($item_data->{icon});
|
134
|
|
|
|
|
|
|
}
|
135
|
|
|
|
|
|
|
}
|
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
#
|
139
|
|
|
|
|
|
|
# external API - getting cmd date, manipulating content
|
140
|
|
|
|
|
|
|
#
|
141
|
0
|
0
|
|
0
|
0
|
|
sub new_cmd { replace_cmd(@_) unless exists $list{ $_[0] } }
|
142
|
|
|
|
|
|
|
sub new_cmd_list {
|
143
|
0
|
|
|
0
|
0
|
|
for (@_) {
|
144
|
|
|
|
|
|
|
#new_cmd();
|
145
|
|
|
|
|
|
|
}
|
146
|
|
|
|
|
|
|
}
|
147
|
|
|
|
|
|
|
sub replace_cmd {
|
148
|
0
|
|
|
0
|
0
|
|
my ($cmd_id, $properties) = @_;
|
149
|
0
|
0
|
|
|
|
|
return unless ref $properties eq 'HASH';
|
150
|
|
|
|
|
|
|
# if node exist, copy juste assigned values
|
151
|
0
|
0
|
|
|
|
|
if ( exists $list{$cmd_id}) {
|
152
|
0
|
|
|
|
|
|
$list{$cmd_id}{$_} = $properties->{$_} for keys %$properties;
|
153
|
|
|
|
|
|
|
}
|
154
|
0
|
|
|
|
|
|
else { $list{$cmd_id} = $properties }
|
155
|
0
|
|
|
|
|
|
numify_key_code($cmd_id);
|
156
|
0
|
|
|
|
|
|
eval_cmd_data($cmd_id);
|
157
|
|
|
|
|
|
|
}
|
158
|
|
|
|
|
|
|
|
159
|
0
|
|
|
0
|
0
|
|
sub del_cmd { delete @list{$_[0]} }
|
160
|
|
|
|
|
|
|
sub rename_cmd {
|
161
|
0
|
|
|
0
|
0
|
|
my ($old_ID, $new_ID) = @_;
|
162
|
0
|
0
|
0
|
|
|
|
return unless $new_ID and ref $list{$old_ID} eq 'HASH';
|
163
|
0
|
|
|
|
|
|
$list{$new_ID} = $list{$old_ID};
|
164
|
0
|
|
|
|
|
|
del_cmd($old_ID);
|
165
|
|
|
|
|
|
|
}
|
166
|
|
|
|
|
|
|
sub get_cmd_property { # explicit value of one command
|
167
|
0
|
|
|
0
|
0
|
|
my $cmd_id = shift;
|
168
|
0
|
|
|
|
|
|
my $leafe = shift;
|
169
|
0
|
0
|
0
|
|
|
|
$list{$cmd_id}{$leafe}
|
170
|
|
|
|
|
|
|
if ref $list{$cmd_id} eq 'HASH'
|
171
|
|
|
|
|
|
|
and exists $list{$cmd_id}{$leafe};
|
172
|
|
|
|
|
|
|
}
|
173
|
|
|
|
|
|
|
sub get_cmd_properties { # all values of one command
|
174
|
0
|
|
|
0
|
0
|
|
my $cmd_id = shift;
|
175
|
0
|
0
|
|
|
|
|
$list{$cmd_id} if ref $list{$cmd_id} eq 'HASH';
|
176
|
|
|
|
|
|
|
}
|
177
|
|
|
|
|
|
|
sub get_property_list { # values of same type from different commands
|
178
|
0
|
|
|
0
|
0
|
|
my $property = shift;
|
179
|
0
|
|
|
|
|
|
my @result;
|
180
|
0
|
|
|
|
|
|
for (@_) {
|
181
|
0
|
0
|
|
|
|
|
push @result, $list{$_}{$property} if exists $list{$_}{$property}
|
182
|
|
|
|
|
|
|
}
|
183
|
0
|
|
|
|
|
|
return @result;
|
184
|
|
|
|
|
|
|
}
|
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
sub run_cmd_by_id {
|
187
|
0
|
|
|
0
|
0
|
|
my $cmd_id = shift;
|
188
|
0
|
0
|
|
|
|
|
$list{$cmd_id}{call}() if ref $list{$cmd_id}{call} eq 'CODE';
|
189
|
|
|
|
|
|
|
}
|
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
sub run_cmd_by_keycode {
|
192
|
0
|
|
|
0
|
0
|
|
my $keycode = shift;
|
193
|
0
|
0
|
|
|
|
|
if (ref $keymap[$keycode] eq 'CODE'){
|
194
|
0
|
|
|
|
|
|
$keymap[$keycode]();
|
195
|
0
|
|
|
|
|
|
return 1;
|
196
|
|
|
|
|
|
|
}
|
197
|
0
|
|
|
|
|
|
return 0;
|
198
|
|
|
|
|
|
|
}
|
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
sub del_temp_data{
|
201
|
0
|
|
|
0
|
0
|
|
my $l18n = Kephra::Config::Localisation::strings();
|
202
|
0
|
0
|
|
|
|
|
delete $l18n->{commandlist} if exists $l18n->{commandlist};
|
203
|
|
|
|
|
|
|
#delete $Kephra::localisation{key}
|
204
|
|
|
|
|
|
|
# if exists $l18n->{key};
|
205
|
|
|
|
|
|
|
}
|
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
=head1 NAME
|
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
Kephra::API::CommandList - external API for user callable functions
|
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
=head1 DESCRIPTION
|
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
The CommandList is a dynamically changeable list, that contains all the
|
214
|
|
|
|
|
|
|
function calls for every menu item, toolbar button and most other widget items.
|
215
|
|
|
|
|
|
|
It holds also label, help text, key binding, icon and more for each command.
|
216
|
|
|
|
|
|
|
All these properties have to be changed globally here in a clean way.
|
217
|
|
|
|
|
|
|
These commands where used by different gui elements, that allows menu and
|
218
|
|
|
|
|
|
|
toolbar definitions to be very compact, readable and and easy changeable.
|
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
Names of commands contain dashes as separator of namespaces.
|
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
=head1 SPECIFICATION
|
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
CommandlistItem
|
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
=over 4
|
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
=item * ID - unique identifier, hashkey, following hash is its value
|
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
=item * call - CODEREF : actual action, performed when this command is called
|
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
=item * sub - string : name of the called routine
|
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
=item * enable - CODEREF : returns enable status (0 for disable)
|
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
=item * enable_event - string : API::EventTable ID when to check to en/disable
|
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
=item * state - CODEREF : that returns state value (for switches)
|
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
=item * state_event - string : API::EventTable ID when to check is state changed
|
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
=item * label - string : descriptive name
|
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
=item * help - string : short help sentence
|
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
=item * key - string : label of key binding
|
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
=item * keycode - numeric keycode
|
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
=item * icon - Wx::Bitmap
|
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
=back
|
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
=cut
|
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
1;
|