slowly fixing up ArdourDialog nonsense
[ardour.git] / gtk2_ardour / keyboard_target.cc
1 /*
2     Copyright (C) 2001-2002 Paul Davis 
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18     $Id$
19 */
20
21 #include <gdk/gdkkeysyms.h>
22 #include <pbd/error.h>
23
24 #include "keyboard.h"
25 #include "keyboard_target.h"
26
27 #include "i18n.h"
28
29 using std::pair;
30
31 KeyboardTarget::ActionMap KeyboardTarget::actions;
32
33 KeyboardTarget::KeyboardTarget (Gtk::Window& win, string name)
34         : _window (win)
35 {
36         _name = name;
37         Keyboard::the_keyboard().register_target (this);
38 }
39
40 KeyboardTarget::~KeyboardTarget ()
41 {
42         GoingAway ();
43 }
44
45 void
46 KeyboardTarget::key_release_event (GdkEventKey *event, Keyboard::State& state)
47 {
48         // relax
49 }
50
51 void
52 KeyboardTarget::key_press_event (GdkEventKey *event, Keyboard::State& state, bool& handled)
53 {
54         KeyMap::iterator result;
55         
56         if ((result = keymap.find (state)) != keymap.end()) {
57                 (*result).second ();
58                 handled = true;
59         }
60 }
61
62 int
63 KeyboardTarget::add_binding (string keystring, string action)
64 {
65         KeyMap::iterator existing;
66         Keyboard::State  state;
67         KeyAction key_action;
68
69         state = Keyboard::translate_key_name (keystring);
70
71         if (keystring.length() == 0) {
72                 error << _("KeyboardTarget: empty string passed to add_binding.")
73                       << endmsg;
74                 return -1;
75         }
76
77         if (state.size() == 0) {
78                 error << string_compose(_("KeyboardTarget: no translation found for \"%1\""), keystring) << endmsg;
79                 return -1;
80         }
81
82         if (find_action (action, key_action)) {
83                 error << string_compose(_("KeyboardTarget: unknown action \"%1\""), action) << endmsg;
84                 return -1;
85         }
86
87         /* remove any existing binding */
88
89         if ((existing = keymap.find (state)) != keymap.end()) {
90                 keymap.erase (existing);
91         }
92         
93         keymap.insert (pair<Keyboard::State,KeyAction> (state, key_action));
94         bindings.insert (pair<string,string> (keystring, action));
95         return 0;
96 }
97
98 string
99 KeyboardTarget::get_binding (string name)
100 {
101         BindingMap::iterator i;
102         
103         for (i = bindings.begin(); i != bindings.end(); ++i) {
104
105                 if (i->second == name) {
106
107                         /* convert keystring to GTK format */
108
109                         string str = i->first;
110                         string gtkstr;
111                         string::size_type p;
112
113                         while (1) {
114
115                                 if ((p = str.find ('-')) == string::npos || (p == str.length() - 1)) {
116                                         break;
117                                 }
118
119                                 gtkstr += '<';
120                                 gtkstr += str.substr (0, p);
121                                 gtkstr += '>';
122
123                                 str = str.substr (p+1);
124
125                         }
126
127                         gtkstr += str;
128
129                         if (gtkstr.length() == 0) {
130                                 return i->first;
131                         } 
132
133                         return gtkstr;
134                 }
135         }
136         return string ();
137 }
138
139 void
140 KeyboardTarget::show_all_actions ()
141 {
142         ActionMap::iterator i;
143         
144         for (i = actions.begin(); i != actions.end(); ++i) {
145                 cout << i->first << endl;
146         }
147 }
148
149 int
150 KeyboardTarget::add_action (string name, KeyAction action)
151 {
152         pair<string,KeyAction> newpair;
153         pair<ActionMap::iterator,bool> result;
154         newpair.first = name;
155         newpair.second = action;
156
157         result = actions.insert (newpair);
158         return result.second ? 0 : -1;
159 }
160
161 int
162 KeyboardTarget::find_action (string name, KeyAction& action)
163 {
164         map<string,KeyAction>::iterator i;
165
166         if ((i = actions.find (name)) != actions.end()) {
167                 action = i->second;
168                 return 0;
169         } else {
170                 return -1;
171         }
172 }
173
174 int
175 KeyboardTarget::remove_action (string name)
176 {
177         map<string,KeyAction>::iterator i;
178
179         if ((i = actions.find (name)) != actions.end()) {
180                 actions.erase (i);
181                 return 0;
182         } else {
183                 return -1;
184         }
185 }
186
187 XMLNode&
188 KeyboardTarget::get_binding_state () const
189 {
190         XMLNode *node = new XMLNode ("context");
191         BindingMap::const_iterator i;
192
193         node->add_property ("name", _name);
194        
195         for (i = bindings.begin(); i != bindings.end(); ++i) {
196                 XMLNode *child;
197
198                 child = new XMLNode ("binding");
199                 child->add_property ("keys", i->first);
200                 child->add_property ("action", i->second);
201                 node->add_child_nocopy (*child);
202         }
203         
204         return *node;
205 }
206         
207 int
208 KeyboardTarget::set_binding_state (const XMLNode& node)
209 {
210         XMLNodeList nlist = node.children();
211         XMLNodeConstIterator niter;
212         XMLNode *child_node;
213
214         bindings.clear ();
215         keymap.clear ();
216
217         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
218                 child_node = *niter;
219
220                 if (child_node->name() == "context") {
221                         XMLProperty *prop;
222                         
223                         if ((prop = child_node->property ("name")) != 0) {
224                                 if (prop->value() == _name) {
225                                         return load_bindings (*child_node);
226                                 }
227                         }
228                 }
229         }
230
231         return 0;
232 }
233
234 int
235 KeyboardTarget::load_bindings (const XMLNode& node)
236 {
237         XMLNodeList nlist = node.children();
238         XMLNodeConstIterator niter;
239
240         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
241                 XMLProperty *keys;
242                 XMLProperty *action;
243                 
244                 keys = (*niter)->property ("keys");
245                 action = (*niter)->property ("action");
246
247                 if (!keys || !action) {
248                         error << _("misformed binding node - ignored") << endmsg;
249                         continue;
250                 }
251
252                 add_binding (keys->value(), action->value());
253                         
254         }
255
256         return 0;
257 }
258