ardour
keyeditor.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 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 */
19 
20 #ifdef WAF_BUILD
21 #include "gtk2ardour-config.h"
22 #endif
23 
24 #include <map>
25 
26 #include <gtkmm/stock.h>
27 #include <gtkmm/label.h>
28 #include <gtkmm/accelkey.h>
29 #include <gtkmm/accelmap.h>
30 #include <gtkmm/uimanager.h>
31 
32 #include "gtkmm2ext/utils.h"
33 
34 #include "pbd/strsplit.h"
35 
37 #include "ardour/profile.h"
38 
39 #include "actions.h"
40 #include "keyboard.h"
41 #include "keyeditor.h"
42 
43 #include "i18n.h"
44 
45 using namespace std;
46 using namespace Gtk;
47 using namespace Gdk;
48 using namespace PBD;
49 
51 
53  : ArdourWindow (_("Key Bindings"))
54  , unbind_button (_("Remove shortcut"))
55  , unbind_box (BUTTONBOX_END)
56 
57 {
58  last_keyval = 0;
59 
60  model = TreeStore::create(columns);
61 
62  view.set_model (model);
63  view.append_column (_("Action"), columns.action);
64  view.append_column (_("Shortcut"), columns.binding);
65  view.set_headers_visible (true);
66  view.get_selection()->set_mode (SELECTION_SINGLE);
67  view.set_reorderable (false);
68  view.set_size_request (500,300);
69  view.set_enable_search (false);
70  view.set_rules_hint (true);
71  view.set_name (X_("KeyEditorTree"));
72 
73  view.get_selection()->signal_changed().connect (sigc::mem_fun (*this, &KeyEditor::action_selected));
74 
75  scroller.add (view);
76  scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
77 
78  vpacker.set_spacing (6);
79  vpacker.set_border_width (12);
80  vpacker.pack_start (scroller);
81 
82  if (!ARDOUR::Profile->get_sae()) {
83 
84  Label* hint = manage (new Label (_("Select an action, then press the key(s) to (re)set its shortcut")));
85  hint->show ();
86  unbind_box.set_spacing (6);
87  unbind_box.pack_start (*hint, false, true);
88  unbind_box.pack_start (unbind_button, false, false);
89  unbind_button.signal_clicked().connect (sigc::mem_fun (*this, &KeyEditor::unbind));
90 
91  vpacker.pack_start (unbind_box, false, false);
92  unbind_box.show ();
93  unbind_button.show ();
94 
95  }
96 
98  reset_label.set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Reset Bindings to Defaults")));
99 
100  reset_box.pack_start (reset_button, true, false);
101  reset_box.show ();
102  reset_button.show ();
103  reset_label.show ();
104  reset_button.signal_clicked().connect (sigc::mem_fun (*this, &KeyEditor::reset));
105  vpacker.pack_start (reset_box, false, false);
106 
107  add (vpacker);
108 
109  view.show ();
110  scroller.show ();
111  vpacker.show ();
112 
113  unbind_button.set_sensitive (false);
114 }
115 
116 void
118 {
119  TreeModel::iterator i = view.get_selection()->get_selected();
120 
121  unbind_button.set_sensitive (false);
122 
123  if (i != model->children().end()) {
124  string path = (*i)[columns.path];
125 
126  if (!(*i)[columns.bindable]) {
127  return;
128  }
129 
130  bool result = AccelMap::change_entry (path,
131  0,
132  (ModifierType) 0,
133  true);
134  if (result) {
135  (*i)[columns.binding] = string ();
136  }
137  }
138 }
139 
140 void
142 {
143  populate ();
144  view.get_selection()->unselect_all ();
145  ArdourWindow::on_show ();
146 }
147 
148 void
150 {
152 }
153 
154 void
156 {
157  if (view.get_selection()->count_selected_rows() == 0) {
158  return;
159  }
160 
161  TreeModel::iterator i = view.get_selection()->get_selected();
162 
163  unbind_button.set_sensitive (false);
164 
165  if (i != model->children().end()) {
166 
167  string path = (*i)[columns.path];
168 
169  if (!(*i)[columns.bindable]) {
170  return;
171  }
172 
173  string binding = (*i)[columns.binding];
174 
175  if (!binding.empty()) {
176  unbind_button.set_sensitive (true);
177  }
178  }
179 }
180 
181 bool
183 {
184  if (!ev->is_modifier) {
185  last_keyval = ev->keyval;
186  }
188 }
189 
190 bool
192 {
193  if (ARDOUR::Profile->get_sae() || last_keyval == 0) {
194  return false;
195  }
196 
197  TreeModel::iterator i = view.get_selection()->get_selected();
198 
199  if (i != model->children().end()) {
200  string path = (*i)[columns.path];
201 
202  if (!(*i)[columns.bindable]) {
203  goto out;
204  }
205 
206  GdkModifierType mod = (GdkModifierType)(Keyboard::RelevantModifierKeyMask & ev->state);
207 
210 
211  bool result = AccelMap::change_entry (path,
212  last_keyval,
213  Gdk::ModifierType(mod),
214  true);
215 
216  if (result) {
217  AccelKey key;
219  unbind_button.set_sensitive (true);
220  }
221  }
222 
223  out:
224  last_keyval = 0;
225  return true;
226 }
227 
228 void
230 {
231  vector<string> paths;
232  vector<string> labels;
233  vector<string> tooltips;
234  vector<string> keys;
235  vector<AccelKey> bindings;
236  typedef std::map<string,TreeIter> NodeMap;
237  NodeMap nodes;
238  NodeMap::iterator r;
239 
240  ActionManager::get_all_actions (labels, paths, tooltips, keys, bindings);
241 
242  vector<string>::iterator k;
243  vector<string>::iterator p;
244  vector<string>::iterator t;
245  vector<string>::iterator l;
246 
247  model->clear ();
248 
249  for (l = labels.begin(), k = keys.begin(), p = paths.begin(), t = tooltips.begin(); l != labels.end(); ++k, ++p, ++t, ++l) {
250 
251  TreeModel::Row row;
252  vector<string> parts;
253 
254  parts.clear ();
255 
256  split (*p, parts, '/');
257 
258  if (parts.empty()) {
259  continue;
260  }
261 
262  //kinda kludgy way to avoid displaying menu items as mappable
263  if ( parts[1] == _("Main_menu") )
264  continue;
265  if ( parts[1] == _("redirectmenu") )
266  continue;
267  if ( parts[1] == _("Editor_menus") )
268  continue;
269  if ( parts[1] == _("RegionList") )
270  continue;
271  if ( parts[1] == _("ProcessorMenu") )
272  continue;
273 
274  if ((r = nodes.find (parts[1])) == nodes.end()) {
275 
276  /* top level is missing */
277 
278  TreeIter rowp;
279  TreeModel::Row parent;
280  rowp = model->append();
281  nodes[parts[1]] = rowp;
282  parent = *(rowp);
283  parent[columns.action] = parts[1];
284  parent[columns.bindable] = false;
285 
286  row = *(model->append (parent.children()));
287 
288  } else {
289 
290  row = *(model->append ((*r->second)->children()));
291 
292  }
293 
294  /* add this action */
295 
296  if (l->empty ()) {
297  row[columns.action] = *t;
298  } else {
299  row[columns.action] = *l;
300  }
301  row[columns.path] = (*p);
302  row[columns.bindable] = true;
303 
304  if (*k == ActionManager::unbound_string) {
305  row[columns.binding] = string();
306  } else {
307  row[columns.binding] = (*k);
308  }
309  }
310 }
311 
312 void
314 {
315  Keyboard::the_keyboard().reset_bindings ();
316  populate ();
317  view.get_selection()->unselect_all ();
318  populate ();
319 }
bool on_key_press_event(GdkEventKey *)
Definition: keyeditor.cc:182
LIBGTKMM2EXT_API bool possibly_translate_mod_to_make_legal_accelerator(GdkModifierType &mod)
Definition: utils.cc:375
KeyEditorColumns columns
Definition: keyeditor.h:61
Gtk::TreeModelColumn< std::string > binding
Definition: keyeditor.h:52
Gtk::TreeModelColumn< std::string > action
Definition: keyeditor.h:51
LIBPBD_API void split(std::string, std::vector< std::string > &, char)
Definition: ardour_ui.h:130
Definition: Beats.hpp:239
Glib::RefPtr< Gtk::TreeStore > model
Definition: keyeditor.h:60
#define _(Text)
Definition: i18n.h:11
LIBGTKMM2EXT_API uint64_t Keyboard
Definition: debug.cc:23
#define X_(Text)
Definition: i18n.h:13
Gtk::HBox reset_box
Definition: keyeditor.h:64
Gtk::Button reset_button
Definition: keyeditor.h:65
bool on_key_release_event(GdkEventKey *)
Definition: keyeditor.cc:191
Gtk::TreeModelColumn< std::string > path
Definition: keyeditor.h:53
void reset()
Definition: keyeditor.cc:313
Gtk::HButtonBox unbind_box
Definition: keyeditor.h:63
LIBARDOUR_API RuntimeProfile * Profile
Definition: globals.cc:120
Gtk::Label reset_label
Definition: keyeditor.h:66
LIBGTKMM2EXT_API std::string unbound_string
Definition: actions.cc:54
LIBGTKMM2EXT_API bool possibly_translate_keyval_to_make_legal_accelerator(uint32_t &keyval)
Definition: utils.cc:399
Gtk::TreeModelColumn< bool > bindable
Definition: keyeditor.h:54
Gtk::Button unbind_button
Definition: keyeditor.h:62
void on_unmap()
Definition: keyeditor.cc:149
LIBGTKMM2EXT_API std::string get_key_representation(const std::string &accel_path, Gtk::AccelKey &key)
bool on_key_press_event(GdkEventKey *)
guint last_keyval
Definition: keyeditor.h:70
void populate()
Definition: keyeditor.cc:229
Definition: debug.h:30
void action_selected()
Definition: keyeditor.cc:155
LIBGTKMM2EXT_API void get_all_actions(std::vector< std::string > &names, std::vector< std::string > &paths, std::vector< std::string > &tooltips, std::vector< std::string > &keys, std::vector< Gtk::AccelKey > &bindings)
Gtk::TreeView view
Definition: keyeditor.h:59
void on_show()
Definition: keyeditor.cc:141
std::string string_compose(const std::string &fmt, const T1 &o1)
Definition: compose.h:208
Gtk::ScrolledWindow scroller
Definition: keyeditor.h:58
Gtk::VBox vpacker
Definition: keyeditor.h:57
void unbind()
Definition: keyeditor.cc:117