summaryrefslogtreecommitdiff
path: root/libs/gtkmm2ext
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2010-08-06 18:44:55 +0000
committerPaul Davis <paul@linuxaudiosystems.com>2010-08-06 18:44:55 +0000
commite2965cd138b31e27dc027bb674585ae93ffdc055 (patch)
treea52397e200b8e952fd3f8db48f6a995a91a8f549 /libs/gtkmm2ext
parent93603ab24ffd43f49956119cd0d94722d4772cda (diff)
new files for new per-window/action-driven key binding mechanism
git-svn-id: svn://localhost/ardour2/branches/3.0@7553 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs/gtkmm2ext')
-rw-r--r--libs/gtkmm2ext/bindings.cc349
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/bindings.h93
2 files changed, 442 insertions, 0 deletions
diff --git a/libs/gtkmm2ext/bindings.cc b/libs/gtkmm2ext/bindings.cc
new file mode 100644
index 0000000000..1e8ef03fa0
--- /dev/null
+++ b/libs/gtkmm2ext/bindings.cc
@@ -0,0 +1,349 @@
+#include <iostream>
+#include "pbd/xml++.h"
+#include "gtkmm2ext/bindings.h"
+#include "gtkmm2ext/keyboard.h"
+
+#include "i18n.h"
+
+using namespace std;
+using namespace Glib;
+using namespace Gtk;
+using namespace Gtkmm2ext;
+
+string
+KeyboardKey::name () const
+{
+ int s = state();
+
+ string str;
+
+ if (s & Keyboard::PrimaryModifier) {
+ str += "Primary";
+ }
+ if (s & Keyboard::SecondaryModifier) {
+ if (!str.empty()) {
+ str += '-';
+ }
+ str += "Secondary";
+ }
+ if (s & Keyboard::TertiaryModifier) {
+ if (!str.empty()) {
+ str += '-';
+ }
+ str += "Tertiary";
+ }
+ if (s & Keyboard::Level4Modifier) {
+ if (!str.empty()) {
+ str += '-';
+ }
+ str += "Level4";
+ }
+
+ if (!str.empty()) {
+ str += '-';
+ }
+
+ str += gdk_keyval_name (key());
+
+ return str;
+}
+
+bool
+KeyboardKey::make_key (const string& str, KeyboardKey& k)
+{
+ int s = 0;
+
+ if (str.find ("Primary") != string::npos) {
+ s |= Keyboard::PrimaryModifier;
+ }
+
+ if (str.find ("Secondary") != string::npos) {
+ s |= Keyboard::SecondaryModifier;
+ }
+
+ if (str.find ("Tertiary") != string::npos) {
+ s |= Keyboard::TertiaryModifier;
+ }
+
+ if (str.find ("Level4") != string::npos) {
+ s |= Keyboard::Level4Modifier;
+ }
+
+ string::size_type lastmod = str.find_last_of ('-');
+ guint keyval;
+
+ if (lastmod == string::npos) {
+ keyval = gdk_keyval_from_name (str.c_str());
+ } else {
+ keyval = gdk_keyval_from_name (str.substr (lastmod+1).c_str());
+ }
+
+ if (keyval == GDK_VoidSymbol) {
+ return false;
+ }
+
+ k = KeyboardKey (s, keyval);
+ return true;
+}
+
+Bindings::Bindings ()
+ : action_map (0)
+{
+}
+
+Bindings::~Bindings()
+{
+}
+
+void
+Bindings::set_action_map (ActionMap& am)
+{
+ action_map = &am;
+ press_bindings.clear ();
+ release_bindings.clear ();
+}
+
+bool
+Bindings::activate (KeyboardKey kb, KeyboardKey::Operation op)
+{
+ KeybindingMap* kbm;
+
+ switch (op) {
+ case KeyboardKey::Press:
+ kbm = &press_bindings;
+ break;
+ case KeyboardKey::Release:
+ kbm = &release_bindings;
+ break;
+ }
+
+ KeybindingMap::iterator k = kbm->find (kb);
+
+ if (k == kbm->end()) {
+ /* no entry for this key in the state map */
+ return false;
+ }
+
+ /* lets do it ... */
+
+ cerr << "Firing up " << k->second->get_name() << endl;
+ k->second->activate ();
+ return true;
+}
+
+void
+Bindings::add (KeyboardKey kb, KeyboardKey::Operation op, RefPtr<Action> what)
+{
+ KeybindingMap* kbm;
+
+ switch (op) {
+ case KeyboardKey::Press:
+ kbm = &press_bindings;
+ break;
+ case KeyboardKey::Release:
+ kbm = &release_bindings;
+ break;
+ }
+
+ KeybindingMap::iterator k = kbm->find (kb);
+
+ if (k == kbm->end()) {
+ pair<KeyboardKey,RefPtr<Action> > newpair (kb, what);
+ kbm->insert (newpair);
+ } else {
+ k->second = what;
+ }
+}
+
+void
+Bindings::remove (KeyboardKey kb, KeyboardKey::Operation op)
+{
+ KeybindingMap* kbm;
+
+ switch (op) {
+ case KeyboardKey::Press:
+ kbm = &press_bindings;
+ break;
+ case KeyboardKey::Release:
+ kbm = &release_bindings;
+ break;
+ }
+
+ KeybindingMap::iterator k = kbm->find (kb);
+
+ if (k != kbm->end()) {
+ kbm->erase (k);
+ }
+}
+
+bool
+Bindings::save (const string& path)
+{
+ XMLTree tree;
+ XMLNode* root = new XMLNode (X_("Bindings"));
+ tree.set_root (root);
+
+ XMLNode* presses = new XMLNode (X_("Press"));
+ root->add_child_nocopy (*presses);
+
+ for (KeybindingMap::iterator k = press_bindings.begin(); k != press_bindings.end(); ++k) {
+ XMLNode* child;
+ child = new XMLNode (X_("Binding"));
+ child->add_property (X_("key"), k->first.name());
+ child->add_property (X_("action"), k->second->get_name());
+ presses->add_child_nocopy (*child);
+ }
+
+ if (!tree.write (path)) {
+ ::unlink (path.c_str());
+ return false;
+ }
+
+ return true;
+}
+
+bool
+Bindings::load (const string& path)
+{
+ XMLTree tree;
+
+ if (!action_map) {
+ cerr << "No action map to load bindings with!\n";
+ return false;
+ }
+
+ if (!tree.read (path)) {
+ cerr << "Cannot load XML file @ " << path << endl;
+ return false;
+ }
+
+ press_bindings.clear ();
+ release_bindings.clear ();
+
+ XMLNode& root (*tree.root());
+ const XMLNodeList& children (root.children());
+
+ cerr << "check the " << children.size() << " children\n";
+
+ for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
+
+ cerr << "child name: " << (*i)->name() << endl;
+
+ if ((*i)->name() == X_("Press") || (*i)->name() == X_("Release")) {
+
+ KeyboardKey::Operation op;
+
+ if ((*i)->name() == X_("Press")) {
+ op = KeyboardKey::Press;
+ } else {
+ op = KeyboardKey::Release;
+ }
+
+ const XMLNodeList& gchildren ((*i)->children());
+
+ for (XMLNodeList::const_iterator p = gchildren.begin(); p != gchildren.end(); ++p) {
+
+ XMLProperty* ap;
+ XMLProperty* kp;
+
+ ap = (*p)->property ("action");
+ kp = (*p)->property ("key");
+
+ if (!ap || !kp) {
+ continue;
+ }
+
+ cerr << "key = " << kp->value () << " action = " << ap->value() << endl;
+
+ RefPtr<Action> act = action_map->find_action (ap->value());
+
+ if (!act) {
+ continue;
+ }
+
+ KeyboardKey k;
+
+ if (!KeyboardKey::make_key (kp->value(), k)) {
+ continue;
+ }
+
+ cerr << "binding " << act->get_name() << " to " << k.name() << endl;
+
+ add (k, op, act);
+ }
+ }
+ }
+
+ return true;
+}
+
+RefPtr<Action>
+ActionMap::find_action (const string& name)
+{
+ _ActionMap::iterator a = actions.find (name);
+
+ if (a != actions.end()) {
+ return a->second;
+ }
+
+ return RefPtr<Action>();
+}
+
+RefPtr<Action>
+ActionMap::register_action (const char* path,
+ const char* name, const char* label, sigc::slot<void> sl)
+{
+ string fullpath;
+
+ RefPtr<Action> act = Action::create (name, label);
+
+ act->signal_activate().connect (sl);
+
+ fullpath = path;
+ fullpath += '/';
+ fullpath += name;
+
+ actions.insert (_ActionMap::value_type (fullpath, act));
+ cerr << "Registered action @ " << fullpath << endl;
+ return act;
+}
+
+RefPtr<Action>
+ActionMap::register_radio_action (const char* path, Gtk::RadioAction::Group& rgroup,
+ const char* name, const char* label, sigc::slot<void> sl)
+{
+ string fullpath;
+
+ RefPtr<Action> act = RadioAction::create (rgroup, name, label);
+
+ act->signal_activate().connect (sl);
+
+ fullpath = path;
+ fullpath += '/';
+ fullpath += name;
+
+ actions.insert (_ActionMap::value_type (fullpath, act));
+ cerr << "Registered action @ " << fullpath << endl;
+
+ return act;
+}
+
+RefPtr<Action>
+ActionMap::register_toggle_action (const char*path,
+ const char* name, const char* label, sigc::slot<void> sl)
+{
+ string fullpath;
+
+ RefPtr<Action> act = ToggleAction::create (name, label);
+
+ act->signal_activate().connect (sl);
+
+ fullpath = path;
+ fullpath += '/';
+ fullpath += name;
+
+ actions.insert (_ActionMap::value_type (fullpath, act));
+ cerr << "Registered action @ " << fullpath << endl;
+
+ return act;
+}
diff --git a/libs/gtkmm2ext/gtkmm2ext/bindings.h b/libs/gtkmm2ext/gtkmm2ext/bindings.h
new file mode 100644
index 0000000000..0ece4a7404
--- /dev/null
+++ b/libs/gtkmm2ext/gtkmm2ext/bindings.h
@@ -0,0 +1,93 @@
+#ifndef __libgtkmm2ext_bindings_h__
+#define __libgtkmm2ext_bindings_h__
+
+#include <map>
+#include <stdint.h>
+#include <gdk/gdkkeysyms.h>
+#include <gtkmm/action.h>
+#include <gtkmm/action.h>
+#include <gtkmm/radioaction.h>
+#include <gtkmm/toggleaction.h>
+
+namespace Gtkmm2ext {
+
+class KeyboardKey
+{
+ public:
+ enum Operation {
+ Press,
+ Release
+ };
+
+ KeyboardKey () {
+ _val = GDK_VoidSymbol;
+ }
+
+ KeyboardKey (int state, int keycode) {
+ _val = state;
+ _val <<= 32;
+ _val |= keycode;
+ };
+
+ int state() const { return _val >> 32; }
+ int key() const { return _val & 0xffff; }
+
+ bool operator<(const KeyboardKey& other) const {
+ return _val < other._val;
+ }
+
+ bool operator==(const KeyboardKey& other) const {
+ return _val == other._val;
+ }
+
+ std::string name() const;
+ static bool make_key (const std::string&, KeyboardKey&);
+
+ private:
+ uint64_t _val;
+};
+
+class ActionMap {
+ public:
+ ActionMap() {}
+ ~ActionMap() {}
+
+ Glib::RefPtr<Gtk::Action> register_action (const char* path,
+ const char* name, const char* label, sigc::slot<void> sl);
+ Glib::RefPtr<Gtk::Action> register_radio_action (const char* path, Gtk::RadioAction::Group&,
+ const char* name, const char* label, sigc::slot<void> sl);
+ Glib::RefPtr<Gtk::Action> register_toggle_action (const char*path,
+ const char* name, const char* label, sigc::slot<void> sl);
+
+ Glib::RefPtr<Gtk::Action> find_action (const std::string& name);
+
+ private:
+ typedef std::map<std::string, Glib::RefPtr<Gtk::Action> > _ActionMap;
+ _ActionMap actions;
+};
+
+class Bindings {
+ public:
+ Bindings();
+ ~Bindings ();
+
+ void add (KeyboardKey, KeyboardKey::Operation, Glib::RefPtr<Gtk::Action>);
+ void remove (KeyboardKey, KeyboardKey::Operation);
+ bool activate (KeyboardKey, KeyboardKey::Operation);
+
+ bool load (const std::string& path);
+ bool save (const std::string& path);
+
+ void set_action_map (ActionMap&);
+
+ private:
+ typedef std::map<KeyboardKey,Glib::RefPtr<Gtk::Action> > KeybindingMap;
+ KeybindingMap press_bindings;
+ KeybindingMap release_bindings;
+
+ ActionMap* action_map;
+};
+
+} // namespace
+
+#endif /* __libgtkmm2ext_bindings_h__ */