2 Copyright (C) 2002 Paul Davis
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.
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.
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.
21 #include "gtk2ardour-config.h"
26 #include "ardour/profile.h"
28 #include <gtkmm/stock.h>
29 #include <gtkmm/label.h>
30 #include <gtkmm/accelkey.h>
31 #include <gtkmm/accelmap.h>
32 #include <gtkmm/uimanager.h>
34 #include "gtkmm2ext/utils.h"
36 #include "pbd/strsplit.h"
37 #include "pbd/replace_all.h"
39 #include "ardour/profile.h"
43 #include "keyeditor.h"
53 using Gtkmm2ext::Keyboard
;
55 KeyEditor::KeyEditor ()
56 : ArdourDialog (_("Key Bindings"), false)
57 , unbind_button (_("Remove shortcut"))
58 , unbind_box (BUTTONBOX_END
)
64 model
= TreeStore::create(columns
);
66 view
.set_model (model
);
67 view
.append_column (_("Action"), columns
.action
);
68 view
.append_column (_("Shortcut"), columns
.binding
);
69 view
.set_headers_visible (true);
70 view
.get_selection()->set_mode (SELECTION_SINGLE
);
71 view
.set_reorderable (false);
72 view
.set_size_request (500,300);
73 view
.set_enable_search (false);
74 view
.set_rules_hint (true);
75 view
.set_name (X_("KeyEditorTree"));
77 view
.get_selection()->signal_changed().connect (sigc::mem_fun (*this, &KeyEditor::action_selected
));
80 scroller
.set_policy (Gtk::POLICY_NEVER
, Gtk::POLICY_AUTOMATIC
);
83 get_vbox()->set_spacing (6);
84 get_vbox()->pack_start (scroller
);
86 if (!ARDOUR::Profile
->get_sae()) {
88 Label
* hint
= manage (new Label (_("Select an action, then press the key(s) to (re)set its shortcut")));
90 unbind_box
.set_spacing (6);
91 unbind_box
.pack_start (*hint
, false, true);
92 unbind_box
.pack_start (unbind_button
, false, false);
93 unbind_button
.signal_clicked().connect (sigc::mem_fun (*this, &KeyEditor::unbind
));
95 get_vbox()->pack_start (unbind_box
, false, false);
97 unbind_button
.show ();
101 get_vbox()->set_border_width (12);
106 unbind_button
.set_sensitive (false);
112 TreeModel::iterator i
= view
.get_selection()->get_selected();
114 unbind_button
.set_sensitive (false);
116 cerr
<< "trying to unbind\n";
118 if (i
!= model
->children().end()) {
119 string path
= (*i
)[columns
.path
];
121 if (!(*i
)[columns
.bindable
]) {
125 bool result
= AccelMap::change_entry (path
,
130 (*i
)[columns
.binding
] = string ();
136 KeyEditor::on_show ()
139 view
.get_selection()->unselect_all ();
140 ArdourDialog::on_show ();
144 KeyEditor::on_unmap ()
146 ArdourDialog::on_unmap ();
150 KeyEditor::action_selected ()
152 if (view
.get_selection()->count_selected_rows() == 0) {
156 TreeModel::iterator i
= view
.get_selection()->get_selected();
158 unbind_button
.set_sensitive (false);
160 if (i
!= model
->children().end()) {
162 string path
= (*i
)[columns
.path
];
164 if (!(*i
)[columns
.bindable
]) {
168 string binding
= (*i
)[columns
.binding
];
170 if (!binding
.empty()) {
171 unbind_button
.set_sensitive (true);
177 KeyEditor::on_key_press_event (GdkEventKey
* ev
)
180 last_state
= ev
->state
;
185 KeyEditor::on_key_release_event (GdkEventKey
* ev
)
187 if (ARDOUR::Profile
->get_sae() || !can_bind
|| ev
->state
!= last_state
) {
191 TreeModel::iterator i
= view
.get_selection()->get_selected();
193 if (i
!= model
->children().end()) {
194 string path
= (*i
)[columns
.path
];
196 if (!(*i
)[columns
.bindable
]) {
200 cerr
<< "real lkeyval: " << ev
->keyval
<< endl
;
201 Gtkmm2ext::possibly_translate_keyval_to_make_legal_accelerator (ev
->keyval
);
202 cerr
<< "using keyval = " << ev
->keyval
<< endl
;
205 bool result
= AccelMap::change_entry (path
,
207 ModifierType (Keyboard::RelevantModifierKeyMask
& ev
->state
),
210 cerr
<< "New binding to " << ev
->keyval
<< " worked: " << result
<< endl
;
214 (*i
)[columns
.binding
] = ActionManager::get_key_representation (path
, key
);
224 KeyEditor::populate ()
226 vector
<string
> paths
;
227 vector
<string
> labels
;
228 vector
<string
> tooltips
;
230 vector
<AccelKey
> bindings
;
231 typedef std::map
<string
,TreeIter
> NodeMap
;
235 ActionManager::get_all_actions (labels
, paths
, tooltips
, keys
, bindings
);
237 vector
<string
>::iterator k
;
238 vector
<string
>::iterator p
;
239 vector
<string
>::iterator t
;
240 vector
<string
>::iterator l
;
244 for (l
= labels
.begin(), k
= keys
.begin(), p
= paths
.begin(), t
= tooltips
.begin(); l
!= labels
.end(); ++k
, ++p
, ++t
, ++l
) {
247 vector
<string
> parts
;
251 split (*p
, parts
, '/');
257 if ((r
= nodes
.find (parts
[1])) == nodes
.end()) {
259 /* top level is missing */
262 TreeModel::Row parent
;
263 rowp
= model
->append();
264 nodes
[parts
[1]] = rowp
;
266 parent
[columns
.action
] = parts
[1];
267 parent
[columns
.bindable
] = false;
269 row
= *(model
->append (parent
.children()));
273 row
= *(model
->append ((*r
->second
)->children()));
277 /* add this action */
280 row
[columns
.action
] = *t
;
282 row
[columns
.action
] = *l
;
284 row
[columns
.path
] = (*p
);
285 row
[columns
.bindable
] = true;
287 if (*k
== ActionManager::unbound_string
) {
288 row
[columns
.binding
] = string();
295 NSAlternate/NSOption key to Mod1
296 NSCommand key to Meta
299 replace_all (label
, "<Meta>", _("Command-"));
300 replace_all (label
, "<Alt>", _("Option-"));
301 replace_all (label
, "<Shift>", _("Shift-"));
302 replace_all (label
, "<Control>", _("Control-"));
303 row
[columns
.binding
] = label
;
305 row
[columns
.binding
] = (*k
);