2 Copyright (C) 2012 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.
22 #include <glib/gstdio.h>
24 #include "pbd/xml++.h"
25 #include "pbd/convert.h"
27 #include "gtkmm2ext/actions.h"
28 #include "gtkmm2ext/bindings.h"
29 #include "gtkmm2ext/keyboard.h"
36 using namespace Gtkmm2ext;
38 uint32_t Bindings::_ignored_state = 0;
40 MouseButton::MouseButton (uint32_t state, uint32_t keycode)
42 uint32_t ignore = Bindings::ignored_state();
44 if (gdk_keyval_is_upper (keycode) && gdk_keyval_is_lower (keycode)) {
45 /* key is not subject to case, so ignore SHIFT
47 ignore |= GDK_SHIFT_MASK;
50 _val = (state & ~ignore);
56 MouseButton::make_button (const string& str, MouseButton& b)
60 if (str.find ("Primary") != string::npos) {
61 s |= Keyboard::PrimaryModifier;
64 if (str.find ("Secondary") != string::npos) {
65 s |= Keyboard::SecondaryModifier;
68 if (str.find ("Tertiary") != string::npos) {
69 s |= Keyboard::TertiaryModifier;
72 if (str.find ("Level4") != string::npos) {
73 s |= Keyboard::Level4Modifier;
76 string::size_type lastmod = str.find_last_of ('-');
77 uint32_t button_number;
79 if (lastmod == string::npos) {
80 button_number = PBD::atoi (str);
82 button_number = PBD::atoi (str.substr (lastmod+1));
85 b = MouseButton (s, button_number);
90 MouseButton::name () const
96 if (s & Keyboard::PrimaryModifier) {
99 if (s & Keyboard::SecondaryModifier) {
105 if (s & Keyboard::TertiaryModifier) {
111 if (s & Keyboard::Level4Modifier) {
123 snprintf (buf, sizeof (buf), "%u", button());
129 KeyboardKey::KeyboardKey (uint32_t state, uint32_t keycode)
131 uint32_t ignore = Bindings::ignored_state();
133 if (gdk_keyval_is_upper (keycode) && gdk_keyval_is_lower (keycode)) {
134 /* key is not subject to case, so ignore SHIFT
136 ignore |= GDK_SHIFT_MASK;
139 _val = (state & ~ignore);
146 KeyboardKey::name () const
152 if (s & Keyboard::PrimaryModifier) {
155 if (s & Keyboard::SecondaryModifier) {
161 if (s & Keyboard::TertiaryModifier) {
167 if (s & Keyboard::Level4Modifier) {
178 str += gdk_keyval_name (key());
184 KeyboardKey::make_key (const string& str, KeyboardKey& k)
188 if (str.find ("Primary") != string::npos) {
189 s |= Keyboard::PrimaryModifier;
192 if (str.find ("Secondary") != string::npos) {
193 s |= Keyboard::SecondaryModifier;
196 if (str.find ("Tertiary") != string::npos) {
197 s |= Keyboard::TertiaryModifier;
200 if (str.find ("Level4") != string::npos) {
201 s |= Keyboard::Level4Modifier;
204 string::size_type lastmod = str.find_last_of ('-');
207 if (lastmod == string::npos) {
208 keyval = gdk_keyval_from_name (str.c_str());
210 keyval = gdk_keyval_from_name (str.substr (lastmod+1).c_str());
213 if (keyval == GDK_VoidSymbol) {
217 k = KeyboardKey (s, keyval);
221 Bindings::Bindings ()
226 Bindings::~Bindings()
231 Bindings::set_action_map (ActionMap& am)
234 press_bindings.clear ();
235 release_bindings.clear ();
239 Bindings::activate (KeyboardKey kb, Operation op)
241 KeybindingMap* kbm = 0;
245 kbm = &press_bindings;
248 kbm = &release_bindings;
252 KeybindingMap::iterator k = kbm->find (kb);
254 if (k == kbm->end()) {
255 /* no entry for this key in the state map */
261 k->second->activate ();
266 Bindings::add (KeyboardKey kb, Operation op, RefPtr<Action> what)
268 KeybindingMap* kbm = 0;
272 kbm = &press_bindings;
275 kbm = &release_bindings;
279 KeybindingMap::iterator k = kbm->find (kb);
281 if (k == kbm->end()) {
282 pair<KeyboardKey,RefPtr<Action> > newpair (kb, what);
283 kbm->insert (newpair);
284 // cerr << "Bindings added " << kb.key() << " w/ " << kb.state() << " => " << what->get_name() << endl;
291 Bindings::remove (KeyboardKey kb, Operation op)
293 KeybindingMap* kbm = 0;
297 kbm = &press_bindings;
300 kbm = &release_bindings;
304 KeybindingMap::iterator k = kbm->find (kb);
306 if (k != kbm->end()) {
312 Bindings::activate (MouseButton bb, Operation op)
314 MouseButtonBindingMap* bbm = 0;
318 bbm = &button_press_bindings;
321 bbm = &button_release_bindings;
325 MouseButtonBindingMap::iterator b = bbm->find (bb);
327 if (b == bbm->end()) {
328 /* no entry for this key in the state map */
334 b->second->activate ();
339 Bindings::add (MouseButton bb, Operation op, RefPtr<Action> what)
341 MouseButtonBindingMap* bbm = 0;
345 bbm = &button_press_bindings;
348 bbm = &button_release_bindings;
352 MouseButtonBindingMap::iterator b = bbm->find (bb);
354 if (b == bbm->end()) {
355 pair<MouseButton,RefPtr<Action> > newpair (bb, what);
356 bbm->insert (newpair);
357 // cerr << "Bindings added mouse button " << bb.button() << " w/ " << bb.state() << " => " << what->get_name() << endl;
364 Bindings::remove (MouseButton bb, Operation op)
366 MouseButtonBindingMap* bbm = 0;
370 bbm = &button_press_bindings;
373 bbm = &button_release_bindings;
377 MouseButtonBindingMap::iterator b = bbm->find (bb);
379 if (b != bbm->end()) {
385 Bindings::save (const string& path)
388 XMLNode* root = new XMLNode (X_("Bindings"));
389 tree.set_root (root);
393 if (!tree.write (path)) {
394 ::g_unlink (path.c_str());
402 Bindings::save (XMLNode& root)
404 XMLNode* presses = new XMLNode (X_("Press"));
405 root.add_child_nocopy (*presses);
407 for (KeybindingMap::iterator k = press_bindings.begin(); k != press_bindings.end(); ++k) {
409 child = new XMLNode (X_("Binding"));
410 child->add_property (X_("key"), k->first.name());
411 string ap = k->second->get_accel_path();
412 child->add_property (X_("action"), ap.substr (ap.find ('/') + 1));
413 presses->add_child_nocopy (*child);
416 for (MouseButtonBindingMap::iterator k = button_press_bindings.begin(); k != button_press_bindings.end(); ++k) {
418 child = new XMLNode (X_("Binding"));
419 child->add_property (X_("button"), k->first.name());
420 string ap = k->second->get_accel_path();
421 child->add_property (X_("action"), ap.substr (ap.find ('/') + 1));
422 presses->add_child_nocopy (*child);
425 XMLNode* releases = new XMLNode (X_("Release"));
426 root.add_child_nocopy (*releases);
428 for (KeybindingMap::iterator k = release_bindings.begin(); k != release_bindings.end(); ++k) {
430 child = new XMLNode (X_("Binding"));
431 child->add_property (X_("key"), k->first.name());
432 string ap = k->second->get_accel_path();
433 child->add_property (X_("action"), ap.substr (ap.find ('/') + 1));
434 releases->add_child_nocopy (*child);
437 for (MouseButtonBindingMap::iterator k = button_release_bindings.begin(); k != button_release_bindings.end(); ++k) {
439 child = new XMLNode (X_("Binding"));
440 child->add_property (X_("button"), k->first.name());
441 string ap = k->second->get_accel_path();
442 child->add_property (X_("action"), ap.substr (ap.find ('/') + 1));
443 releases->add_child_nocopy (*child);
449 Bindings::load (const string& path)
457 if (!tree.read (path)) {
461 press_bindings.clear ();
462 release_bindings.clear ();
464 XMLNode& root (*tree.root());
465 const XMLNodeList& children (root.children());
467 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
475 Bindings::load (const XMLNode& node)
477 if (node.name() == X_("Press") || node.name() == X_("Release")) {
481 if (node.name() == X_("Press")) {
487 const XMLNodeList& children (node.children());
489 for (XMLNodeList::const_iterator p = children.begin(); p != children.end(); ++p) {
495 ap = (*p)->property ("action");
496 kp = (*p)->property ("key");
497 bp = (*p)->property ("button");
499 if (!ap || (!kp && !bp)) {
506 act = action_map->find_action (ap->value());
510 string::size_type slash = ap->value().find ('/');
511 if (slash != string::npos) {
512 string group = ap->value().substr (0, slash);
513 string action = ap->value().substr (slash+1);
514 act = ActionManager::get_action (group.c_str(), action.c_str());
524 if (!KeyboardKey::make_key (kp->value(), k)) {
530 if (!MouseButton::make_button (bp->value(), b)) {
540 ActionMap::find_action (const string& name)
542 _ActionMap::iterator a = actions.find (name);
544 if (a != actions.end()) {
548 return RefPtr<Action>();
552 ActionMap::register_action (const char* path,
553 const char* name, const char* label, sigc::slot<void> sl)
557 RefPtr<Action> act = Action::create (name, label);
559 act->signal_activate().connect (sl);
565 actions.insert (_ActionMap::value_type (fullpath, act));
570 ActionMap::register_radio_action (const char* path, Gtk::RadioAction::Group& rgroup,
571 const char* name, const char* label,
572 sigc::slot<void,GtkAction*> sl,
577 RefPtr<Action> act = RadioAction::create (rgroup, name, label);
578 RefPtr<RadioAction> ract = RefPtr<RadioAction>::cast_dynamic(act);
579 ract->property_value() = value;
581 act->signal_activate().connect (sigc::bind (sl, act->gobj()));
587 actions.insert (_ActionMap::value_type (fullpath, act));
592 ActionMap::register_toggle_action (const char* path,
593 const char* name, const char* label, sigc::slot<void> sl)
597 RefPtr<Action> act = ToggleAction::create (name, label);
599 act->signal_activate().connect (sl);
605 actions.insert (_ActionMap::value_type (fullpath, act));