start using new keybinding stuff in step editor dialog
[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                 return false;
212         }
213
214         if (!tree.read (path)) {
215                 return false;
216         }
217         
218         press_bindings.clear ();
219         release_bindings.clear ();
220
221         XMLNode& root (*tree.root());
222         const XMLNodeList& children (root.children());
223
224         for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
225
226                 if ((*i)->name() == X_("Press") || (*i)->name() == X_("Release")) {
227
228                         KeyboardKey::Operation op;
229
230                         if ((*i)->name() == X_("Press")) {
231                                 op = KeyboardKey::Press;
232                         } else {
233                                 op = KeyboardKey::Release;
234                         }
235                         
236                         const XMLNodeList& gchildren ((*i)->children());
237
238                         for (XMLNodeList::const_iterator p = gchildren.begin(); p != gchildren.end(); ++p) {
239
240                                 XMLProperty* ap;
241                                 XMLProperty* kp;
242
243                                 ap = (*p)->property ("action");
244                                 kp = (*p)->property ("key");
245
246                                 if (!ap || !kp) {
247                                         continue;
248                                 }
249
250                                 RefPtr<Action> act = action_map->find_action (ap->value());
251                                 
252                                 if (!act) {
253                                         continue;
254                                 }
255
256                                 KeyboardKey k;
257                                 
258                                 if (!KeyboardKey::make_key (kp->value(), k)) {
259                                         continue;
260                                 }
261
262                                 add (k, op, act);
263                         }
264                 }
265         }
266
267         return true;
268 }
269
270 RefPtr<Action>
271 ActionMap::find_action (const string& name)
272 {
273         _ActionMap::iterator a = actions.find (name);
274
275         if (a != actions.end()) {
276                 return a->second;
277         }
278
279         return RefPtr<Action>();
280 }
281
282 RefPtr<Action> 
283 ActionMap::register_action (const char* path,
284                             const char* name, const char* label, sigc::slot<void> sl)
285 {
286         string fullpath;
287
288         RefPtr<Action> act = Action::create (name, label);
289
290         act->signal_activate().connect (sl);
291
292         fullpath = path;
293         fullpath += '/';
294         fullpath += name;
295
296         actions.insert (_ActionMap::value_type (fullpath, act));
297         return act;
298 }
299
300 RefPtr<Action> 
301 ActionMap::register_radio_action (const char* path, Gtk::RadioAction::Group& rgroup,
302                                  const char* name, const char* label, sigc::slot<void> sl)
303 {
304         string fullpath;
305
306         RefPtr<Action> act = RadioAction::create (rgroup, name, label);
307
308         act->signal_activate().connect (sl);
309
310         fullpath = path;
311         fullpath += '/';
312         fullpath += name;
313
314         actions.insert (_ActionMap::value_type (fullpath, act));
315         return act;
316 }
317
318 RefPtr<Action> 
319 ActionMap::register_toggle_action (const char* path,
320                                    const char* name, const char* label, sigc::slot<void> sl)
321 {
322         string fullpath;
323
324         RefPtr<Action> act = ToggleAction::create (name, label);
325
326         act->signal_activate().connect (sl);
327
328         fullpath = path;
329         fullpath += '/';
330         fullpath += name;
331
332         actions.insert (_ActionMap::value_type (fullpath, act));
333         return act;
334 }