ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/DC/BindingEditor.pm
(Generate patch)

Comparing deliantra/Deliantra-Client/DC/BindingEditor.pm (file contents):
Revision 1.1 by root, Mon Jun 26 21:59:04 2006 UTC vs.
Revision 1.8 by elmex, Thu Oct 26 20:45:06 2006 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines