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/gstdio_compat.h"
23 #include <gtkmm/accelmap.h>
24 #include <gtkmm/uimanager.h>
26 #include "pbd/convert.h"
27 #include "pbd/debug.h"
28 #include "pbd/error.h"
29 #include "pbd/replace_all.h"
30 #include "pbd/xml++.h"
32 #include "gtkmm2ext/actions.h"
33 #include "gtkmm2ext/bindings.h"
34 #include "gtkmm2ext/debug.h"
35 #include "gtkmm2ext/keyboard.h"
36 #include "gtkmm2ext/utils.h"
43 using namespace Gtkmm2ext;
46 list<Bindings*> Bindings::bindings; /* global. Gulp */
47 list<ActionMap*> ActionMap::action_maps; /* global. Gulp */
48 PBD::Signal1<void,Bindings*> Bindings::BindingsChanged;
50 template <typename IteratorValueType>
51 struct ActionNameRegistered
53 ActionNameRegistered(std::string const& name)
57 bool operator()(IteratorValueType elem) const {
58 return elem.second.action_name == action_name;
60 std::string const& action_name;
63 MouseButton::MouseButton (uint32_t state, uint32_t keycode)
65 uint32_t ignore = ~Keyboard::RelevantModifierKeyMask;
67 /* this is a slightly wierd test that relies on
68 * gdk_keyval_is_{upper,lower}() returning true for keys that have no
69 * case-sensitivity. This covers mostly non-alphanumeric keys.
72 if (gdk_keyval_is_upper (keycode) && gdk_keyval_is_lower (keycode)) {
73 /* key is not subject to case, so ignore SHIFT
75 ignore |= GDK_SHIFT_MASK;
78 _val = (state & ~ignore);
84 MouseButton::make_button (const string& str, MouseButton& b)
88 if (str.find ("Primary") != string::npos) {
89 s |= Keyboard::PrimaryModifier;
92 if (str.find ("Secondary") != string::npos) {
93 s |= Keyboard::SecondaryModifier;
96 if (str.find ("Tertiary") != string::npos) {
97 s |= Keyboard::TertiaryModifier;
100 if (str.find ("Level4") != string::npos) {
101 s |= Keyboard::Level4Modifier;
104 string::size_type lastmod = str.find_last_of ('-');
105 uint32_t button_number;
107 if (lastmod == string::npos) {
108 button_number = PBD::atoi (str);
110 button_number = PBD::atoi (str.substr (lastmod+1));
113 b = MouseButton (s, button_number);
118 MouseButton::name () const
124 if (s & Keyboard::PrimaryModifier) {
127 if (s & Keyboard::SecondaryModifier) {
133 if (s & Keyboard::TertiaryModifier) {
139 if (s & Keyboard::Level4Modifier) {
151 snprintf (buf, sizeof (buf), "%u", button());
157 /*================================ KeyboardKey ================================*/
158 KeyboardKey::KeyboardKey (uint32_t state, uint32_t keycode)
160 uint32_t ignore = ~Keyboard::RelevantModifierKeyMask;
162 _val = (state & ~ignore);
168 KeyboardKey::display_label () const
174 /* This magically returns a string that will display the right thing
175 * on all platforms, notably the command key on OS X.
178 uint32_t mod = state();
181 /* We use both bits (MOD2|META) for Primary on OS X,
182 * but we don't want MOD2 showing up in listings.
185 if (mod & GDK_MOD2_MASK) {
186 mod &= ~GDK_MOD2_MASK;
190 return gtk_accelerator_get_label (key(), (GdkModifierType) mod);
194 KeyboardKey::name () const
200 if (s & Keyboard::PrimaryModifier) {
203 if (s & Keyboard::SecondaryModifier) {
209 if (s & Keyboard::TertiaryModifier) {
215 if (s & Keyboard::Level4Modifier) {
226 char const *gdk_name = gdk_keyval_name (key());
239 KeyboardKey::native_name () const
245 if (s & Keyboard::PrimaryModifier) {
246 str += Keyboard::primary_modifier_name ();
248 if (s & Keyboard::SecondaryModifier) {
252 str += Keyboard::secondary_modifier_name ();
254 if (s & Keyboard::TertiaryModifier) {
258 str += Keyboard::tertiary_modifier_name ();
260 if (s & Keyboard::Level4Modifier) {
264 str += Keyboard::level4_modifier_name ();
271 char const *gdk_name = gdk_keyval_name (key());
284 KeyboardKey::native_short_name () const
290 if (s & Keyboard::PrimaryModifier) {
291 str += Keyboard::primary_modifier_short_name ();
293 if (s & Keyboard::SecondaryModifier) {
297 str += Keyboard::secondary_modifier_short_name ();
299 if (s & Keyboard::TertiaryModifier) {
303 str += Keyboard::tertiary_modifier_short_name ();
305 if (s & Keyboard::Level4Modifier) {
309 str += Keyboard::level4_modifier_short_name ();
316 char const *gdk_name = gdk_keyval_name (key());
329 KeyboardKey::make_key (const string& str, KeyboardKey& k)
333 if (str.find ("Primary") != string::npos) {
334 s |= Keyboard::PrimaryModifier;
337 if (str.find ("Secondary") != string::npos) {
338 s |= Keyboard::SecondaryModifier;
341 if (str.find ("Tertiary") != string::npos) {
342 s |= Keyboard::TertiaryModifier;
345 if (str.find ("Level4") != string::npos) {
346 s |= Keyboard::Level4Modifier;
349 /* since all SINGLE key events keycodes are changed to lower case
350 * before looking them up, make sure we only store lower case here. The
351 * Shift part will be stored in the modifier part of the KeyboardKey.
353 * And yes Mildred, this doesn't cover CapsLock cases. Oh well.
358 string::size_type lastmod = str.find_last_of ('-');
360 if (lastmod != string::npos) {
361 actual = str.substr (lastmod+1);
367 if (actual.size() == 1) {
368 actual = PBD::downcase (actual);
372 keyval = gdk_keyval_from_name (actual.c_str());
374 if (keyval == GDK_VoidSymbol || keyval == 0) {
378 k = KeyboardKey (s, keyval);
383 /*================================= Bindings =================================*/
384 Bindings::Bindings (std::string const& name)
388 bindings.push_back (this);
391 Bindings::~Bindings()
393 bindings.remove (this);
397 Bindings::ardour_action_name (RefPtr<Action> action)
399 /* Skip "<Actions>/" */
400 return action->get_accel_path ().substr (10);
404 Bindings::get_binding_for_action (RefPtr<Action> action, Operation& op)
406 const string action_name = ardour_action_name (action);
408 for (KeybindingMap::iterator k = press_bindings.begin(); k != press_bindings.end(); ++k) {
410 /* option one: action has already been associated with the
414 if (k->second.action == action) {
418 /* option two: action name matches, so lookup the action,
419 * setup the association while we're here, and return the binding.
422 if (_action_map && k->second.action_name == action_name) {
423 k->second.action = _action_map->find_action (action_name);
429 for (KeybindingMap::iterator k = release_bindings.begin(); k != release_bindings.end(); ++k) {
431 /* option one: action has already been associated with the
435 if (k->second.action == action) {
439 /* option two: action name matches, so lookup the action,
440 * setup the association while we're here, and return the binding.
443 if (_action_map && k->second.action_name == action_name) {
444 k->second.action = _action_map->find_action (action_name);
450 return KeyboardKey::null_key();
454 Bindings::set_action_map (ActionMap& actions)
457 _action_map->set_bindings (0);
460 _action_map = &actions;
461 _action_map->set_bindings (this);
468 Bindings::empty_keys() const
470 return press_bindings.empty() && release_bindings.empty();
474 Bindings::empty_mouse () const
476 return button_press_bindings.empty() && button_release_bindings.empty();
480 Bindings::empty() const
482 return empty_keys() && empty_mouse ();
486 Bindings::activate (KeyboardKey kb, Operation op)
488 KeybindingMap& kbm = get_keymap (op);
490 /* if shift was pressed, GDK will send us (e.g) 'E' rather than 'e'.
491 Our bindings all use the lower case character/keyname, so switch
492 to the lower case before doing the lookup.
495 KeyboardKey unshifted (kb.state(), gdk_keyval_to_lower (kb.key()));
497 KeybindingMap::iterator k = kbm.find (unshifted);
499 if (k == kbm.end()) {
500 /* no entry for this key in the state map */
501 DEBUG_TRACE (DEBUG::Bindings, string_compose ("no binding for %1\n", unshifted));
505 RefPtr<Action> action;
507 if (k->second.action) {
508 action = k->second.action;
511 action = _action_map->find_action (k->second.action_name);
517 DEBUG_TRACE (DEBUG::Bindings, string_compose ("binding for %1: %2\n", unshifted, k->second.action_name));
521 /* return true even if the action could not be found */
527 Bindings::associate ()
529 KeybindingMap::iterator k;
535 for (k = press_bindings.begin(); k != press_bindings.end(); ++k) {
536 k->second.action = _action_map->find_action (k->second.action_name);
537 if (k->second.action) {
538 push_to_gtk (k->first, k->second.action);
540 cerr << _name << " didn't find " << k->second.action_name << " in " << _action_map->name() << endl;
544 for (k = release_bindings.begin(); k != release_bindings.end(); ++k) {
545 k->second.action = _action_map->find_action (k->second.action_name);
546 /* no working support in GTK for release bindings */
549 MouseButtonBindingMap::iterator b;
551 for (b = button_press_bindings.begin(); b != button_press_bindings.end(); ++b) {
552 b->second.action = _action_map->find_action (b->second.action_name);
555 for (b = button_release_bindings.begin(); b != button_release_bindings.end(); ++b) {
556 b->second.action = _action_map->find_action (b->second.action_name);
561 Bindings::dissociate ()
563 KeybindingMap::iterator k;
565 for (k = press_bindings.begin(); k != press_bindings.end(); ++k) {
566 k->second.action.clear ();
568 for (k = release_bindings.begin(); k != release_bindings.end(); ++k) {
569 k->second.action.clear ();
574 Bindings::push_to_gtk (KeyboardKey kb, RefPtr<Action> what)
576 /* GTK has the useful feature of showing key bindings for actions in
577 * menus. As of August 2015, we have no interest in trying to
578 * reimplement this functionality, so we will use it even though we no
579 * longer use GTK accelerators for handling key events. To do this, we
580 * need to make sure that there is a fully populated GTK AccelMap set
581 * up with all bindings/actions.
584 Gtk::AccelKey gtk_key;
585 bool entry_exists = Gtk::AccelMap::lookup_entry (what->get_accel_path(), gtk_key);
589 /* there is a trick happening here. It turns out that
590 * gtk_accel_map_add_entry() performs no validation checks on
591 * the accelerator keyval. This means we can use it to define
592 * ANY accelerator, even if they violate GTK's rules
593 * (e.g. about not using navigation keys). This works ONLY when
594 * the entry in the GTK accelerator map has not already been
595 * added. The entries will be added by the GTK UIManager when
596 * building menus, so this code must be called before that
601 int mod = kb.state();
603 /* See comments in Keyboard::Keyboard about GTK handling of MOD2, META and the Command key.
605 * If we do not do this, GTK+ won't show the correct text for shortcuts in menus.
608 if (mod & GDK_MOD2_MASK) {
609 mod = mod | GDK_META_MASK;
613 Gtk::AccelMap::add_entry (what->get_accel_path(), kb.key(), (Gdk::ModifierType) mod);
618 Bindings::replace (KeyboardKey kb, Operation op, string const & action_name, bool can_save)
624 if (is_registered(op, action_name)) {
625 remove (op, action_name, can_save);
628 /* XXX need a way to get the old group name */
629 add (kb, op, action_name, 0, can_save);
635 Bindings::add (KeyboardKey kb, Operation op, string const& action_name, XMLProperty const* group, bool can_save)
637 if (is_registered (op, action_name)) {
641 KeybindingMap& kbm = get_keymap (op);
643 KeybindingMap::value_type new_pair = make_pair (kb, ActionInfo (action_name, group->value()));
644 (void) kbm.insert (new_pair).first;
646 KeybindingMap::value_type new_pair = make_pair (kb, ActionInfo (action_name));
647 (void) kbm.insert (new_pair).first;
651 Keyboard::keybindings_changed ();
654 BindingsChanged (this); /* EMIT SIGNAL */
659 Bindings::remove (Operation op, std::string const& action_name, bool can_save)
661 bool erased_action = false;
662 KeybindingMap& kbm = get_keymap (op);
663 for (KeybindingMap::iterator k = kbm.begin(); k != kbm.end(); ++k) {
664 if (k->second.action_name == action_name) {
666 erased_action = true;
671 if (!erased_action) {
672 return erased_action;
676 Keyboard::keybindings_changed ();
679 BindingsChanged (this); /* EMIT SIGNAL */
680 return erased_action;
685 Bindings::activate (MouseButton bb, Operation op)
687 MouseButtonBindingMap& bbm = get_mousemap(op);
689 MouseButtonBindingMap::iterator b = bbm.find (bb);
691 if (b == bbm.end()) {
692 /* no entry for this key in the state map */
696 RefPtr<Action> action;
698 if (b->second.action) {
699 action = b->second.action;
702 action = _action_map->find_action (b->second.action_name);
708 DEBUG_TRACE (DEBUG::Bindings, string_compose ("activating action %1\n", ardour_action_name (action)));
712 /* return true even if the action could not be found */
718 Bindings::add (MouseButton bb, Operation op, string const& action_name, XMLProperty const* /*group*/)
720 MouseButtonBindingMap& bbm = get_mousemap(op);
722 MouseButtonBindingMap::value_type newpair (bb, ActionInfo (action_name));
723 bbm.insert (newpair);
727 Bindings::remove (MouseButton bb, Operation op)
729 MouseButtonBindingMap& bbm = get_mousemap(op);
730 MouseButtonBindingMap::iterator b = bbm.find (bb);
732 if (b != bbm.end()) {
738 Bindings::save (XMLNode& root)
740 XMLNode* presses = new XMLNode (X_("Press"));
742 for (KeybindingMap::iterator k = press_bindings.begin(); k != press_bindings.end(); ++k) {
745 if (k->first.name().empty()) {
749 child = new XMLNode (X_("Binding"));
750 child->add_property (X_("key"), k->first.name());
751 child->add_property (X_("action"), k->second.action_name);
752 presses->add_child_nocopy (*child);
755 for (MouseButtonBindingMap::iterator k = button_press_bindings.begin(); k != button_press_bindings.end(); ++k) {
757 child = new XMLNode (X_("Binding"));
758 child->add_property (X_("button"), k->first.name());
759 child->add_property (X_("action"), k->second.action_name);
760 presses->add_child_nocopy (*child);
763 XMLNode* releases = new XMLNode (X_("Release"));
765 for (KeybindingMap::iterator k = release_bindings.begin(); k != release_bindings.end(); ++k) {
768 if (k->first.name().empty()) {
772 child = new XMLNode (X_("Binding"));
773 child->add_property (X_("key"), k->first.name());
774 child->add_property (X_("action"), k->second.action_name);
775 releases->add_child_nocopy (*child);
778 for (MouseButtonBindingMap::iterator k = button_release_bindings.begin(); k != button_release_bindings.end(); ++k) {
780 child = new XMLNode (X_("Binding"));
781 child->add_property (X_("button"), k->first.name());
782 child->add_property (X_("action"), k->second.action_name);
783 releases->add_child_nocopy (*child);
786 root.add_child_nocopy (*presses);
787 root.add_child_nocopy (*releases);
791 Bindings::save_all_bindings_as_html (ostream& ostr)
793 if (bindings.empty()) {
798 ostr << "<html>\n<head>\n<title>";
799 ostr << PROGRAM_NAME;
800 ostr << "</title>\n";
805 .key-name-even, .key-name-odd\n\
807 font-weight: bold;\n\
810 .key-action-odd, .key-action-even\n\
812 font-weight: normal;\n\
813 font-style: italic;\n\
815 ostr << "</style>\n";
817 ostr << "</head>\n<body>\n";
819 ostr << "<div class=\"container\">\n";
821 for (list<Bindings*>::const_iterator b = bindings.begin(); b != bindings.end(); ++b) {
822 (*b)->save_as_html (ostr);
831 Bindings::save_as_html (ostream& ostr) const
834 if (!press_bindings.empty()) {
836 ostr << "<div class=\"binding-set\">\n";
841 /* first pass: separate by group */
843 typedef std::map<std::string, std::vector<KeybindingMap::const_iterator> > GroupMap;
846 for (KeybindingMap::const_iterator k = press_bindings.begin(); k != press_bindings.end(); ++k) {
847 if (k->first.name().empty()) {
852 if (!k->second.group_name.empty()) {
853 group_name = k->second.group_name;
855 group_name = X_("nogroup");
858 GroupMap::iterator gm = group_map.find (group_name);
859 if (gm == group_map.end()) {
860 std::vector<KeybindingMap::const_iterator> li;
862 group_map.insert (make_pair (group_name,li));
864 gm->second.push_back (k);
868 for (GroupMap::const_iterator gm = group_map.begin(); gm != group_map.end(); ++gm) {
870 ostr << "<div class=\"group\">\n";
871 ostr << "<div class=\"group-name\">" << gm->first << "</div>\n";
873 for (vector<KeybindingMap::const_iterator>::const_iterator k = gm->second.begin(); k != gm->second.end(); ++k) {
875 if ((*k)->first.name().empty()) {
879 RefPtr<Action> action;
881 if ((*k)->second.action) {
882 action = (*k)->second.action;
885 action = _action_map->find_action ((*k)->second.action_name);
893 string key_name = (*k)->first.native_short_name ();
894 replace_all (key_name, X_("KP_"), X_("Numpad "));
896 string::size_type pos;
898 char const *targets[] = { X_("Separator"), X_("Add"), X_("Subtract"), X_("Decimal"), X_("Divide"),
899 X_("grave"), X_("comma"), X_("period"), X_("asterisk"), X_("backslash"),
900 X_("apostrophe"), X_("minus"), X_("plus"), X_("slash"), X_("semicolon"),
901 X_("colon"), X_("equal"), X_("bracketleft"), X_("bracketright"),
902 X_("ampersand"), X_("numbersign"), X_("parenleft"), X_("parenright"),
903 X_("quoteright"), X_("quoteleft"), X_("exclam"), X_("quotedbl"),
907 char const *replacements[] = { X_("-"), X_("+"), X_("-"), X_("."), X_("/"),
908 X_("`"), X_(","), X_("."), X_("*"), X_("\\"),
909 X_("'"), X_("-"), X_("+"), X_("/"), X_(";"),
910 X_(":"), X_("="), X_("{"), X_("{"),
911 X_("&"), X_("#"), X_("("), X_(")"),
912 X_("`"), X_("'"), X_("!"), X_("\""),
915 for (size_t n = 0; targets[n]; ++n) {
916 if ((pos = key_name.find (targets[n])) != string::npos) {
917 key_name.replace (pos, strlen (targets[n]), replacements[n]);
921 ostr << "<div class=\"key\">" << key_name << "</div>";
922 ostr << "<div class=\"action\">" << action->get_label() << "</div>\n";
924 ostr << "</div>\n\n";
932 Bindings::load (XMLNode const& node)
934 const XMLNodeList& children (node.children());
936 press_bindings.clear ();
937 release_bindings.clear ();
939 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
940 /* each node could be Press or Release */
941 load_operation (**i);
948 Bindings::load_operation (XMLNode const& node)
950 if (node.name() == X_("Press") || node.name() == X_("Release")) {
954 if (node.name() == X_("Press")) {
960 const XMLNodeList& children (node.children());
962 for (XMLNodeList::const_iterator p = children.begin(); p != children.end(); ++p) {
964 XMLProperty const * ap;
965 XMLProperty const * kp;
966 XMLProperty const * bp;
967 XMLProperty const * gp;
968 XMLNode const * child = *p;
970 ap = child->property ("action");
971 kp = child->property ("key");
972 bp = child->property ("button");
973 gp = child->property ("group");
975 if (!ap || (!kp && !bp)) {
981 if (!KeyboardKey::make_key (kp->value(), k)) {
984 add (k, op, ap->value(), gp);
987 if (!MouseButton::make_button (bp->value(), b)) {
990 add (b, op, ap->value(), gp);
997 Bindings::get_all_actions (std::vector<std::string>& paths,
998 std::vector<std::string>& labels,
999 std::vector<std::string>& tooltips,
1000 std::vector<std::string>& keys,
1001 std::vector<RefPtr<Action> >& actions)
1007 /* build a reverse map from actions to bindings */
1009 typedef map<Glib::RefPtr<Gtk::Action>,KeyboardKey> ReverseMap;
1012 for (KeybindingMap::const_iterator k = press_bindings.begin(); k != press_bindings.end(); ++k) {
1013 rmap.insert (make_pair (k->second.action, k->first));
1016 /* get a list of all actions */
1018 ActionMap::Actions all_actions;
1019 _action_map->get_actions (all_actions);
1021 for (ActionMap::Actions::const_iterator act = all_actions.begin(); act != all_actions.end(); ++act) {
1023 paths.push_back ((*act)->get_accel_path());
1024 labels.push_back ((*act)->get_label());
1025 tooltips.push_back ((*act)->get_tooltip());
1027 ReverseMap::iterator r = rmap.find (*act);
1029 if (r != rmap.end()) {
1030 keys.push_back (r->second.display_label());
1032 keys.push_back (string());
1035 actions.push_back (*act);
1040 Bindings::get_bindings (string const& name, ActionMap& map)
1042 for (list<Bindings*>::iterator b = bindings.begin(); b != bindings.end(); b++) {
1043 if ((*b)->name() == name) {
1044 (*b)->set_action_map (map);
1053 Bindings::associate_all ()
1055 for (list<Bindings*>::iterator b = bindings.begin(); b != bindings.end(); b++) {
1061 Bindings::is_bound (KeyboardKey const& kb, Operation op) const
1063 const KeybindingMap& km = get_keymap(op);
1064 return km.find(kb) != km.end();
1068 Bindings::is_registered (Operation op, std::string const& action_name) const
1070 const KeybindingMap& km = get_keymap(op);
1071 return std::find_if(km.begin(), km.end(), ActionNameRegistered<KeybindingMap::const_iterator::value_type>(action_name)) != km.end();
1074 Bindings::KeybindingMap&
1075 Bindings::get_keymap (Operation op)
1079 return press_bindings;
1082 return release_bindings;
1086 const Bindings::KeybindingMap&
1087 Bindings::get_keymap (Operation op) const
1091 return press_bindings;
1094 return release_bindings;
1098 Bindings::MouseButtonBindingMap&
1099 Bindings::get_mousemap (Operation op)
1103 return button_press_bindings;
1106 return button_release_bindings;
1110 /*==========================================ACTION MAP =========================================*/
1112 ActionMap::ActionMap (string const & name)
1116 action_maps.push_back (this);
1119 ActionMap::~ActionMap ()
1121 action_maps.remove (this);
1125 ActionMap::set_bindings (Bindings* b)
1131 ActionMap::get_actions (ActionMap::Actions& acts)
1133 for (_ActionMap::iterator a = _actions.begin(); a != _actions.end(); ++a) {
1134 acts.push_back (a->second);
1139 ActionMap::find_action (const string& name)
1141 _ActionMap::iterator a = _actions.find (name);
1143 if (a != _actions.end()) {
1147 return RefPtr<Action>();
1151 ActionMap::create_action_group (const string& name)
1153 RefPtr<ActionGroup> g = ActionGroup::create (name);
1155 /* this is one of the places where our own Action management code
1156 has to touch the GTK one, because we want the GtkUIManager to
1157 be able to create widgets (particularly Menus) from our actions.
1159 This is a a necessary step for that to happen.
1163 ActionManager::ui_manager->insert_action_group (g);
1170 ActionMap::register_action (RefPtr<ActionGroup> group, const char* name, const char* label)
1174 RefPtr<Action> act = Action::create (name, label);
1176 fullpath = group->get_name();
1180 if (_actions.insert (_ActionMap::value_type (fullpath, act)).second) {
1185 /* already registered */
1186 return RefPtr<Action> ();
1190 ActionMap::register_action (RefPtr<ActionGroup> group,
1191 const char* name, const char* label, sigc::slot<void> sl)
1195 RefPtr<Action> act = Action::create (name, label);
1197 fullpath = group->get_name();
1201 if (_actions.insert (_ActionMap::value_type (fullpath, act)).second) {
1202 group->add (act, sl);
1206 /* already registered */
1207 return RefPtr<Action>();
1211 ActionMap::register_radio_action (RefPtr<ActionGroup> group,
1212 Gtk::RadioAction::Group& rgroup,
1213 const char* name, const char* label,
1214 sigc::slot<void> sl)
1218 RefPtr<Action> act = RadioAction::create (rgroup, name, label);
1219 RefPtr<RadioAction> ract = RefPtr<RadioAction>::cast_dynamic(act);
1221 fullpath = group->get_name();
1225 if (_actions.insert (_ActionMap::value_type (fullpath, act)).second) {
1226 group->add (act, sl);
1230 /* already registered */
1231 return RefPtr<Action>();
1235 ActionMap::register_radio_action (RefPtr<ActionGroup> group,
1236 Gtk::RadioAction::Group& rgroup,
1237 const char* name, const char* label,
1238 sigc::slot<void,GtkAction*> sl,
1243 RefPtr<Action> act = RadioAction::create (rgroup, name, label);
1244 RefPtr<RadioAction> ract = RefPtr<RadioAction>::cast_dynamic(act);
1245 ract->property_value() = value;
1247 fullpath = group->get_name();
1251 if (_actions.insert (_ActionMap::value_type (fullpath, act)).second) {
1252 group->add (act, sigc::bind (sl, act->gobj()));
1256 /* already registered */
1258 return RefPtr<Action>();
1262 ActionMap::register_toggle_action (RefPtr<ActionGroup> group,
1263 const char* name, const char* label, sigc::slot<void> sl)
1267 fullpath = group->get_name();
1271 RefPtr<Action> act = ToggleAction::create (name, label);
1273 if (_actions.insert (_ActionMap::value_type (fullpath, act)).second) {
1274 group->add (act, sl);
1278 /* already registered */
1279 return RefPtr<Action>();
1283 ActionMap::get_all_actions (std::vector<std::string>& paths,
1284 std::vector<std::string>& labels,
1285 std::vector<std::string>& tooltips,
1286 std::vector<std::string>& keys,
1287 std::vector<RefPtr<Action> >& actions)
1289 for (list<ActionMap*>::const_iterator map = action_maps.begin(); map != action_maps.end(); ++map) {
1291 ActionMap::Actions these_actions;
1292 (*map)->get_actions (these_actions);
1294 for (ActionMap::Actions::const_iterator act = these_actions.begin(); act != these_actions.end(); ++act) {
1296 paths.push_back ((*act)->get_accel_path());
1297 labels.push_back ((*act)->get_label());
1298 tooltips.push_back ((*act)->get_tooltip());
1299 actions.push_back (*act);
1301 Bindings* bindings = (*map)->bindings();
1306 Bindings::Operation op;
1308 key = bindings->get_binding_for_action (*act, op);
1310 if (key == KeyboardKey::null_key()) {
1311 keys.push_back (string());
1313 keys.push_back (key.display_label());
1316 keys.push_back (string());
1320 these_actions.clear ();
1324 std::ostream& operator<<(std::ostream& out, Gtkmm2ext::KeyboardKey const & k) {
1325 char const *gdk_name = gdk_keyval_name (k.key());
1326 return out << "Key " << k.key() << " (" << (gdk_name ? gdk_name : "no-key") << ") state " << hex << k.state() << dec;