From e35e26fa9b418e04095eb53e8f172dacb1c2545e Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Tue, 4 Aug 2015 13:59:32 -0400 Subject: [PATCH] redesign key editor to work with tabbed notebook, one tab per set of bindings --- gtk2_ardour/keyeditor.cc | 234 +++++++++++++++++++++------------------ gtk2_ardour/keyeditor.h | 77 +++++++++---- 2 files changed, 182 insertions(+), 129 deletions(-) diff --git a/gtk2_ardour/keyeditor.cc b/gtk2_ardour/keyeditor.cc index cbbbfafc73..f517217b0d 100644 --- a/gtk2_ardour/keyeditor.cc +++ b/gtk2_ardour/keyeditor.cc @@ -29,6 +29,7 @@ #include #include +#include "gtkmm2ext/bindings.h" #include "gtkmm2ext/utils.h" #include "pbd/strsplit.h" @@ -48,6 +49,7 @@ using namespace Gdk; using namespace PBD; using Gtkmm2ext::Keyboard; +using Gtkmm2ext::Bindings; KeyEditor::KeyEditor () : ArdourWindow (_("Key Bindings")) @@ -57,28 +59,10 @@ KeyEditor::KeyEditor () { last_keyval = 0; - model = TreeStore::create(columns); - - view.set_model (model); - view.append_column (_("Action"), columns.action); - view.append_column (_("Shortcut"), columns.binding); - view.set_headers_visible (true); - view.get_selection()->set_mode (SELECTION_SINGLE); - view.set_reorderable (false); - view.set_size_request (500,300); - view.set_enable_search (false); - view.set_rules_hint (true); - view.set_name (X_("KeyEditorTree")); - - view.get_selection()->signal_changed().connect (sigc::mem_fun (*this, &KeyEditor::action_selected)); - - scroller.add (view); - scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); - - vpacker.set_spacing (6); - vpacker.set_border_width (12); - vpacker.pack_start (scroller); - + notebook.signal_switch_page ().connect (sigc::mem_fun (*this, &KeyEditor::page_change)); + + vpacker.pack_start (notebook, true, true); + if (!ARDOUR::Profile->get_sae()) { Label* hint = manage (new Label (_("Select an action, then press the key(s) to (re)set its shortcut"))); @@ -106,19 +90,114 @@ KeyEditor::KeyEditor () add (vpacker); - view.show (); - scroller.show (); - vpacker.show (); - unbind_button.set_sensitive (false); } +void +KeyEditor::add_tab (string const & name, Bindings& bindings) +{ + Tab* t = new Tab (*this, name, &bindings); + t->populate (); + t->show_all (); + notebook.append_page (*t, name); +} + void KeyEditor::unbind () { + current_tab()->unbind (); +} + +void +KeyEditor::page_change (GtkNotebookPage*, guint) +{ + current_tab()->view.get_selection()->unselect_all (); + unbind_button.set_sensitive (false); +} + +bool +KeyEditor::on_key_press_event (GdkEventKey* ev) +{ + if (!ev->is_modifier) { + last_keyval = ev->keyval; + } + return ArdourWindow::on_key_press_event (ev); +} + +bool +KeyEditor::on_key_release_event (GdkEventKey* ev) +{ + if (ARDOUR::Profile->get_sae() || last_keyval == 0) { + return false; + } + + current_tab()->bind (ev, last_keyval); + + last_keyval = 0; + return true; +} + +KeyEditor::Tab::Tab (KeyEditor& ke, string const & str, Bindings* b) + : owner (ke) + , name (str) + , bindings (b) +{ + model = TreeStore::create(columns); + + view.set_model (model); + view.append_column (_("Action"), columns.action); + view.append_column (_("Shortcut"), columns.binding); + view.set_headers_visible (true); + view.get_selection()->set_mode (SELECTION_SINGLE); + view.set_reorderable (false); + view.set_size_request (500,300); + view.set_enable_search (false); + view.set_rules_hint (true); + view.set_name (X_("KeyEditorTree")); + + view.get_selection()->signal_changed().connect (sigc::mem_fun (*this, &Tab::action_selected)); + + scroller.add (view); + scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); + + set_spacing (6); + set_border_width (12); + pack_start (scroller); +} + +void +KeyEditor::Tab::action_selected () +{ + if (view.get_selection()->count_selected_rows() == 0) { + return; + } + TreeModel::iterator i = view.get_selection()->get_selected(); - unbind_button.set_sensitive (false); + owner.unbind_button.set_sensitive (false); + + if (i != model->children().end()) { + + string path = (*i)[columns.path]; + + if (!(*i)[columns.bindable]) { + return; + } + + string binding = (*i)[columns.binding]; + + if (!binding.empty()) { + owner.unbind_button.set_sensitive (true); + } + } +} + +void +KeyEditor::Tab::unbind () +{ + TreeModel::iterator i = view.get_selection()->get_selected(); + + owner.unbind_button.set_sensitive (false); if (i != model->children().end()) { string path = (*i)[columns.path]; @@ -138,106 +217,48 @@ KeyEditor::unbind () } void -KeyEditor::on_show () +KeyEditor::Tab::bind (GdkEventKey* release_event, guint pressed_key) { - populate (); - view.get_selection()->unselect_all (); - ArdourWindow::on_show (); -} - -void -KeyEditor::on_unmap () -{ - ArdourWindow::on_unmap (); -} - -void -KeyEditor::action_selected () -{ - if (view.get_selection()->count_selected_rows() == 0) { - return; - } - TreeModel::iterator i = view.get_selection()->get_selected(); - unbind_button.set_sensitive (false); - if (i != model->children().end()) { - string path = (*i)[columns.path]; if (!(*i)[columns.bindable]) { return; } - string binding = (*i)[columns.binding]; + GdkModifierType mod = (GdkModifierType)(Keyboard::RelevantModifierKeyMask & release_event->state); - if (!binding.empty()) { - unbind_button.set_sensitive (true); - } - } -} - -bool -KeyEditor::on_key_press_event (GdkEventKey* ev) -{ - if (!ev->is_modifier) { - last_keyval = ev->keyval; - } - return ArdourWindow::on_key_press_event (ev); -} - -bool -KeyEditor::on_key_release_event (GdkEventKey* ev) -{ - if (ARDOUR::Profile->get_sae() || last_keyval == 0) { - return false; - } - - TreeModel::iterator i = view.get_selection()->get_selected(); - - if (i != model->children().end()) { - string path = (*i)[columns.path]; - - if (!(*i)[columns.bindable]) { - goto out; - } - - GdkModifierType mod = (GdkModifierType)(Keyboard::RelevantModifierKeyMask & ev->state); - - Gtkmm2ext::possibly_translate_keyval_to_make_legal_accelerator (ev->keyval); + Gtkmm2ext::possibly_translate_keyval_to_make_legal_accelerator (release_event->keyval); Gtkmm2ext::possibly_translate_mod_to_make_legal_accelerator (mod); bool result = AccelMap::change_entry (path, - last_keyval, + pressed_key, Gdk::ModifierType(mod), true); if (result) { AccelKey key; (*i)[columns.binding] = ActionManager::get_key_representation (path, key); - unbind_button.set_sensitive (true); + owner.unbind_button.set_sensitive (true); } } - - out: - last_keyval = 0; - return true; } void -KeyEditor::populate () +KeyEditor::Tab::populate () { vector paths; vector labels; vector tooltips; vector keys; - vector bindings; + vector binds; typedef std::map NodeMap; NodeMap nodes; NodeMap::iterator r; - ActionManager::get_all_actions (labels, paths, tooltips, keys, bindings); + bindings->get_all_actions (labels, paths, tooltips, keys, binds); vector::iterator k; vector::iterator p; @@ -260,16 +281,11 @@ KeyEditor::populate () } //kinda kludgy way to avoid displaying menu items as mappable - if ( parts[1] == _("Main_menu") ) - continue; - if ( parts[1] == _("redirectmenu") ) - continue; - if ( parts[1] == _("Editor_menus") ) - continue; - if ( parts[1] == _("RegionList") ) - continue; - if ( parts[1] == _("ProcessorMenu") ) + if ((parts[1].find ("Menu") == parts[1].length() - 4) || + (parts[1].find ("menu") == parts[1].length() - 4) || + (parts[1] == _("RegionList"))) { continue; + } if ((r = nodes.find (parts[1])) == nodes.end()) { @@ -313,7 +329,15 @@ void KeyEditor::reset () { Keyboard::the_keyboard().reset_bindings (); - populate (); - view.get_selection()->unselect_all (); - populate (); + + for (Tabs::iterator t = tabs.begin(); t != tabs.end(); ++t) { + (*t)->view.get_selection()->unselect_all (); + (*t)->populate (); + } +} + +KeyEditor::Tab* +KeyEditor::current_tab () +{ + return dynamic_cast (notebook.get_nth_page (notebook.get_current_page())); } diff --git a/gtk2_ardour/keyeditor.h b/gtk2_ardour/keyeditor.h index 14ae2b980c..472b5063f7 100644 --- a/gtk2_ardour/keyeditor.h +++ b/gtk2_ardour/keyeditor.h @@ -23,56 +23,85 @@ #include #include +#include +#include #include #include -#include #include "ardour_window.h" +namespace Gtkmm2ext { + class Bindings; +} + class KeyEditor : public ArdourWindow { public: KeyEditor (); + void add_tab (std::string const &name, Gtkmm2ext::Bindings&); + protected: - void on_show (); - void on_unmap (); bool on_key_press_event (GdkEventKey*); bool on_key_release_event (GdkEventKey*); private: - struct KeyEditorColumns : public Gtk::TreeModel::ColumnRecord { - KeyEditorColumns () { - add (action); - add (binding); - add (path); - add (bindable); - } - Gtk::TreeModelColumn action; - Gtk::TreeModelColumn binding; - Gtk::TreeModelColumn path; - Gtk::TreeModelColumn bindable; + class Tab : public Gtk::VBox + { + public: + Tab (KeyEditor&, std::string const &name, Gtkmm2ext::Bindings*); + + void populate (); + void unbind (); + void bind (GdkEventKey* release_event, guint pressed_key); + void action_selected (); + + struct KeyEditorColumns : public Gtk::TreeModel::ColumnRecord { + KeyEditorColumns () { + add (action); + add (binding); + add (path); + add (bindable); + } + Gtk::TreeModelColumn action; + Gtk::TreeModelColumn binding; + Gtk::TreeModelColumn path; + Gtk::TreeModelColumn bindable; + }; + + Gtk::VBox vpacker; + /* give KeyEditor full access to these. This is just a helper + class with no special semantics + */ + + KeyEditor& owner; + std::string name; + Gtkmm2ext::Bindings* bindings; + Gtk::ScrolledWindow scroller; + Gtk::TreeView view; + Glib::RefPtr model; + KeyEditorColumns columns; }; - Gtk::VBox vpacker; - Gtk::ScrolledWindow scroller; - Gtk::TreeView view; - Glib::RefPtr model; - KeyEditorColumns columns; + friend class Tab; + + Gtk::VBox vpacker; + Gtk::Notebook notebook; Gtk::Button unbind_button; Gtk::HButtonBox unbind_box; Gtk::HBox reset_box; Gtk::Button reset_button; Gtk::Label reset_label; - - void unbind (); - guint last_keyval; - void action_selected (); - void populate (); + typedef std::vector Tabs; + Tabs tabs; + Tab* current_tab(); + + void unbind (); void reset (); + void page_change (GtkNotebookPage*, guint); }; #endif /* __ardour_gtk_key_editor_h__ */