fixes for 98% of all the warnings/errors reported by OS X gcc on tiger
[ardour.git] / libs / gtkmm2ext / bindings.cc
1 #include <iostream>
2
3 #include "pbd/xml++.h"
4 #include "pbd/convert.h"
5
6 #include "gtkmm2ext/actions.h"
7 #include "gtkmm2ext/bindings.h"
8 #include "gtkmm2ext/keyboard.h"
9
10 #include "i18n.h"
11
12 using namespace std;
13 using namespace Glib;
14 using namespace Gtk;
15 using namespace Gtkmm2ext;
16
17 uint32_t Bindings::_ignored_state = 0;
18
19 MouseButton::MouseButton (uint32_t state, uint32_t keycode)
20 {
21         uint32_t ignore = Bindings::ignored_state();
22         
23         if (gdk_keyval_is_upper (keycode) && gdk_keyval_is_lower (keycode)) {
24                 /* key is not subject to case, so ignore SHIFT
25                  */
26                 ignore |= GDK_SHIFT_MASK;
27         }
28
29         _val = (state & ~ignore);
30         _val <<= 32;
31         _val |= keycode;
32 };
33
34 bool
35 MouseButton::make_button (const string& str, MouseButton& b)
36 {
37         int s = 0;
38
39         if (str.find ("Primary") != string::npos) {
40                 s |= Keyboard::PrimaryModifier;
41         }
42
43         if (str.find ("Secondary") != string::npos) {
44                 s |= Keyboard::SecondaryModifier;
45         }
46
47         if (str.find ("Tertiary") != string::npos) {
48                 s |= Keyboard::TertiaryModifier;
49         }
50
51         if (str.find ("Level4") != string::npos) {
52                 s |= Keyboard::Level4Modifier;
53         }
54
55         string::size_type lastmod = str.find_last_of ('-');
56         uint32_t button_number;
57         
58         if (lastmod == string::npos) {
59                 button_number = PBD::atoi (str);
60         } else {
61                 button_number = PBD::atoi (str.substr (lastmod+1));
62         }
63
64         b = MouseButton (s, button_number);
65         return true;
66 }
67
68 string
69 MouseButton::name () const
70 {
71         int s = state();
72         
73         string str;
74
75         if (s & Keyboard::PrimaryModifier) {
76                 str += "Primary";
77         } 
78         if (s & Keyboard::SecondaryModifier) {
79                 if (!str.empty()) {
80                         str += '-';
81                 }
82                 str += "Secondary";
83         }
84         if (s & Keyboard::TertiaryModifier) {
85                 if (!str.empty()) {
86                         str += '-';
87                 }
88                 str += "Tertiary";
89         } 
90         if (s & Keyboard::Level4Modifier) {
91                 if (!str.empty()) {
92                         str += '-';
93                 }
94                 str += "Level4";
95         }
96         
97         if (!str.empty()) {
98                 str += '-';
99         }
100
101         char buf[16];
102         snprintf (buf, sizeof (buf), "%u", button());
103         str += buf;
104
105         return str;
106 }
107
108 KeyboardKey::KeyboardKey (uint32_t state, uint32_t keycode)
109 {
110         uint32_t ignore = Bindings::ignored_state();
111         
112         if (gdk_keyval_is_upper (keycode) && gdk_keyval_is_lower (keycode)) {
113                 /* key is not subject to case, so ignore SHIFT
114                  */
115                 ignore |= GDK_SHIFT_MASK;
116         }
117
118         _val = (state & ~ignore);
119         _val <<= 32;
120         _val |= keycode;
121 };
122
123
124 string
125 KeyboardKey::name () const
126 {
127         int s = state();
128         
129         string str;
130
131         if (s & Keyboard::PrimaryModifier) {
132                 str += "Primary";
133         } 
134         if (s & Keyboard::SecondaryModifier) {
135                 if (!str.empty()) {
136                         str += '-';
137                 }
138                 str += "Secondary";
139         }
140         if (s & Keyboard::TertiaryModifier) {
141                 if (!str.empty()) {
142                         str += '-';
143                 }
144                 str += "Tertiary";
145         } 
146         if (s & Keyboard::Level4Modifier) {
147                 if (!str.empty()) {
148                         str += '-';
149                 }
150                 str += "Level4";
151         }
152         
153         if (!str.empty()) {
154                 str += '-';
155         }
156
157         str += gdk_keyval_name (key());
158
159         return str;
160 }
161
162 bool
163 KeyboardKey::make_key (const string& str, KeyboardKey& k)
164 {
165         int s = 0;
166
167         if (str.find ("Primary") != string::npos) {
168                 s |= Keyboard::PrimaryModifier;
169         }
170
171         if (str.find ("Secondary") != string::npos) {
172                 s |= Keyboard::SecondaryModifier;
173         }
174
175         if (str.find ("Tertiary") != string::npos) {
176                 s |= Keyboard::TertiaryModifier;
177         }
178
179         if (str.find ("Level4") != string::npos) {
180                 s |= Keyboard::Level4Modifier;
181         }
182
183         string::size_type lastmod = str.find_last_of ('-');
184         guint keyval;
185
186         if (lastmod == string::npos) {
187                 keyval = gdk_keyval_from_name (str.c_str());
188         } else {
189                 keyval = gdk_keyval_from_name (str.substr (lastmod+1).c_str());
190         }
191
192         if (keyval == GDK_VoidSymbol) {
193                 return false;
194         }
195
196         k = KeyboardKey (s, keyval);
197         return true;
198 }
199
200 Bindings::Bindings ()
201         : action_map (0)
202 {
203 }
204
205 Bindings::~Bindings()
206 {
207 }
208
209 void
210 Bindings::set_action_map (ActionMap& am)
211 {
212         action_map = &am;
213         press_bindings.clear ();
214         release_bindings.clear ();
215 }
216
217 bool
218 Bindings::activate (KeyboardKey kb, Operation op)
219 {
220         KeybindingMap* kbm = 0;
221
222         switch (op) {
223         case Press:
224                 kbm = &press_bindings;
225                 break;
226         case Release:
227                 kbm = &release_bindings;
228                 break;
229         }
230
231         KeybindingMap::iterator k = kbm->find (kb);
232
233         if (k == kbm->end()) {
234                 /* no entry for this key in the state map */
235                 return false;
236         }
237
238         /* lets do it ... */
239
240         k->second->activate ();
241         return true;
242 }
243
244 void
245 Bindings::add (KeyboardKey kb, Operation op, RefPtr<Action> what)
246 {
247         KeybindingMap* kbm = 0;
248
249         switch (op) {
250         case Press:
251                 kbm = &press_bindings;
252                 break;
253         case Release:
254                 kbm = &release_bindings;
255                 break;
256         }
257
258         KeybindingMap::iterator k = kbm->find (kb);
259
260         if (k == kbm->end()) {
261                 pair<KeyboardKey,RefPtr<Action> > newpair (kb, what);
262                 kbm->insert (newpair);
263                 cerr << "Bindings added " << kb.key() << " w/ " << kb.state() << " => " << what->get_name() << endl;
264         } else {
265                 k->second = what;
266         }
267 }
268
269 void
270 Bindings::remove (KeyboardKey kb, Operation op)
271 {
272         KeybindingMap* kbm = 0;
273
274         switch (op) {
275         case Press:
276                 kbm = &press_bindings;
277                 break;
278         case Release:
279                 kbm = &release_bindings;
280                 break;
281         }
282
283         KeybindingMap::iterator k = kbm->find (kb);
284
285         if (k != kbm->end()) {
286                 kbm->erase (k);
287         }
288 }
289
290 bool
291 Bindings::activate (MouseButton bb, Operation op)
292 {
293         MouseButtonBindingMap* bbm = 0;
294
295         switch (op) {
296         case Press:
297                 bbm = &button_press_bindings;
298                 break;
299         case Release:
300                 bbm = &button_release_bindings;
301                 break;
302         }
303
304         MouseButtonBindingMap::iterator b = bbm->find (bb);
305         
306         if (b == bbm->end()) {
307                 /* no entry for this key in the state map */
308                 return false;
309         }
310
311         /* lets do it ... */
312
313         b->second->activate ();
314         return true;
315 }
316
317 void
318 Bindings::add (MouseButton bb, Operation op, RefPtr<Action> what)
319 {
320         MouseButtonBindingMap* bbm = 0;
321
322         switch (op) {
323         case Press:
324                 bbm = &button_press_bindings;
325                 break;
326         case Release:
327                 bbm = &button_release_bindings;
328                 break;
329         }
330
331         MouseButtonBindingMap::iterator b = bbm->find (bb);
332
333         if (b == bbm->end()) {
334                 pair<MouseButton,RefPtr<Action> > newpair (bb, what);
335                 bbm->insert (newpair);
336                 cerr << "Bindings added mouse button " << bb.button() << " w/ " << bb.state() << " => " << what->get_name() << endl;
337         } else {
338                 b->second = what;
339         }
340 }
341
342 void
343 Bindings::remove (MouseButton bb, Operation op)
344 {
345         MouseButtonBindingMap* bbm = 0;
346
347         switch (op) {
348         case Press:
349                 bbm = &button_press_bindings;
350                 break;
351         case Release:
352                 bbm = &button_release_bindings;
353                 break;
354         }
355         
356         MouseButtonBindingMap::iterator b = bbm->find (bb);
357
358         if (b != bbm->end()) {
359                 bbm->erase (b);
360         }
361 }
362
363 bool
364 Bindings::save (const string& path)
365 {
366         XMLTree tree;
367         XMLNode* root = new XMLNode (X_("Bindings"));
368         tree.set_root (root);
369         
370         save (*root);
371
372         if (!tree.write (path)) {
373                 ::unlink (path.c_str());
374                 return false;
375         }
376
377         return true;
378 }
379
380 void
381 Bindings::save (XMLNode& root)
382 {
383         XMLNode* presses = new XMLNode (X_("Press"));
384         root.add_child_nocopy (*presses);
385
386         for (KeybindingMap::iterator k = press_bindings.begin(); k != press_bindings.end(); ++k) {
387                 XMLNode* child;
388                 child = new XMLNode (X_("Binding"));
389                 child->add_property (X_("key"), k->first.name());
390                 string ap = k->second->get_accel_path();
391                 child->add_property (X_("action"), ap.substr (ap.find ('/') + 1));
392                 presses->add_child_nocopy (*child);
393         }
394
395         for (MouseButtonBindingMap::iterator k = button_press_bindings.begin(); k != button_press_bindings.end(); ++k) {
396                 XMLNode* child;
397                 child = new XMLNode (X_("Binding"));
398                 child->add_property (X_("button"), k->first.name());
399                 string ap = k->second->get_accel_path();
400                 child->add_property (X_("action"), ap.substr (ap.find ('/') + 1));
401                 presses->add_child_nocopy (*child);
402         }
403
404         XMLNode* releases = new XMLNode (X_("Release"));
405         root.add_child_nocopy (*releases);
406
407         for (KeybindingMap::iterator k = release_bindings.begin(); k != release_bindings.end(); ++k) {
408                 XMLNode* child;
409                 child = new XMLNode (X_("Binding"));
410                 child->add_property (X_("key"), k->first.name());
411                 string ap = k->second->get_accel_path();
412                 child->add_property (X_("action"), ap.substr (ap.find ('/') + 1));
413                 releases->add_child_nocopy (*child);
414         }
415
416         for (MouseButtonBindingMap::iterator k = button_release_bindings.begin(); k != button_release_bindings.end(); ++k) {
417                 XMLNode* child;
418                 child = new XMLNode (X_("Binding"));
419                 child->add_property (X_("button"), k->first.name());
420                 string ap = k->second->get_accel_path();
421                 child->add_property (X_("action"), ap.substr (ap.find ('/') + 1));
422                 releases->add_child_nocopy (*child);
423         }
424
425 }
426
427 bool
428 Bindings::load (const string& path)
429 {
430         XMLTree tree;
431
432         if (!action_map) {
433                 return false;
434         }
435
436         if (!tree.read (path)) {
437                 return false;
438         }
439         
440         press_bindings.clear ();
441         release_bindings.clear ();
442
443         XMLNode& root (*tree.root());
444         const XMLNodeList& children (root.children());
445
446         for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
447                 load (**i);
448         }
449
450         return true;
451 }
452
453 void
454 Bindings::load (const XMLNode& node)
455 {
456         if (node.name() == X_("Press") || node.name() == X_("Release")) {
457                 
458                 Operation op;
459                 
460                 if (node.name() == X_("Press")) {
461                         op = Press;
462                 } else {
463                         op = Release;
464                 }
465                 
466                 const XMLNodeList& children (node.children());
467                 
468                 for (XMLNodeList::const_iterator p = children.begin(); p != children.end(); ++p) {
469                         
470                         XMLProperty* ap;
471                         XMLProperty* kp;
472                         XMLProperty* bp;
473                         
474                         ap = (*p)->property ("action");
475                         kp = (*p)->property ("key");
476                         bp = (*p)->property ("button");
477                         
478                         if (!ap || (!kp && !bp)) {
479                                 continue;
480                         }
481
482                         RefPtr<Action> act;
483
484                         if (action_map) {
485                                 act = action_map->find_action (ap->value());
486                         } 
487
488                         if (!act) {
489                                 string::size_type slash = ap->value().find ('/');
490                                 if (slash != string::npos) {
491                                         string group = ap->value().substr (0, slash);
492                                         string action = ap->value().substr (slash+1);
493                                         act = ActionManager::get_action (group.c_str(), action.c_str());
494                                 }
495                         }
496                         
497                         if (!act) {
498                                 continue;
499                         }
500                         
501                         if (kp) {
502                                 KeyboardKey k;
503                                 if (!KeyboardKey::make_key (kp->value(), k)) {
504                                         continue;
505                                 }
506                                 add (k, op, act);
507                         } else {
508                                 MouseButton b;
509                                 if (!MouseButton::make_button (bp->value(), b)) {
510                                         continue;
511                                 }
512                                 add (b, op, act);
513                         }
514                 }
515         }
516 }        
517
518 RefPtr<Action>
519 ActionMap::find_action (const string& name)
520 {
521         _ActionMap::iterator a = actions.find (name);
522
523         if (a != actions.end()) {
524                 return a->second;
525         }
526
527         return RefPtr<Action>();
528 }
529
530 RefPtr<Action> 
531 ActionMap::register_action (const char* path,
532                             const char* name, const char* label, sigc::slot<void> sl)
533 {
534         string fullpath;
535
536         RefPtr<Action> act = Action::create (name, label);
537
538         act->signal_activate().connect (sl);
539
540         fullpath = path;
541         fullpath += '/';
542         fullpath += name;
543
544         actions.insert (_ActionMap::value_type (fullpath, act));
545         return act;
546 }
547
548 RefPtr<Action> 
549 ActionMap::register_radio_action (const char* path, Gtk::RadioAction::Group& rgroup,
550                                   const char* name, const char* label, 
551                                   sigc::slot<void,GtkAction*> sl,
552                                   int value)
553 {
554         string fullpath;
555
556         RefPtr<Action> act = RadioAction::create (rgroup, name, label);
557         RefPtr<RadioAction> ract = RefPtr<RadioAction>::cast_dynamic(act);
558         ract->property_value() = value;
559
560         act->signal_activate().connect (sigc::bind (sl, act->gobj()));
561
562         fullpath = path;
563         fullpath += '/';
564         fullpath += name;
565
566         actions.insert (_ActionMap::value_type (fullpath, act));
567         return act;
568 }
569
570 RefPtr<Action> 
571 ActionMap::register_toggle_action (const char* path,
572                                    const char* name, const char* label, sigc::slot<void> sl)
573 {
574         string fullpath;
575
576         RefPtr<Action> act = ToggleAction::create (name, label);
577
578         act->signal_activate().connect (sl);
579
580         fullpath = path;
581         fullpath += '/';
582         fullpath += name;
583
584         actions.insert (_ActionMap::value_type (fullpath, act));
585         return act;
586 }