ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/DC/BindingEditor.pm
Revision: 1.2
Committed: Sun Jul 2 18:52:05 2006 UTC (18 years ago) by root
Branch: MAIN
Changes since 1.1: +131 -18 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 package CFClient::BindingEditor;
2
3 use strict;
4
5 use CFClient::UI;
6
7 our @ISA = CFClient::UI::FancyFrame::;
8
9 my @ALLOWED_MODIFIER_KEYS = (
10 CFClient::SDLK_LSHIFT,
11 CFClient::SDLK_LCTRL ,
12 CFClient::SDLK_LALT ,
13 CFClient::SDLK_LMETA ,
14
15 CFClient::SDLK_RSHIFT,
16 CFClient::SDLK_RCTRL ,
17 CFClient::SDLK_RALT ,
18 CFClient::SDLK_RMETA ,
19 );
20
21 my %ALLOWED_MODIFIERS = (
22 CFClient::KMOD_LSHIFT => "LSHIFT",
23 CFClient::KMOD_LCTRL => "LCTRL",
24 CFClient::KMOD_LALT => "LALT",
25 CFClient::KMOD_LMETA => "LMETA",
26
27 CFClient::KMOD_RSHIFT => "RSHIFT",
28 CFClient::KMOD_RCTRL => "RCTRL",
29 CFClient::KMOD_RALT => "RALT",
30 CFClient::KMOD_RMETA => "RMETA",
31 );
32
33 my %DIRECT_BIND_CHARS = map { $_ => 1 } qw/0 1 2 3 4 5 6 7 8 9/;
34 my @DIRECT_BIND_KEYS = (
35 CFClient::SDLK_F1,
36 CFClient::SDLK_F2,
37 CFClient::SDLK_F3,
38 CFClient::SDLK_F4,
39 CFClient::SDLK_F5,
40 CFClient::SDLK_F6,
41 CFClient::SDLK_F7,
42 CFClient::SDLK_F8,
43 CFClient::SDLK_F9,
44 CFClient::SDLK_F10,
45 CFClient::SDLK_F11,
46 CFClient::SDLK_F12,
47 CFClient::SDLK_F13,
48 CFClient::SDLK_F14,
49 CFClient::SDLK_F15,
50 );
51
52 sub keycombo_to_name {
53 my ($mod, $sym) = @_;
54
55 my $mods = join '+',
56 map { $ALLOWED_MODIFIERS{$_} }
57 grep { ($_ + 0) & ($mod + 0) }
58 keys %ALLOWED_MODIFIERS;
59 $mods .= "+" if $mods ne '';
60
61 return $mods . CFClient::SDL_GetKeyName ($sym);
62 }
63
64 sub new {
65 my $class = shift;
66
67 my $self = $class->SUPER::new (
68 binding => [],
69 commands => [],
70 title => "Macro/Keybinding Recorder",
71 @_
72 );
73
74 $self->add (my $vb = new CFClient::UI::VBox);
75
76 $vb->add ($self->{rec_btn} = new CFClient::UI::Button
77 text => "start recording",
78 tooltip => "Start/Stops recording of actions."
79 ."All subsequent actions after the recording started will be captured."
80 ."The actions are displayed after the record was stopped."
81 ."To bind the action you have to click on the 'Bind' button",
82 on_activate => sub {
83 unless ($self->{recording}) {
84 $self->start;
85 } else {
86 $self->stop;
87 }
88 });
89
90 $vb->add (new CFClient::UI::Label text => "Actions:");
91 $vb->add ($self->{cmdbox} = new CFClient::UI::VBox);
92
93 $vb->add (new CFClient::UI::Label text => "Bound to: ");
94 $vb->add (my $hb = new CFClient::UI::HBox);
95 $hb->add ($self->{keylbl} = new CFClient::UI::Label expand => 1);
96 $hb->add (new CFClient::UI::Button
97 text => "bind",
98 tooltip => "This opens a query where you have to press the key combination to bind the recorded actions",
99 on_activate => sub {
100 $self->ask_for_bind;
101 });
102
103 $vb->add (my $hb = new CFClient::UI::HBox);
104 $hb->add (new CFClient::UI::Button
105 text => "OK",
106 expand => 1,
107 tooltip => "This closes the binding editor and saves the binding",
108 on_activate => sub {
109 (delete $self->{binder})->destroy if $self->{binder};
110 $self->hide;
111 $self->commit;
112 0
113 });
114
115 $hb->add (new CFClient::UI::Button
116 text => "Cancel",
117 expand => 1,
118 tooltip => "This closes the binding editor without saving",
119 on_activate => sub {
120 (delete $self->{binder})->destroy if $self->{binder};
121 $self->hide;
122 $self->{binding_cancel}->()
123 if $self->{binding_cancel};
124 0
125 });
126
127 $self->update_binding_widgets;
128
129 $self
130 }
131
132 sub cfg_bind {
133 my ($self, $mod, $sym, $cmds) = @_;
134 $::CFG->{profile}{default}{bindings}{$mod}{$sym} = $cmds;
135 ::update_bindings ();
136 }
137
138 sub cfg_unbind {
139 my ($self, $mod, $sym, $cmds) = @_;
140 delete $::CFG->{profile}{default}{bindings}{$mod}{$sym};
141 ::update_bindings ();
142 }
143
144 sub commit {
145 my ($self) = @_;
146
147 my ($mod, $sym, $cmds) = $self->get_binding;
148
149 if ($sym != 0 && @$cmds > 0) {
150 $::STATUSBOX->add ("Bound actions to <i>" . keycombo_to_name ($mod, $sym) . "</i>. "
151 . "Do not forget to 'Save Config'!");
152 $self->{binding_change}->($mod, $sym, $cmds)
153 if $self->{binding_change};
154 } else {
155 $::STATUSBOX->add ("No action bound, no key or action specified!");
156 $self->{binding_cancel}->()
157 if $self->{binding_cancel};
158 }
159 }
160
161 sub start {
162 my ($self) = @_;
163
164 $self->{rec_btn}->set_text ("stop recording");
165 $self->{recording} = 1;
166 $self->clear_command_list;
167 $::CONN->start_record if $::CONN;
168 }
169
170 sub stop {
171 my ($self) = @_;
172
173 $self->{rec_btn}->set_text ("start recording");
174 $self->{recording} = 0;
175
176 my $rec;
177 $rec = $::CONN->stop_record if $::CONN;
178 return unless ref $rec eq 'ARRAY';
179 $self->set_command_list ($rec);
180 }
181
182 sub ask_for_bind {
183 my ($self, $commit, $end_cb) = @_;
184
185 return if $self->{binder};
186
187 Scalar::Util::weaken $self;
188
189 $self->{binder} = new CFClient::UI::FancyFrame
190 title => "Bind Action",
191 x => "center",
192 y => "center",
193 z => 1000,
194 has_close_button => 1,
195 on_delete => sub {
196 (delete $self->{binder})->destroy;
197 1
198 },
199 ;
200
201 $self->{binder}->add (my $vb = new CFClient::UI::VBox);
202 $vb->add (new CFClient::UI::Label
203 text => "Press a modifier (CTRL, ALT and/or SHIFT) and a key."
204 . "You can only bind 0-9 and F1-F15 without modifiers."
205 );
206 $vb->add (my $entry = new CFClient::UI::Entry
207 text => "",
208 on_key_down => sub {
209 my ($entry, $ev) = @_;
210
211 my $mod = $ev->{mod};
212 my $sym = $ev->{sym};
213
214 # XXX: This seems a little bit hackisch to me, but I have to ignore them
215 return if grep { $_ == $sym } @ALLOWED_MODIFIER_KEYS;
216
217 if ($mod == CFClient::KMOD_NONE
218 and not $DIRECT_BIND_CHARS{chr ($ev->{unicode})}
219 and not grep { $sym == $_ } @DIRECT_BIND_KEYS)
220 {
221 $::STATUSBOX->add (
222 "Cannot bind key " . CFClient::SDL_GetKeyName ($sym) . " directly without modifier, "
223 . "as those keys are reserved for the command completer."
224 );
225 return;
226 }
227
228 $entry->grab_focus;
229
230 $self->{binding} = [$mod, $sym];
231 $self->update_binding_widgets;
232 $self->commit if $commit;
233 $end_cb->() if $end_cb;
234
235 warn "dexxey $self $self->{binder}\n";#d#
236 (delete $self->{binder})->destroy;
237 1
238 },
239 on_focus_out => sub {
240 # segfaults and worse :()
241 #(delete $self->{binder})->destroy if $self->{binder};
242 1
243 },
244 );
245
246 $entry->grab_focus;
247 $self->{binder}->show;
248 }
249
250 # $mod and $sym are the modifiers and key symbol
251 # $cmds is a array ref of strings (the commands)
252 # $cb is the callback that is executed on OK
253 # $ccb is the callback that is executed on CANCEL and
254 # when the binding was unsuccessful on OK
255 sub set_binding {
256 my ($self, $mod, $sym, $cmds, $cb, $ccb) = @_;
257
258 $self->clear_command_list;
259 $self->{recording} = 0;
260 $self->{rec_btn}->set_text ("start recording");
261
262 $self->{binding} = [$mod, $sym];
263 $self->{commands} = $cmds;
264
265 $self->{binding_change} = $cb;
266 $self->{binding_cancel} = $ccb;
267
268 $self->update_binding_widgets;
269 }
270
271 # this is a shortcut method that asks for a binding
272 # and then just binds it.
273 sub do_quick_binding {
274 my ($self, $cmds, $end_cb) = @_;
275 $self->set_binding (undef, undef, $cmds, sub { $self->cfg_bind (@_) });
276 $self->ask_for_bind (1, $end_cb);
277 }
278
279 sub update_binding_widgets {
280 my ($self) = @_;
281 my ($mod, $sym, $cmds) = $self->get_binding;
282 $self->{keylbl}->set_text (keycombo_to_name ($mod, $sym));
283 $self->set_command_list ($cmds);
284 }
285
286 sub get_binding {
287 my ($self) = @_;
288 return (
289 $self->{binding}->[0],
290 $self->{binding}->[1],
291 [ grep { defined $_ } @{$self->{commands}} ]
292 );
293 }
294
295 sub clear_command_list {
296 my ($self) = @_;
297 $self->{cmdbox}->clear ();
298 }
299
300 sub set_command_list {
301 my ($self, $cmds) = @_;
302
303 $self->{cmdbox}->clear ();
304 $self->{commands} = $cmds;
305
306 my $idx = 0;
307
308 for (@$cmds) {
309 $self->{cmdbox}->add (my $hb = new CFClient::UI::HBox);
310
311 my $i = $idx;
312 $hb->add (new CFClient::UI::Label text => $_);
313 $hb->add (new CFClient::UI::Button
314 text => "delete",
315 tooltip => "Deletes the action from the record",
316 on_activate => sub {
317 $self->{cmdbox}->remove ($hb);
318 $cmds->[$i] = undef;
319 });
320
321
322 $idx++
323 }
324 }
325
326 1