~ubuntu-branches/ubuntu/utopic/ardour3/utopic

« back to all changes in this revision

Viewing changes to gtk2_ardour/keyeditor.cc

  • Committer: Package Import Robot
  • Author(s): Felipe Sateler
  • Date: 2013-09-21 19:05:02 UTC
  • Revision ID: package-import@ubuntu.com-20130921190502-8gsftrku6jnzhd7v
Tags: upstream-3.4~dfsg
ImportĀ upstreamĀ versionĀ 3.4~dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
36
#include "ardour/profile.h"
 
37
 
 
38
#include "actions.h"
 
39
#include "keyboard.h"
 
40
#include "keyeditor.h"
 
41
#include "utils.h"
 
42
 
 
43
#include "i18n.h"
 
44
 
 
45
using namespace std;
 
46
using namespace Gtk;
 
47
using namespace Gdk;
 
48
using namespace PBD;
 
49
 
 
50
using Gtkmm2ext::Keyboard;
 
51
 
 
52
KeyEditor::KeyEditor ()
 
53
        : ArdourWindow (_("Key Bindings"))
 
54
        , unbind_button (_("Remove shortcut"))
 
55
        , unbind_box (BUTTONBOX_END)
 
56
 
 
57
{
 
58
        can_bind = false;
 
59
        last_state = 0;
 
60
 
 
61
        model = TreeStore::create(columns);
 
62
 
 
63
        view.set_model (model);
 
64
        view.append_column (_("Action"), columns.action);
 
65
        view.append_column (_("Shortcut"), columns.binding);
 
66
        view.set_headers_visible (true);
 
67
        view.get_selection()->set_mode (SELECTION_SINGLE);
 
68
        view.set_reorderable (false);
 
69
        view.set_size_request (500,300);
 
70
        view.set_enable_search (false);
 
71
        view.set_rules_hint (true);
 
72
        view.set_name (X_("KeyEditorTree"));
 
73
 
 
74
        view.get_selection()->signal_changed().connect (sigc::mem_fun (*this, &KeyEditor::action_selected));
 
75
 
 
76
        scroller.add (view);
 
77
        scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
 
78
 
 
79
        add (vpacker);
 
80
 
 
81
        vpacker.set_spacing (6);
 
82
        vpacker.pack_start (scroller);
 
83
 
 
84
        if (!ARDOUR::Profile->get_sae()) {
 
85
 
 
86
                Label* hint = manage (new Label (_("Select an action, then press the key(s) to (re)set its shortcut")));
 
87
                hint->show ();
 
88
                unbind_box.set_spacing (6);
 
89
                unbind_box.pack_start (*hint, false, true);
 
90
                unbind_box.pack_start (unbind_button, false, false);
 
91
                unbind_button.signal_clicked().connect (sigc::mem_fun (*this, &KeyEditor::unbind));
 
92
 
 
93
                vpacker.pack_start (unbind_box, false, false);
 
94
                unbind_box.show ();
 
95
                unbind_button.show ();
 
96
 
 
97
        }
 
98
 
 
99
        vpacker.set_border_width (12);
 
100
 
 
101
        view.show ();
 
102
        scroller.show ();
 
103
        vpacker.show ();
 
104
 
 
105
        unbind_button.set_sensitive (false);
 
106
}
 
107
 
 
108
void
 
109
KeyEditor::unbind ()
 
110
{
 
111
        TreeModel::iterator i = view.get_selection()->get_selected();
 
112
 
 
113
        unbind_button.set_sensitive (false);
 
114
 
 
115
        if (i != model->children().end()) {
 
116
                string path = (*i)[columns.path];
 
117
 
 
118
                if (!(*i)[columns.bindable]) {
 
119
                        return;
 
120
                }
 
121
 
 
122
                bool result = AccelMap::change_entry (path,
 
123
                                                      0,
 
124
                                                      (ModifierType) 0,
 
125
                                                      true);
 
126
                if (result) {
 
127
                        (*i)[columns.binding] = string ();
 
128
                }
 
129
        }
 
130
}
 
131
 
 
132
void
 
133
KeyEditor::on_show ()
 
134
{
 
135
        populate ();
 
136
        view.get_selection()->unselect_all ();
 
137
        ArdourWindow::on_show ();
 
138
}
 
139
 
 
140
void
 
141
KeyEditor::on_unmap ()
 
142
{
 
143
        ArdourWindow::on_unmap ();
 
144
}
 
145
 
 
146
void
 
147
KeyEditor::action_selected ()
 
148
{
 
149
        if (view.get_selection()->count_selected_rows() == 0) {
 
150
                return;
 
151
        }
 
152
 
 
153
        TreeModel::iterator i = view.get_selection()->get_selected();
 
154
 
 
155
        unbind_button.set_sensitive (false);
 
156
 
 
157
        if (i != model->children().end()) {
 
158
 
 
159
                string path = (*i)[columns.path];
 
160
 
 
161
                if (!(*i)[columns.bindable]) {
 
162
                        return;
 
163
                }
 
164
 
 
165
                string binding = (*i)[columns.binding];
 
166
 
 
167
                if (!binding.empty()) {
 
168
                        unbind_button.set_sensitive (true);
 
169
                }
 
170
        }
 
171
}
 
172
 
 
173
bool
 
174
KeyEditor::on_key_press_event (GdkEventKey* ev)
 
175
{
 
176
        can_bind = true;
 
177
        last_state = ev->state;
 
178
        return false;
 
179
}
 
180
 
 
181
bool
 
182
KeyEditor::on_key_release_event (GdkEventKey* ev)
 
183
{
 
184
        if (ARDOUR::Profile->get_sae() || !can_bind || ev->state != last_state) {
 
185
                return false;
 
186
        }
 
187
 
 
188
        TreeModel::iterator i = view.get_selection()->get_selected();
 
189
 
 
190
        if (i != model->children().end()) {
 
191
                string path = (*i)[columns.path];
 
192
 
 
193
                if (!(*i)[columns.bindable]) {
 
194
                        goto out;
 
195
                }
 
196
 
 
197
                Gtkmm2ext::possibly_translate_keyval_to_make_legal_accelerator (ev->keyval);
 
198
 
 
199
 
 
200
                bool result = AccelMap::change_entry (path,
 
201
                                                      ev->keyval,
 
202
                                                      ModifierType (Keyboard::RelevantModifierKeyMask & ev->state),
 
203
                                                      true);
 
204
 
 
205
                if (result) {
 
206
                        AccelKey key;
 
207
                        (*i)[columns.binding] = ActionManager::get_key_representation (path, key);
 
208
                }
 
209
        }
 
210
 
 
211
  out:
 
212
        can_bind = false;
 
213
        return true;
 
214
}
 
215
 
 
216
void
 
217
KeyEditor::populate ()
 
218
{
 
219
        vector<string> paths;
 
220
        vector<string> labels;
 
221
        vector<string> tooltips;
 
222
        vector<string> keys;
 
223
        vector<AccelKey> bindings;
 
224
        typedef std::map<string,TreeIter> NodeMap;
 
225
        NodeMap nodes;
 
226
        NodeMap::iterator r;
 
227
 
 
228
        ActionManager::get_all_actions (labels, paths, tooltips, keys, bindings);
 
229
 
 
230
        vector<string>::iterator k;
 
231
        vector<string>::iterator p;
 
232
        vector<string>::iterator t;
 
233
        vector<string>::iterator l;
 
234
 
 
235
        model->clear ();
 
236
 
 
237
        for (l = labels.begin(), k = keys.begin(), p = paths.begin(), t = tooltips.begin(); l != labels.end(); ++k, ++p, ++t, ++l) {
 
238
 
 
239
                TreeModel::Row row;
 
240
                vector<string> parts;
 
241
 
 
242
                parts.clear ();
 
243
 
 
244
                split (*p, parts, '/');
 
245
 
 
246
                if (parts.empty()) {
 
247
                        continue;
 
248
                }
 
249
 
 
250
                //kinda kludgy way to avoid displaying menu items as mappable
 
251
                if ( parts[1] == _("Main_menu") )
 
252
                        continue;
 
253
                if ( parts[1] == _("JACK") )
 
254
                        continue;
 
255
                if ( parts[1] == _("redirectmenu") )
 
256
                        continue;
 
257
                if ( parts[1] == _("Editor_menus") )
 
258
                        continue;
 
259
                if ( parts[1] == _("RegionList") )
 
260
                        continue;
 
261
                if ( parts[1] == _("ProcessorMenu") )
 
262
                        continue;
 
263
 
 
264
                if ((r = nodes.find (parts[1])) == nodes.end()) {
 
265
 
 
266
                        /* top level is missing */
 
267
 
 
268
                        TreeIter rowp;
 
269
                        TreeModel::Row parent;
 
270
                        rowp = model->append();
 
271
                        nodes[parts[1]] = rowp;
 
272
                        parent = *(rowp);
 
273
                        parent[columns.action] = parts[1];
 
274
                        parent[columns.bindable] = false;
 
275
 
 
276
                        row = *(model->append (parent.children()));
 
277
 
 
278
                } else {
 
279
 
 
280
                        row = *(model->append ((*r->second)->children()));
 
281
 
 
282
                }
 
283
 
 
284
                /* add this action */
 
285
 
 
286
                if (l->empty ()) {
 
287
                        row[columns.action] = *t;
 
288
                } else {
 
289
                        row[columns.action] = *l;
 
290
                }
 
291
                row[columns.path] = (*p);
 
292
                row[columns.bindable] = true;
 
293
 
 
294
                if (*k == ActionManager::unbound_string) {
 
295
                        row[columns.binding] = string();
 
296
                } else {
 
297
                        row[columns.binding] = (*k);
 
298
                }
 
299
        }
 
300
}