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
600 Gtk::AccelMap::add_entry (what->get_accel_path(), kb.key(), (Gdk::ModifierType) kb.state());
605 Bindings::replace (KeyboardKey kb, Operation op, string const & action_name, bool can_save)
611 if (is_registered(op, action_name)) {
612 remove (op, action_name, can_save);
615 /* XXX need a way to get the old group name */
616 add (kb, op, action_name, 0, can_save);
622 Bindings::add (KeyboardKey kb, Operation op, string const& action_name, XMLProperty const* group, bool can_save)
624 if (is_registered (op, action_name)) {
628 KeybindingMap& kbm = get_keymap (op);
630 KeybindingMap::value_type new_pair = make_pair (kb, ActionInfo (action_name, group->value()));
631 kbm.insert (new_pair).first;
633 KeybindingMap::value_type new_pair = make_pair (kb, ActionInfo (action_name));
634 kbm.insert (new_pair).first;
638 Keyboard::keybindings_changed ();
641 BindingsChanged (this); /* EMIT SIGNAL */
646 Bindings::remove (Operation op, std::string const& action_name, bool can_save)
648 bool erased_action = false;
649 KeybindingMap& kbm = get_keymap (op);
650 for (KeybindingMap::iterator k = kbm.begin(); k != kbm.end(); ++k) {
651 if (k->second.action_name == action_name) {
653 erased_action = true;
658 if (!erased_action) {
659 return erased_action;
663 Keyboard::keybindings_changed ();
666 BindingsChanged (this); /* EMIT SIGNAL */
667 return erased_action;
672 Bindings::activate (MouseButton bb, Operation op)
674 MouseButtonBindingMap& bbm = get_mousemap(op);
676 MouseButtonBindingMap::iterator b = bbm.find (bb);
678 if (b == bbm.end()) {
679 /* no entry for this key in the state map */
683 RefPtr<Action> action;
685 if (b->second.action) {
686 action = b->second.action;
689 action = _action_map->find_action (b->second.action_name);
695 DEBUG_TRACE (DEBUG::Bindings, string_compose ("activating action %1\n", ardour_action_name (action)));
699 /* return true even if the action could not be found */
705 Bindings::add (MouseButton bb, Operation op, string const& action_name, XMLProperty const* /*group*/)
707 MouseButtonBindingMap& bbm = get_mousemap(op);
709 MouseButtonBindingMap::value_type newpair (bb, ActionInfo (action_name));
710 bbm.insert (newpair);
714 Bindings::remove (MouseButton bb, Operation op)
716 MouseButtonBindingMap& bbm = get_mousemap(op);
717 MouseButtonBindingMap::iterator b = bbm.find (bb);
719 if (b != bbm.end()) {
725 Bindings::save (XMLNode& root)
727 XMLNode* presses = new XMLNode (X_("Press"));
729 for (KeybindingMap::iterator k = press_bindings.begin(); k != press_bindings.end(); ++k) {
732 if (k->first.name().empty()) {
736 child = new XMLNode (X_("Binding"));
737 child->add_property (X_("key"), k->first.name());
738 child->add_property (X_("action"), k->second.action_name);
739 presses->add_child_nocopy (*child);
742 for (MouseButtonBindingMap::iterator k = button_press_bindings.begin(); k != button_press_bindings.end(); ++k) {
744 child = new XMLNode (X_("Binding"));
745 child->add_property (X_("button"), k->first.name());
746 child->add_property (X_("action"), k->second.action_name);
747 presses->add_child_nocopy (*child);
750 XMLNode* releases = new XMLNode (X_("Release"));
752 for (KeybindingMap::iterator k = release_bindings.begin(); k != release_bindings.end(); ++k) {
755 if (k->first.name().empty()) {
759 child = new XMLNode (X_("Binding"));
760 child->add_property (X_("key"), k->first.name());
761 child->add_property (X_("action"), k->second.action_name);
762 releases->add_child_nocopy (*child);
765 for (MouseButtonBindingMap::iterator k = button_release_bindings.begin(); k != button_release_bindings.end(); ++k) {
767 child = new XMLNode (X_("Binding"));
768 child->add_property (X_("button"), k->first.name());
769 child->add_property (X_("action"), k->second.action_name);
770 releases->add_child_nocopy (*child);
773 root.add_child_nocopy (*presses);
774 root.add_child_nocopy (*releases);
778 Bindings::save_all_bindings_as_html (ostream& ostr)
780 if (bindings.empty()) {
785 ostr << "<html>\n<head>\n<title>";
786 ostr << PROGRAM_NAME;
787 ostr << "</title>\n";
792 .key-name-even, .key-name-odd\n\
794 font-weight: bold;\n\
797 .key-action-odd, .key-action-even\n\
799 font-weight: normal;\n\
800 font-style: italic;\n\
802 ostr << "</style>\n";
804 ostr << "</head>\n<body>\n";
806 ostr << "<div class=\"container\">\n";
808 for (list<Bindings*>::const_iterator b = bindings.begin(); b != bindings.end(); ++b) {
809 (*b)->save_as_html (ostr);
818 Bindings::save_as_html (ostream& ostr) const
821 if (!press_bindings.empty()) {
823 ostr << "<div class=\"binding-set\">\n";
828 /* first pass: separate by group */
830 typedef std::map<std::string, std::vector<KeybindingMap::const_iterator> > GroupMap;
833 for (KeybindingMap::const_iterator k = press_bindings.begin(); k != press_bindings.end(); ++k) {
834 if (k->first.name().empty()) {
839 if (!k->second.group_name.empty()) {
840 group_name = k->second.group_name;
842 group_name = X_("nogroup");
845 GroupMap::iterator gm = group_map.find (group_name);
846 if (gm == group_map.end()) {
847 std::vector<KeybindingMap::const_iterator> li;
849 group_map.insert (make_pair (group_name,li));
851 gm->second.push_back (k);
855 for (GroupMap::const_iterator gm = group_map.begin(); gm != group_map.end(); ++gm) {
857 ostr << "<div class=\"group\">\n";
858 ostr << "<div class=\"group-name\">" << gm->first << "</div>\n";
860 for (vector<KeybindingMap::const_iterator>::const_iterator k = gm->second.begin(); k != gm->second.end(); ++k) {
862 if ((*k)->first.name().empty()) {
866 RefPtr<Action> action;
868 if ((*k)->second.action) {
869 action = (*k)->second.action;
872 action = _action_map->find_action ((*k)->second.action_name);
880 string key_name = (*k)->first.native_short_name ();
881 replace_all (key_name, X_("KP_"), X_("Numpad "));
883 string::size_type pos;
885 char const *targets[] = { X_("Separator"), X_("Add"), X_("Subtract"), X_("Decimal"), X_("Divide"),
886 X_("grave"), X_("comma"), X_("period"), X_("asterisk"), X_("backslash"),
887 X_("apostrophe"), X_("minus"), X_("plus"), X_("slash"), X_("semicolon"),
888 X_("colon"), X_("equal"), X_("bracketleft"), X_("bracketright"),
889 X_("ampersand"), X_("numbersign"), X_("parenleft"), X_("parenright"),
890 X_("quoteright"), X_("quoteleft"), X_("exclam"), X_("quotedbl"),
894 char const *replacements[] = { X_("-"), X_("+"), X_("-"), X_("."), X_("/"),
895 X_("`"), X_(","), X_("."), X_("*"), X_("\\"),
896 X_("'"), X_("-"), X_("+"), X_("/"), X_(";"),
897 X_(":"), X_("="), X_("{"), X_("{"),
898 X_("&"), X_("#"), X_("("), X_(")"),
899 X_("`"), X_("'"), X_("!"), X_("\""),
902 for (size_t n = 0; targets[n]; ++n) {
903 if ((pos = key_name.find (targets[n])) != string::npos) {
904 key_name.replace (pos, strlen (targets[n]), replacements[n]);
908 ostr << "<div class=\"key\">" << key_name << "</div>";
909 ostr << "<div class=\"action\">" << action->get_label() << "</div>\n";
911 ostr << "</div>\n\n";
919 Bindings::load (XMLNode const& node)
921 const XMLNodeList& children (node.children());
923 press_bindings.clear ();
924 release_bindings.clear ();
926 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
927 /* each node could be Press or Release */
928 load_operation (**i);
935 Bindings::load_operation (XMLNode const& node)
937 if (node.name() == X_("Press") || node.name() == X_("Release")) {
941 if (node.name() == X_("Press")) {
947 const XMLNodeList& children (node.children());
949 for (XMLNodeList::const_iterator p = children.begin(); p != children.end(); ++p) {
951 XMLProperty const * ap;
952 XMLProperty const * kp;
953 XMLProperty const * bp;
954 XMLProperty const * gp;
955 XMLNode const * child = *p;
957 ap = child->property ("action");
958 kp = child->property ("key");
959 bp = child->property ("button");
960 gp = child->property ("group");
962 if (!ap || (!kp && !bp)) {
968 if (!KeyboardKey::make_key (kp->value(), k)) {
971 add (k, op, ap->value(), gp);
974 if (!MouseButton::make_button (bp->value(), b)) {
977 add (b, op, ap->value(), gp);
984 Bindings::get_all_actions (std::vector<std::string>& paths,
985 std::vector<std::string>& labels,
986 std::vector<std::string>& tooltips,
987 std::vector<std::string>& keys,
988 std::vector<RefPtr<Action> >& actions)
994 /* build a reverse map from actions to bindings */
996 typedef map<Glib::RefPtr<Gtk::Action>,KeyboardKey> ReverseMap;
999 for (KeybindingMap::const_iterator k = press_bindings.begin(); k != press_bindings.end(); ++k) {
1000 rmap.insert (make_pair (k->second.action, k->first));
1003 /* get a list of all actions */
1005 ActionMap::Actions all_actions;
1006 _action_map->get_actions (all_actions);
1008 for (ActionMap::Actions::const_iterator act = all_actions.begin(); act != all_actions.end(); ++act) {
1010 paths.push_back ((*act)->get_accel_path());
1011 labels.push_back ((*act)->get_label());
1012 tooltips.push_back ((*act)->get_tooltip());
1014 ReverseMap::iterator r = rmap.find (*act);
1016 if (r != rmap.end()) {
1017 keys.push_back (r->second.display_label());
1019 keys.push_back (string());
1022 actions.push_back (*act);
1027 Bindings::get_bindings (string const& name, ActionMap& map)
1029 for (list<Bindings*>::iterator b = bindings.begin(); b != bindings.end(); b++) {
1030 if ((*b)->name() == name) {
1031 (*b)->set_action_map (map);
1040 Bindings::associate_all ()
1042 for (list<Bindings*>::iterator b = bindings.begin(); b != bindings.end(); b++) {
1048 Bindings::is_bound (KeyboardKey const& kb, Operation op) const
1050 const KeybindingMap& km = get_keymap(op);
1051 return km.find(kb) != km.end();
1055 Bindings::is_registered (Operation op, std::string const& action_name) const
1057 const KeybindingMap& km = get_keymap(op);
1058 return std::find_if(km.begin(), km.end(), ActionNameRegistered<KeybindingMap::const_iterator::value_type>(action_name)) != km.end();
1061 Bindings::KeybindingMap&
1062 Bindings::get_keymap (Operation op)
1066 return press_bindings;
1069 return release_bindings;
1073 const Bindings::KeybindingMap&
1074 Bindings::get_keymap (Operation op) const
1078 return press_bindings;
1081 return release_bindings;
1085 Bindings::MouseButtonBindingMap&
1086 Bindings::get_mousemap (Operation op)
1090 return button_press_bindings;
1093 return button_release_bindings;
1097 /*==========================================ACTION MAP =========================================*/
1099 ActionMap::ActionMap (string const & name)
1103 action_maps.push_back (this);
1106 ActionMap::~ActionMap ()
1108 action_maps.remove (this);
1112 ActionMap::set_bindings (Bindings* b)
1118 ActionMap::get_actions (ActionMap::Actions& acts)
1120 for (_ActionMap::iterator a = _actions.begin(); a != _actions.end(); ++a) {
1121 acts.push_back (a->second);
1126 ActionMap::find_action (const string& name)
1128 _ActionMap::iterator a = _actions.find (name);
1130 if (a != _actions.end()) {
1134 return RefPtr<Action>();
1138 ActionMap::create_action_group (const string& name)
1140 RefPtr<ActionGroup> g = ActionGroup::create (name);
1142 /* this is one of the places where our own Action management code
1143 has to touch the GTK one, because we want the GtkUIManager to
1144 be able to create widgets (particularly Menus) from our actions.
1146 This is a a necessary step for that to happen.
1150 ActionManager::ui_manager->insert_action_group (g);
1157 ActionMap::register_action (RefPtr<ActionGroup> group, const char* name, const char* label)
1161 RefPtr<Action> act = Action::create (name, label);
1163 fullpath = group->get_name();
1167 if (_actions.insert (_ActionMap::value_type (fullpath, act)).second) {
1172 /* already registered */
1173 return RefPtr<Action> ();
1177 ActionMap::register_action (RefPtr<ActionGroup> group,
1178 const char* name, const char* label, sigc::slot<void> sl)
1182 RefPtr<Action> act = Action::create (name, label);
1184 fullpath = group->get_name();
1188 if (_actions.insert (_ActionMap::value_type (fullpath, act)).second) {
1189 group->add (act, sl);
1193 /* already registered */
1194 return RefPtr<Action>();
1198 ActionMap::register_radio_action (RefPtr<ActionGroup> group,
1199 Gtk::RadioAction::Group& rgroup,
1200 const char* name, const char* label,
1201 sigc::slot<void> sl)
1205 RefPtr<Action> act = RadioAction::create (rgroup, name, label);
1206 RefPtr<RadioAction> ract = RefPtr<RadioAction>::cast_dynamic(act);
1208 fullpath = group->get_name();
1212 if (_actions.insert (_ActionMap::value_type (fullpath, act)).second) {
1213 group->add (act, sl);
1217 /* already registered */
1218 return RefPtr<Action>();
1222 ActionMap::register_radio_action (RefPtr<ActionGroup> group,
1223 Gtk::RadioAction::Group& rgroup,
1224 const char* name, const char* label,
1225 sigc::slot<void,GtkAction*> sl,
1230 RefPtr<Action> act = RadioAction::create (rgroup, name, label);
1231 RefPtr<RadioAction> ract = RefPtr<RadioAction>::cast_dynamic(act);
1232 ract->property_value() = value;
1234 fullpath = group->get_name();
1238 if (_actions.insert (_ActionMap::value_type (fullpath, act)).second) {
1239 group->add (act, sigc::bind (sl, act->gobj()));
1243 /* already registered */
1245 return RefPtr<Action>();
1249 ActionMap::register_toggle_action (RefPtr<ActionGroup> group,
1250 const char* name, const char* label, sigc::slot<void> sl)
1254 fullpath = group->get_name();
1258 RefPtr<Action> act = ToggleAction::create (name, label);
1260 if (_actions.insert (_ActionMap::value_type (fullpath, act)).second) {
1261 group->add (act, sl);
1265 /* already registered */
1266 return RefPtr<Action>();
1270 ActionMap::get_all_actions (std::vector<std::string>& paths,
1271 std::vector<std::string>& labels,
1272 std::vector<std::string>& tooltips,
1273 std::vector<std::string>& keys,
1274 std::vector<RefPtr<Action> >& actions)
1276 for (list<ActionMap*>::const_iterator map = action_maps.begin(); map != action_maps.end(); ++map) {
1278 ActionMap::Actions these_actions;
1279 (*map)->get_actions (these_actions);
1281 for (ActionMap::Actions::const_iterator act = these_actions.begin(); act != these_actions.end(); ++act) {
1283 paths.push_back ((*act)->get_accel_path());
1284 labels.push_back ((*act)->get_label());
1285 tooltips.push_back ((*act)->get_tooltip());
1286 actions.push_back (*act);
1288 Bindings* bindings = (*map)->bindings();
1293 Bindings::Operation op;
1295 key = bindings->get_binding_for_action (*act, op);
1297 if (key == KeyboardKey::null_key()) {
1298 keys.push_back (string());
1300 keys.push_back (key.display_label());
1303 keys.push_back (string());
1307 these_actions.clear ();
1311 std::ostream& operator<<(std::ostream& out, Gtkmm2ext::KeyboardKey const & k) {
1312 char const *gdk_name = gdk_keyval_name (k.key());
1313 return out << "Key " << k.key() << " (" << (gdk_name ? gdk_name : "no-key") << ") state " << hex << k.state() << dec;