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 "pbd/xml++.h"
23 #include "pbd/convert.h"
25 #include "gtkmm2ext/actions.h"
26 #include "gtkmm2ext/bindings.h"
27 #include "gtkmm2ext/keyboard.h"
34 using namespace Gtkmm2ext;
36 uint32_t Bindings::_ignored_state = 0;
38 MouseButton::MouseButton (uint32_t state, uint32_t keycode)
40 uint32_t ignore = Bindings::ignored_state();
42 if (gdk_keyval_is_upper (keycode) && gdk_keyval_is_lower (keycode)) {
43 /* key is not subject to case, so ignore SHIFT
45 ignore |= GDK_SHIFT_MASK;
48 _val = (state & ~ignore);
54 MouseButton::make_button (const string& str, MouseButton& b)
58 if (str.find ("Primary") != string::npos) {
59 s |= Keyboard::PrimaryModifier;
62 if (str.find ("Secondary") != string::npos) {
63 s |= Keyboard::SecondaryModifier;
66 if (str.find ("Tertiary") != string::npos) {
67 s |= Keyboard::TertiaryModifier;
70 if (str.find ("Level4") != string::npos) {
71 s |= Keyboard::Level4Modifier;
74 string::size_type lastmod = str.find_last_of ('-');
75 uint32_t button_number;
77 if (lastmod == string::npos) {
78 button_number = PBD::atoi (str);
80 button_number = PBD::atoi (str.substr (lastmod+1));
83 b = MouseButton (s, button_number);
88 MouseButton::name () const
94 if (s & Keyboard::PrimaryModifier) {
97 if (s & Keyboard::SecondaryModifier) {
103 if (s & Keyboard::TertiaryModifier) {
109 if (s & Keyboard::Level4Modifier) {
121 snprintf (buf, sizeof (buf), "%u", button());
127 KeyboardKey::KeyboardKey (uint32_t state, uint32_t keycode)
129 uint32_t ignore = Bindings::ignored_state();
131 if (gdk_keyval_is_upper (keycode) && gdk_keyval_is_lower (keycode)) {
132 /* key is not subject to case, so ignore SHIFT
134 ignore |= GDK_SHIFT_MASK;
137 _val = (state & ~ignore);
144 KeyboardKey::name () const
150 if (s & Keyboard::PrimaryModifier) {
153 if (s & Keyboard::SecondaryModifier) {
159 if (s & Keyboard::TertiaryModifier) {
165 if (s & Keyboard::Level4Modifier) {
176 str += gdk_keyval_name (key());
182 KeyboardKey::make_key (const string& str, KeyboardKey& k)
186 if (str.find ("Primary") != string::npos) {
187 s |= Keyboard::PrimaryModifier;
190 if (str.find ("Secondary") != string::npos) {
191 s |= Keyboard::SecondaryModifier;
194 if (str.find ("Tertiary") != string::npos) {
195 s |= Keyboard::TertiaryModifier;
198 if (str.find ("Level4") != string::npos) {
199 s |= Keyboard::Level4Modifier;
202 string::size_type lastmod = str.find_last_of ('-');
205 if (lastmod == string::npos) {
206 keyval = gdk_keyval_from_name (str.c_str());
208 keyval = gdk_keyval_from_name (str.substr (lastmod+1).c_str());
211 if (keyval == GDK_VoidSymbol) {
215 k = KeyboardKey (s, keyval);
219 Bindings::Bindings ()
224 Bindings::~Bindings()
229 Bindings::set_action_map (ActionMap& am)
232 press_bindings.clear ();
233 release_bindings.clear ();
237 Bindings::activate (KeyboardKey kb, Operation op)
239 KeybindingMap* kbm = 0;
243 kbm = &press_bindings;
246 kbm = &release_bindings;
250 KeybindingMap::iterator k = kbm->find (kb);
252 if (k == kbm->end()) {
253 /* no entry for this key in the state map */
259 k->second->activate ();
264 Bindings::add (KeyboardKey kb, Operation op, RefPtr<Action> what)
266 KeybindingMap* kbm = 0;
270 kbm = &press_bindings;
273 kbm = &release_bindings;
277 KeybindingMap::iterator k = kbm->find (kb);
279 if (k == kbm->end()) {
280 pair<KeyboardKey,RefPtr<Action> > newpair (kb, what);
281 kbm->insert (newpair);
282 // cerr << "Bindings added " << kb.key() << " w/ " << kb.state() << " => " << what->get_name() << endl;
289 Bindings::remove (KeyboardKey kb, Operation op)
291 KeybindingMap* kbm = 0;
295 kbm = &press_bindings;
298 kbm = &release_bindings;
302 KeybindingMap::iterator k = kbm->find (kb);
304 if (k != kbm->end()) {
310 Bindings::activate (MouseButton bb, Operation op)
312 MouseButtonBindingMap* bbm = 0;
316 bbm = &button_press_bindings;
319 bbm = &button_release_bindings;
323 MouseButtonBindingMap::iterator b = bbm->find (bb);
325 if (b == bbm->end()) {
326 /* no entry for this key in the state map */
332 b->second->activate ();
337 Bindings::add (MouseButton bb, Operation op, RefPtr<Action> what)
339 MouseButtonBindingMap* bbm = 0;
343 bbm = &button_press_bindings;
346 bbm = &button_release_bindings;
350 MouseButtonBindingMap::iterator b = bbm->find (bb);
352 if (b == bbm->end()) {
353 pair<MouseButton,RefPtr<Action> > newpair (bb, what);
354 bbm->insert (newpair);
355 // cerr << "Bindings added mouse button " << bb.button() << " w/ " << bb.state() << " => " << what->get_name() << endl;
362 Bindings::remove (MouseButton bb, Operation op)
364 MouseButtonBindingMap* bbm = 0;
368 bbm = &button_press_bindings;
371 bbm = &button_release_bindings;
375 MouseButtonBindingMap::iterator b = bbm->find (bb);
377 if (b != bbm->end()) {
383 Bindings::save (const string& path)
386 XMLNode* root = new XMLNode (X_("Bindings"));
387 tree.set_root (root);
391 if (!tree.write (path)) {
392 ::unlink (path.c_str());
400 Bindings::save (XMLNode& root)
402 XMLNode* presses = new XMLNode (X_("Press"));
403 root.add_child_nocopy (*presses);
405 for (KeybindingMap::iterator k = press_bindings.begin(); k != press_bindings.end(); ++k) {
407 child = new XMLNode (X_("Binding"));
408 child->add_property (X_("key"), k->first.name());
409 string ap = k->second->get_accel_path();
410 child->add_property (X_("action"), ap.substr (ap.find ('/') + 1));
411 presses->add_child_nocopy (*child);
414 for (MouseButtonBindingMap::iterator k = button_press_bindings.begin(); k != button_press_bindings.end(); ++k) {
416 child = new XMLNode (X_("Binding"));
417 child->add_property (X_("button"), k->first.name());
418 string ap = k->second->get_accel_path();
419 child->add_property (X_("action"), ap.substr (ap.find ('/') + 1));
420 presses->add_child_nocopy (*child);
423 XMLNode* releases = new XMLNode (X_("Release"));
424 root.add_child_nocopy (*releases);
426 for (KeybindingMap::iterator k = release_bindings.begin(); k != release_bindings.end(); ++k) {
428 child = new XMLNode (X_("Binding"));
429 child->add_property (X_("key"), k->first.name());
430 string ap = k->second->get_accel_path();
431 child->add_property (X_("action"), ap.substr (ap.find ('/') + 1));
432 releases->add_child_nocopy (*child);
435 for (MouseButtonBindingMap::iterator k = button_release_bindings.begin(); k != button_release_bindings.end(); ++k) {
437 child = new XMLNode (X_("Binding"));
438 child->add_property (X_("button"), k->first.name());
439 string ap = k->second->get_accel_path();
440 child->add_property (X_("action"), ap.substr (ap.find ('/') + 1));
441 releases->add_child_nocopy (*child);
447 Bindings::load (const string& path)
455 if (!tree.read (path)) {
459 press_bindings.clear ();
460 release_bindings.clear ();
462 XMLNode& root (*tree.root());
463 const XMLNodeList& children (root.children());
465 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
473 Bindings::load (const XMLNode& node)
475 if (node.name() == X_("Press") || node.name() == X_("Release")) {
479 if (node.name() == X_("Press")) {
485 const XMLNodeList& children (node.children());
487 for (XMLNodeList::const_iterator p = children.begin(); p != children.end(); ++p) {
493 ap = (*p)->property ("action");
494 kp = (*p)->property ("key");
495 bp = (*p)->property ("button");
497 if (!ap || (!kp && !bp)) {
504 act = action_map->find_action (ap->value());
508 string::size_type slash = ap->value().find ('/');
509 if (slash != string::npos) {
510 string group = ap->value().substr (0, slash);
511 string action = ap->value().substr (slash+1);
512 act = ActionManager::get_action (group.c_str(), action.c_str());
522 if (!KeyboardKey::make_key (kp->value(), k)) {
528 if (!MouseButton::make_button (bp->value(), b)) {
538 ActionMap::find_action (const string& name)
540 _ActionMap::iterator a = actions.find (name);
542 if (a != actions.end()) {
546 return RefPtr<Action>();
550 ActionMap::register_action (const char* path,
551 const char* name, const char* label, sigc::slot<void> sl)
555 RefPtr<Action> act = Action::create (name, label);
557 act->signal_activate().connect (sl);
563 actions.insert (_ActionMap::value_type (fullpath, act));
568 ActionMap::register_radio_action (const char* path, Gtk::RadioAction::Group& rgroup,
569 const char* name, const char* label,
570 sigc::slot<void,GtkAction*> sl,
575 RefPtr<Action> act = RadioAction::create (rgroup, name, label);
576 RefPtr<RadioAction> ract = RefPtr<RadioAction>::cast_dynamic(act);
577 ract->property_value() = value;
579 act->signal_activate().connect (sigc::bind (sl, act->gobj()));
585 actions.insert (_ActionMap::value_type (fullpath, act));
590 ActionMap::register_toggle_action (const char* path,
591 const char* name, const char* label, sigc::slot<void> sl)
595 RefPtr<Action> act = ToggleAction::create (name, label);
597 act->signal_activate().connect (sl);
603 actions.insert (_ActionMap::value_type (fullpath, act));