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.7 by root, Sun Oct 1 14:48:51 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);
32
33my %DIRECT_BIND_CHARS = map { $_ => 1 } qw/0 1 2 3 4 5 6 7 8 9/;
34my @DIRECT_BIND_KEYS = (
35 CFPlus::SDLK_F1,
36 CFPlus::SDLK_F2,
37 CFPlus::SDLK_F3,
38 CFPlus::SDLK_F4,
39 CFPlus::SDLK_F5,
40 CFPlus::SDLK_F6,
41 CFPlus::SDLK_F7,
42 CFPlus::SDLK_F8,
43 CFPlus::SDLK_F9,
44 CFPlus::SDLK_F10,
45 CFPlus::SDLK_F11,
46 CFPlus::SDLK_F12,
47 CFPlus::SDLK_F13,
48 CFPlus::SDLK_F14,
49 CFPlus::SDLK_F15,
50);
51
52sub 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 . CFPlus::SDL_GetKeyName ($sym);
62}
6 63
7sub new { 64sub new {
8 my $class = shift; 65 my $class = shift;
9 66
10 my $self = $class->SUPER::new ( 67 my $self = $class->SUPER::new (
12 commands => [], 69 commands => [],
13 title => "Macro/Keybinding Recorder", 70 title => "Macro/Keybinding Recorder",
14 @_ 71 @_
15 ); 72 );
16 73
17 $self->add (my $vb = new CFClient::UI::VBox); 74 $self->add (my $vb = new CFPlus::UI::VBox);
18 75
19 $vb->add ($self->{rec_btn} = new CFClient::UI::Button 76 $vb->add ($self->{rec_btn} = new CFPlus::UI::Button
20 text => "start recording", 77 text => "start recording",
21 tooltip => "Start/Stops recording of actions." 78 tooltip => "Start/Stops recording of actions."
22 ."All subsequent actions after the recording started will be captured." 79 ."All subsequent actions after the recording started will be captured."
23 ."The actions are displayed after the record was stopped." 80 ."The actions are displayed after the record was stopped."
24 ."To bind the action you have to click on the 'Bind' button", 81 ."To bind the action you have to click on the 'Bind' button",
28 } else { 85 } else {
29 $self->stop; 86 $self->stop;
30 } 87 }
31 }); 88 });
32 89
33 $vb->add (new CFClient::UI::Label text => "Actions:"); 90 $vb->add (new CFPlus::UI::Label text => "Actions:");
34 $vb->add ($self->{cmdbox} = new CFClient::UI::VBox); 91 $vb->add ($self->{cmdbox} = new CFPlus::UI::VBox);
35 92
36 $vb->add (new CFClient::UI::Label text => "Bound to: "); 93 $vb->add (new CFPlus::UI::Label text => "Bound to: ");
37 $vb->add (my $hb = new CFClient::UI::HBox); 94 $vb->add (my $hb = new CFPlus::UI::HBox);
38 $hb->add ($self->{keylbl} = new CFClient::UI::Label expand => 1); 95 $hb->add ($self->{keylbl} = new CFPlus::UI::Label expand => 1);
39 $hb->add (new CFClient::UI::Button 96 $hb->add (new CFPlus::UI::Button
40 text => "bind", 97 text => "bind",
41 tooltip => "This opens a query where you have to press the key combination to bind the recorded actions", 98 tooltip => "This opens a query where you have to press the key combination to bind the recorded actions",
42 on_activate => sub { 99 on_activate => sub {
43 $self->ask_for_bind; 100 $self->ask_for_bind;
44 }); 101 });
45 102
46 $vb->add (my $hb = new CFClient::UI::HBox); 103 $vb->add (my $hb = new CFPlus::UI::HBox);
47 $hb->add (new CFClient::UI::Button 104 $hb->add (new CFPlus::UI::Button
48 text => "ok", 105 text => "OK",
49 expand => 1, 106 expand => 1,
50 tooltip => "This closes the binding editor and saves the binding", 107 tooltip => "This closes the binding editor and saves the binding",
51 on_activate => sub { 108 on_activate => sub {
109 (delete $self->{binder})->destroy if $self->{binder};
52 $self->hide; 110 $self->hide;
53 $self->commit; 111 $self->commit;
112 0
54 }); 113 });
55 114
56 $hb->add (new CFClient::UI::Button 115 $hb->add (new CFPlus::UI::Button
57 text => "cancel", 116 text => "Cancel",
58 expand => 1, 117 expand => 1,
59 tooltip => "This closes the binding editor without saving", 118 tooltip => "This closes the binding editor without saving",
60 on_activate => sub { 119 on_activate => sub {
120 (delete $self->{binder})->destroy if $self->{binder};
61 $self->hide; 121 $self->hide;
62 $self->{binding_cancel}->() 122 $self->{binding_cancel}->()
63 if $self->{binding_cancel}; 123 if $self->{binding_cancel};
124 0
64 }); 125 });
65 126
66 $self->update_binding_widgets; 127 $self->update_binding_widgets;
67 128
68 $self 129 $self
69} 130}
70 131
71sub cfg_bind { 132sub cfg_bind {
72 my ($self, $mod, $sym, $cmds) = @_; 133 my ($self, $mod, $sym, $cmds) = @_;
73 $::CFG->{profile}{default}{bindings}{$mod}{$sym} = $cmds; 134 $::PROFILE->{bindings}{$mod}{$sym} = $cmds;
74 ::update_bindings (); 135 ::update_bindings ();
75} 136}
76 137
77sub cfg_unbind { 138sub cfg_unbind {
78 my ($self, $mod, $sym, $cmds) = @_; 139 my ($self, $mod, $sym, $cmds) = @_;
79 delete $::CFG->{profile}{default}{bindings}{$mod}{$sym}; 140 delete $::PROFILE->{bindings}{$mod}{$sym};
80 ::update_bindings (); 141 ::update_bindings ();
81} 142}
82 143
83sub commit { 144sub commit {
84 my ($self) = @_; 145 my ($self) = @_;
146
85 my ($mod, $sym, $cmds) = $self->get_binding; 147 my ($mod, $sym, $cmds) = $self->get_binding;
148
86 if ($sym != 0 && @$cmds > 0) { 149 if ($sym != 0 && @$cmds > 0) {
87 $::STATUSBOX->add ("Bound actions to '".CFClient::Binder::keycombo_to_name ($mod, $sym) 150 $::STATUSBOX->add ("Bound actions to <i>" . keycombo_to_name ($mod, $sym) . "</i>. "
88 ."'. Don't forget 'Save Config'!"); 151 . "Do not forget to 'Save Config'!");
89 $self->{binding_change}->($mod, $sym, $cmds) 152 $self->{binding_change}->($mod, $sym, $cmds)
90 if $self->{binding_change}; 153 if $self->{binding_change};
91 } else { 154 } else {
92 $::STATUSBOX->add ("No action bound, no key or action specified!"); 155 $::STATUSBOX->add ("No action bound, no key or action specified!");
93 $self->{binding_cancel}->() 156 $self->{binding_cancel}->()
114 $rec = $::CONN->stop_record if $::CONN; 177 $rec = $::CONN->stop_record if $::CONN;
115 return unless ref $rec eq 'ARRAY'; 178 return unless ref $rec eq 'ARRAY';
116 $self->set_command_list ($rec); 179 $self->set_command_list ($rec);
117} 180}
118 181
119
120sub ask_for_bind_and_commit {
121 my ($self) = @_;
122 $self->ask_for_bind (1);
123}
124
125sub ask_for_bind { 182sub ask_for_bind {
126 my ($self, $commit, $end_cb) = @_; 183 my ($self, $commit, $end_cb) = @_;
127 184
128 CFClient::Binder::open_binding_dialog (sub { 185 return if $self->{binder};
129 my ($mod, $sym) = @_; 186
130 $self->{binding} = [$mod, $sym]; # XXX: how to stop that memleak? 187 Scalar::Util::weaken $self;
188
189 $self->{binder} = new CFPlus::UI::Toplevel
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 CFPlus::UI::VBox);
202 $vb->add (new CFPlus::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 CFPlus::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 == CFPlus::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 " . CFPlus::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];
131 $self->update_binding_widgets; 231 $self->update_binding_widgets;
132 $self->commit if $commit; 232 $self->commit if $commit;
133 $end_cb->() if $end_cb; 233 $end_cb->() if $end_cb;
234
235 if (my $binder = delete $self->{binder}) {
236 $binder->destroy;
237 }
238 1
239 },
240 on_focus_out => sub {
241 # segfaults and worse :()
242 #(delete $self->{binder})->destroy if $self->{binder};
243 1
244 },
134 }); 245 );
246
247 $entry->grab_focus;
248 $self->{binder}->show;
135} 249}
136 250
137# $mod and $sym are the modifiers and key symbol 251# $mod and $sym are the modifiers and key symbol
138# $cmds is a array ref of strings (the commands) 252# $cmds is a array ref of strings (the commands)
139# $cb is the callback that is executed on OK 253# $cb is the callback that is executed on OK
164} 278}
165 279
166sub update_binding_widgets { 280sub update_binding_widgets {
167 my ($self) = @_; 281 my ($self) = @_;
168 my ($mod, $sym, $cmds) = $self->get_binding; 282 my ($mod, $sym, $cmds) = $self->get_binding;
169 $self->{keylbl}->set_text (CFClient::Binder::keycombo_to_name ($mod, $sym)); 283 $self->{keylbl}->set_text (keycombo_to_name ($mod, $sym));
170 $self->set_command_list ($cmds); 284 $self->set_command_list ($cmds);
171} 285}
172 286
173sub get_binding { 287sub get_binding {
174 my ($self) = @_; 288 my ($self) = @_;
191 $self->{commands} = $cmds; 305 $self->{commands} = $cmds;
192 306
193 my $idx = 0; 307 my $idx = 0;
194 308
195 for (@$cmds) { 309 for (@$cmds) {
196 $self->{cmdbox}->add (my $hb = new CFClient::UI::HBox); 310 $self->{cmdbox}->add (my $hb = new CFPlus::UI::HBox);
197 311
198 my $i = $idx; 312 my $i = $idx;
199 $hb->add (new CFClient::UI::Label text => $_); 313 $hb->add (new CFPlus::UI::Label text => $_);
200 $hb->add (new CFClient::UI::Button 314 $hb->add (new CFPlus::UI::Button
201 text => "delete", 315 text => "delete",
202 tooltip => "Deletes the action from the record", 316 tooltip => "Deletes the action from the record",
203 on_activate => sub { 317 on_activate => sub {
204 $self->{cmdbox}->remove ($hb); 318 $self->{cmdbox}->remove ($hb);
205 $cmds->[$i] = undef; 319 $cmds->[$i] = undef;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines