make all use of bind/mem_fun be explicitly sigc::
[ardour.git] / gtk2_ardour / keyeditor.cc
1 #include <map>
2
3 #include "ardour/profile.h"
4
5 #include <gtkmm/stock.h>
6 #include <gtkmm/label.h>
7 #include <gtkmm/accelkey.h>
8 #include <gtkmm/accelmap.h>
9 #include <gtkmm/uimanager.h>
10
11 #include "pbd/strsplit.h"
12 #include "pbd/replace_all.h"
13
14 #include "ardour/profile.h"
15
16 #include "actions.h"
17 #include "keyboard.h"
18 #include "keyeditor.h"
19 #include "utils.h"
20
21 #include "i18n.h"
22
23 using namespace std;
24 using namespace Gtk;
25 using namespace Gdk;
26 using namespace PBD;
27
28 using Gtkmm2ext::Keyboard;
29
30 KeyEditor::KeyEditor ()
31         : ArdourDialog (_("Key Bindings"), false)
32         , unbind_button (_("Remove shortcut"))
33         , unbind_box (BUTTONBOX_END)
34
35 {
36         can_bind = false;
37         last_state = 0;
38
39         model = TreeStore::create(columns);
40
41         view.set_model (model);
42         view.append_column (_("Action"), columns.action);
43         view.append_column (_("Shortcut"), columns.binding);
44         view.set_headers_visible (true);
45         view.get_selection()->set_mode (SELECTION_SINGLE);
46         view.set_reorderable (false);
47         view.set_size_request (500,300);
48         view.set_enable_search (false);
49         view.set_rules_hint (true);
50         view.set_name (X_("KeyEditorTree"));
51
52         view.get_selection()->signal_changed().connect (sigc::mem_fun (*this, &KeyEditor::action_selected));
53
54         scroller.add (view);
55         scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
56
57
58         get_vbox()->set_spacing (6);
59         get_vbox()->pack_start (scroller);
60
61         if (!ARDOUR::Profile->get_sae()) {
62
63                 Label* hint = manage (new Label (_("Select an action, then press the key(s) to (re)set its shortcut")));
64                 hint->show ();
65                 unbind_box.set_spacing (6);
66                 unbind_box.pack_start (*hint, false, true);
67                 unbind_box.pack_start (unbind_button, false, false);
68                 unbind_button.signal_clicked().connect (sigc::mem_fun (*this, &KeyEditor::unbind));
69
70                 get_vbox()->pack_start (unbind_box, false, false);
71                 unbind_box.show ();
72                 unbind_button.show ();
73
74         }
75
76         get_vbox()->set_border_width (12);
77
78         view.show ();
79         scroller.show ();
80
81         unbind_button.set_sensitive (false);
82 }
83
84 void
85 KeyEditor::unbind ()
86 {
87         TreeModel::iterator i = view.get_selection()->get_selected();
88
89         unbind_button.set_sensitive (false);
90
91         cerr << "trying to unbind\n";
92
93         if (i != model->children().end()) {
94                 string path = (*i)[columns.path];
95
96                 if (!(*i)[columns.bindable]) {
97                         return;
98                 }
99
100                 bool result = AccelMap::change_entry (path,
101                                                       0,
102                                                       (ModifierType) 0,
103                                                       true);
104                 if (result) {
105                         (*i)[columns.binding] = string ();
106                 }
107         }
108 }
109
110 void
111 KeyEditor::on_show ()
112 {
113         populate ();
114         view.get_selection()->unselect_all ();
115         ArdourDialog::on_show ();
116 }
117
118 void
119 KeyEditor::on_unmap ()
120 {
121         ArdourDialog::on_unmap ();
122 }
123
124 void
125 KeyEditor::action_selected ()
126 {
127         if (view.get_selection()->count_selected_rows() == 0) {
128                 return;
129         }
130
131         TreeModel::iterator i = view.get_selection()->get_selected();
132
133         unbind_button.set_sensitive (false);
134
135         if (i != model->children().end()) {
136
137                 string path = (*i)[columns.path];
138
139                 if (!(*i)[columns.bindable]) {
140                         return;
141                 }
142
143                 string binding = (*i)[columns.binding];
144
145                 if (!binding.empty()) {
146                         unbind_button.set_sensitive (true);
147                 }
148         }
149 }
150
151 bool
152 KeyEditor::on_key_press_event (GdkEventKey* ev)
153 {
154         can_bind = true;
155         last_state = ev->state;
156         return false;
157 }
158
159 bool
160 KeyEditor::on_key_release_event (GdkEventKey* ev)
161 {
162         if (ARDOUR::Profile->get_sae() || !can_bind || ev->state != last_state) {
163                 return false;
164         }
165
166         TreeModel::iterator i = view.get_selection()->get_selected();
167
168         if (i != model->children().end()) {
169                 string path = (*i)[columns.path];
170
171                 if (!(*i)[columns.bindable]) {
172                         goto out;
173                 }
174
175                 cerr << "real lkeyval: " << ev->keyval << endl;
176                 possibly_translate_keyval_to_make_legal_accelerator (ev->keyval);
177                 cerr << "using keyval = " << ev->keyval << endl;
178
179
180                 bool result = AccelMap::change_entry (path,
181                                                       ev->keyval,
182                                                       ModifierType (Keyboard::RelevantModifierKeyMask & ev->state),
183                                                       true);
184
185                 cerr << "New binding to " << ev->keyval << " worked: " << result << endl;
186
187                 if (result) {
188                         AccelKey key;
189                         (*i)[columns.binding] = ActionManager::get_key_representation (path, key);
190                 }
191         }
192
193   out:
194         can_bind = false;
195         return true;
196 }
197
198 void
199 KeyEditor::populate ()
200 {
201         vector<string> paths;
202         vector<string> labels;
203         vector<string> keys;
204         vector<AccelKey> bindings;
205         typedef std::map<string,TreeIter> NodeMap;
206         NodeMap nodes;
207         NodeMap::iterator r;
208
209         ActionManager::get_all_actions (labels, paths, keys, bindings);
210
211         vector<string>::iterator k;
212         vector<string>::iterator p;
213         vector<string>::iterator l;
214
215         model->clear ();
216
217         for (l = labels.begin(), k = keys.begin(), p = paths.begin(); l != labels.end(); ++k, ++p, ++l) {
218
219                 TreeModel::Row row;
220                 vector<string> parts;
221
222                 parts.clear ();
223
224                 split (*p, parts, '/');
225
226                 if (parts.empty()) {
227                         continue;
228                 }
229
230                 if ((r = nodes.find (parts[1])) == nodes.end()) {
231
232                         /* top level is missing */
233
234                         TreeIter rowp;
235                         TreeModel::Row parent;
236                         rowp = model->append();
237                         nodes[parts[1]] = rowp;
238                         parent = *(rowp);
239                         parent[columns.action] = parts[1];
240                         parent[columns.bindable] = false;
241
242                         row = *(model->append (parent.children()));
243
244                 } else {
245
246                         row = *(model->append ((*r->second)->children()));
247
248                 }
249
250                 /* add this action */
251
252                 row[columns.action] = (*l);
253                 row[columns.path] = (*p);
254                 row[columns.bindable] = true;
255
256                 if (*k == ActionManager::unbound_string) {
257                         row[columns.binding] = string();
258                 } else {
259
260 #ifdef GTKOSX
261                         string label = (*k);
262
263                         /* Gtk/Quartz maps:
264                            NSAlternate/NSOption key to Mod1
265                            NSCommand key to Meta
266                         */
267
268                         replace_all (label, "<Meta>", _("Command-"));
269                         replace_all (label, "<Alt>", _("Option-"));
270                         replace_all (label, "<Shift>", _("Shift-"));
271                         replace_all (label, "<Control>", _("Control-"));
272                         row[columns.binding] = label;
273 #else
274                         row[columns.binding] = (*k);
275 #endif
276                 }
277         }
278 }