1e8ef03fa025113ec2043a2a8970a8515f558be4
[ardour.git] / libs / gtkmm2ext / bindings.cc
1 #include <iostream>
2 #include "pbd/xml++.h"
3 #include "gtkmm2ext/bindings.h"
4 #include "gtkmm2ext/keyboard.h"
5
6 #include "i18n.h"
7
8 using namespace std;
9 using namespace Glib;
10 using namespace Gtk;
11 using namespace Gtkmm2ext;
12
13 string
14 KeyboardKey::name () const
15 {
16         int s = state();
17         
18         string str;
19
20         if (s & Keyboard::PrimaryModifier) {
21                 str += "Primary";
22         } 
23         if (s & Keyboard::SecondaryModifier) {
24                 if (!str.empty()) {
25                         str += '-';
26                 }
27                 str += "Secondary";
28         }
29         if (s & Keyboard::TertiaryModifier) {
30                 if (!str.empty()) {
31                         str += '-';
32                 }
33                 str += "Tertiary";
34         } 
35         if (s & Keyboard::Level4Modifier) {
36                 if (!str.empty()) {
37                         str += '-';
38                 }
39                 str += "Level4";
40         }
41         
42         if (!str.empty()) {
43                 str += '-';
44         }
45
46         str += gdk_keyval_name (key());
47
48         return str;
49 }
50
51 bool
52 KeyboardKey::make_key (const string& str, KeyboardKey& k)
53 {
54         int s = 0;
55
56         if (str.find ("Primary") != string::npos) {
57                 s |= Keyboard::PrimaryModifier;
58         }
59
60         if (str.find ("Secondary") != string::npos) {
61                 s |= Keyboard::SecondaryModifier;
62         }
63
64         if (str.find ("Tertiary") != string::npos) {
65                 s |= Keyboard::TertiaryModifier;
66         }
67
68         if (str.find ("Level4") != string::npos) {
69                 s |= Keyboard::Level4Modifier;
70         }
71
72         string::size_type lastmod = str.find_last_of ('-');
73         guint keyval;
74
75         if (lastmod == string::npos) {
76                 keyval = gdk_keyval_from_name (str.c_str());
77         } else {
78                 keyval = gdk_keyval_from_name (str.substr (lastmod+1).c_str());
79         }
80
81         if (keyval == GDK_VoidSymbol) {
82                 return false;
83         }
84
85         k = KeyboardKey (s, keyval);
86         return true;
87 }
88
89 Bindings::Bindings ()
90         : action_map (0)
91 {
92 }
93
94 Bindings::~Bindings()
95 {
96 }
97
98 void
99 Bindings::set_action_map (ActionMap& am)
100 {
101         action_map = &am;
102         press_bindings.clear ();
103         release_bindings.clear ();
104 }
105
106 bool
107 Bindings::activate (KeyboardKey kb, KeyboardKey::Operation op)
108 {
109         KeybindingMap* kbm;
110
111         switch (op) {
112         case KeyboardKey::Press:
113                 kbm = &press_bindings;
114                 break;
115         case KeyboardKey::Release:
116                 kbm = &release_bindings;
117                 break;
118         }
119
120         KeybindingMap::iterator k = kbm->find (kb);
121
122         if (k == kbm->end()) {
123                 /* no entry for this key in the state map */
124                 return false;
125         }
126
127         /* lets do it ... */
128
129         cerr << "Firing up " << k->second->get_name() << endl;
130         k->second->activate ();
131         return true;
132 }
133
134 void
135 Bindings::add (KeyboardKey kb, KeyboardKey::Operation op, RefPtr<Action> what)
136 {
137         KeybindingMap* kbm;
138
139         switch (op) {
140         case KeyboardKey::Press:
141                 kbm = &press_bindings;
142                 break;
143         case KeyboardKey::Release:
144                 kbm = &release_bindings;
145                 break;
146         }
147
148         KeybindingMap::iterator k = kbm->find (kb);
149
150         if (k == kbm->end()) {
151                 pair<KeyboardKey,RefPtr<Action> > newpair (kb, what);
152                 kbm->insert (newpair);
153         } else {
154                 k->second = what;
155         }
156 }
157
158 void
159 Bindings::remove (KeyboardKey kb, KeyboardKey::Operation op)
160 {
161         KeybindingMap* kbm;
162
163         switch (op) {
164         case KeyboardKey::Press:
165                 kbm = &press_bindings;
166                 break;
167         case KeyboardKey::Release:
168                 kbm = &release_bindings;
169                 break;
170         }
171
172         KeybindingMap::iterator k = kbm->find (kb);
173
174         if (k != kbm->end()) {
175                 kbm->erase (k);
176         }
177 }
178
179 bool
180 Bindings::save (const string& path)
181 {
182         XMLTree tree;
183         XMLNode* root = new XMLNode (X_("Bindings"));
184         tree.set_root (root);
185
186         XMLNode* presses = new XMLNode (X_("Press"));
187         root->add_child_nocopy (*presses);
188
189         for (KeybindingMap::iterator k = press_bindings.begin(); k != press_bindings.end(); ++k) {
190                 XMLNode* child;
191                 child = new XMLNode (X_("Binding"));
192                 child->add_property (X_("key"), k->first.name());
193                 child->add_property (X_("action"), k->second->get_name());
194                 presses->add_child_nocopy (*child);
195         }
196
197         if (!tree.write (path)) {
198                 ::unlink (path.c_str());
199                 return false;
200         }
201
202         return true;
203 }
204
205 bool
206 Bindings::load (const string& path)
207 {
208         XMLTree tree;
209
210         if (!action_map) {
211                 cerr << "No action map to load bindings with!\n";
212                 return false;
213         }
214
215         if (!tree.read (path)) {
216                 cerr << "Cannot load XML file @ " << path << endl;
217                 return false;
218         }
219         
220         press_bindings.clear ();
221         release_bindings.clear ();
222
223         XMLNode& root (*tree.root());
224         const XMLNodeList& children (root.children());
225
226         cerr << "check the " << children.size() << " children\n";
227         
228         for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
229
230                 cerr << "child name: " << (*i)->name() << endl;
231
232                 if ((*i)->name() == X_("Press") || (*i)->name() == X_("Release")) {
233
234                         KeyboardKey::Operation op;
235
236                         if ((*i)->name() == X_("Press")) {
237                                 op = KeyboardKey::Press;
238                         } else {
239                                 op = KeyboardKey::Release;
240                         }
241                         
242                         const XMLNodeList& gchildren ((*i)->children());
243
244                         for (XMLNodeList::const_iterator p = gchildren.begin(); p != gchildren.end(); ++p) {
245
246                                 XMLProperty* ap;
247                                 XMLProperty* kp;
248
249                                 ap = (*p)->property ("action");
250                                 kp = (*p)->property ("key");
251
252                                 if (!ap || !kp) {
253                                         continue;
254                                 }
255
256                                 cerr << "key = " << kp->value () << " action = " << ap->value() << endl;
257                                 
258                                 RefPtr<Action> act = action_map->find_action (ap->value());
259                                 
260                                 if (!act) {
261                                         continue;
262                                 }
263
264                                 KeyboardKey k;
265                                 
266                                 if (!KeyboardKey::make_key (kp->value(), k)) {
267                                         continue;
268                                 }
269
270                                 cerr << "binding " << act->get_name() << " to " << k.name() << endl;
271
272                                 add (k, op, act);
273                         }
274                 }
275         }
276
277         return true;
278 }
279
280 RefPtr<Action>
281 ActionMap::find_action (const string& name)
282 {
283         _ActionMap::iterator a = actions.find (name);
284
285         if (a != actions.end()) {
286                 return a->second;
287         }
288
289         return RefPtr<Action>();
290 }
291
292 RefPtr<Action> 
293 ActionMap::register_action (const char* path,
294                             const char* name, const char* label, sigc::slot<void> sl)
295 {
296         string fullpath;
297
298         RefPtr<Action> act = Action::create (name, label);
299
300         act->signal_activate().connect (sl);
301
302         fullpath = path;
303         fullpath += '/';
304         fullpath += name;
305
306         actions.insert (_ActionMap::value_type (fullpath, act));
307         cerr << "Registered action @ " << fullpath << endl;
308         return act;
309 }
310
311 RefPtr<Action> 
312 ActionMap::register_radio_action (const char* path, Gtk::RadioAction::Group& rgroup,
313                                  const char* name, const char* label, sigc::slot<void> sl)
314 {
315         string fullpath;
316
317         RefPtr<Action> act = RadioAction::create (rgroup, name, label);
318
319         act->signal_activate().connect (sl);
320
321         fullpath = path;
322         fullpath += '/';
323         fullpath += name;
324
325         actions.insert (_ActionMap::value_type (fullpath, act));
326         cerr << "Registered action @ " << fullpath << endl;
327
328         return act;
329 }
330
331 RefPtr<Action> 
332 ActionMap::register_toggle_action (const char*path,
333                                    const char* name, const char* label, sigc::slot<void> sl)
334 {
335         string fullpath;
336
337         RefPtr<Action> act = ToggleAction::create (name, label);
338
339         act->signal_activate().connect (sl);
340
341         fullpath = path;
342         fullpath += '/';
343         fullpath += name;
344
345         actions.insert (_ActionMap::value_type (fullpath, act));
346         cerr << "Registered action @ " << fullpath << endl;
347
348         return act;
349 }