13
0

redesign key editor to work with tabbed notebook, one tab per set of bindings

This commit is contained in:
Paul Davis 2015-08-04 13:59:32 -04:00
parent 0f748492b3
commit e35e26fa9b
2 changed files with 182 additions and 129 deletions

View File

@ -29,6 +29,7 @@
#include <gtkmm/accelmap.h> #include <gtkmm/accelmap.h>
#include <gtkmm/uimanager.h> #include <gtkmm/uimanager.h>
#include "gtkmm2ext/bindings.h"
#include "gtkmm2ext/utils.h" #include "gtkmm2ext/utils.h"
#include "pbd/strsplit.h" #include "pbd/strsplit.h"
@ -48,6 +49,7 @@ using namespace Gdk;
using namespace PBD; using namespace PBD;
using Gtkmm2ext::Keyboard; using Gtkmm2ext::Keyboard;
using Gtkmm2ext::Bindings;
KeyEditor::KeyEditor () KeyEditor::KeyEditor ()
: ArdourWindow (_("Key Bindings")) : ArdourWindow (_("Key Bindings"))
@ -57,28 +59,10 @@ KeyEditor::KeyEditor ()
{ {
last_keyval = 0; last_keyval = 0;
model = TreeStore::create(columns); notebook.signal_switch_page ().connect (sigc::mem_fun (*this, &KeyEditor::page_change));
view.set_model (model); vpacker.pack_start (notebook, true, true);
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);
if (!ARDOUR::Profile->get_sae()) { if (!ARDOUR::Profile->get_sae()) {
Label* hint = manage (new Label (_("Select an action, then press the key(s) to (re)set its shortcut"))); 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); add (vpacker);
view.show ();
scroller.show ();
vpacker.show ();
unbind_button.set_sensitive (false); 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 void
KeyEditor::unbind () 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(); 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()) { if (i != model->children().end()) {
string path = (*i)[columns.path]; string path = (*i)[columns.path];
@ -138,106 +217,48 @@ KeyEditor::unbind ()
} }
void 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(); TreeModel::iterator i = view.get_selection()->get_selected();
unbind_button.set_sensitive (false);
if (i != model->children().end()) { if (i != model->children().end()) {
string path = (*i)[columns.path]; string path = (*i)[columns.path];
if (!(*i)[columns.bindable]) { if (!(*i)[columns.bindable]) {
return; return;
} }
string binding = (*i)[columns.binding]; GdkModifierType mod = (GdkModifierType)(Keyboard::RelevantModifierKeyMask & release_event->state);
if (!binding.empty()) { Gtkmm2ext::possibly_translate_keyval_to_make_legal_accelerator (release_event->keyval);
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_mod_to_make_legal_accelerator (mod); Gtkmm2ext::possibly_translate_mod_to_make_legal_accelerator (mod);
bool result = AccelMap::change_entry (path, bool result = AccelMap::change_entry (path,
last_keyval, pressed_key,
Gdk::ModifierType(mod), Gdk::ModifierType(mod),
true); true);
if (result) { if (result) {
AccelKey key; AccelKey key;
(*i)[columns.binding] = ActionManager::get_key_representation (path, 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 void
KeyEditor::populate () KeyEditor::Tab::populate ()
{ {
vector<string> paths; vector<string> paths;
vector<string> labels; vector<string> labels;
vector<string> tooltips; vector<string> tooltips;
vector<string> keys; vector<string> keys;
vector<AccelKey> bindings; vector<Gtkmm2ext::KeyboardKey> binds;
typedef std::map<string,TreeIter> NodeMap; typedef std::map<string,TreeIter> NodeMap;
NodeMap nodes; NodeMap nodes;
NodeMap::iterator r; NodeMap::iterator r;
ActionManager::get_all_actions (labels, paths, tooltips, keys, bindings); bindings->get_all_actions (labels, paths, tooltips, keys, binds);
vector<string>::iterator k; vector<string>::iterator k;
vector<string>::iterator p; vector<string>::iterator p;
@ -260,16 +281,11 @@ KeyEditor::populate ()
} }
//kinda kludgy way to avoid displaying menu items as mappable //kinda kludgy way to avoid displaying menu items as mappable
if ( parts[1] == _("Main_menu") ) if ((parts[1].find ("Menu") == parts[1].length() - 4) ||
continue; (parts[1].find ("menu") == parts[1].length() - 4) ||
if ( parts[1] == _("redirectmenu") ) (parts[1] == _("RegionList"))) {
continue;
if ( parts[1] == _("Editor_menus") )
continue;
if ( parts[1] == _("RegionList") )
continue;
if ( parts[1] == _("ProcessorMenu") )
continue; continue;
}
if ((r = nodes.find (parts[1])) == nodes.end()) { if ((r = nodes.find (parts[1])) == nodes.end()) {
@ -313,7 +329,15 @@ void
KeyEditor::reset () KeyEditor::reset ()
{ {
Keyboard::the_keyboard().reset_bindings (); Keyboard::the_keyboard().reset_bindings ();
populate ();
view.get_selection()->unselect_all (); for (Tabs::iterator t = tabs.begin(); t != tabs.end(); ++t) {
populate (); (*t)->view.get_selection()->unselect_all ();
(*t)->populate ();
}
}
KeyEditor::Tab*
KeyEditor::current_tab ()
{
return dynamic_cast<Tab*> (notebook.get_nth_page (notebook.get_current_page()));
} }

View File

@ -23,56 +23,85 @@
#include <string> #include <string>
#include <gtkmm/buttonbox.h> #include <gtkmm/buttonbox.h>
#include <gtkmm/notebook.h>
#include <gtkmm/scrolledwindow.h>
#include <gtkmm/treeview.h> #include <gtkmm/treeview.h>
#include <gtkmm/treestore.h> #include <gtkmm/treestore.h>
#include <gtkmm/scrolledwindow.h>
#include "ardour_window.h" #include "ardour_window.h"
namespace Gtkmm2ext {
class Bindings;
}
class KeyEditor : public ArdourWindow class KeyEditor : public ArdourWindow
{ {
public: public:
KeyEditor (); KeyEditor ();
void add_tab (std::string const &name, Gtkmm2ext::Bindings&);
protected: protected:
void on_show ();
void on_unmap ();
bool on_key_press_event (GdkEventKey*); bool on_key_press_event (GdkEventKey*);
bool on_key_release_event (GdkEventKey*); bool on_key_release_event (GdkEventKey*);
private: private:
struct KeyEditorColumns : public Gtk::TreeModel::ColumnRecord { class Tab : public Gtk::VBox
KeyEditorColumns () { {
add (action); public:
add (binding); Tab (KeyEditor&, std::string const &name, Gtkmm2ext::Bindings*);
add (path);
add (bindable); void populate ();
} void unbind ();
Gtk::TreeModelColumn<std::string> action; void bind (GdkEventKey* release_event, guint pressed_key);
Gtk::TreeModelColumn<std::string> binding; void action_selected ();
Gtk::TreeModelColumn<std::string> path;
Gtk::TreeModelColumn<bool> bindable; struct KeyEditorColumns : public Gtk::TreeModel::ColumnRecord {
KeyEditorColumns () {
add (action);
add (binding);
add (path);
add (bindable);
}
Gtk::TreeModelColumn<std::string> action;
Gtk::TreeModelColumn<std::string> binding;
Gtk::TreeModelColumn<std::string> path;
Gtk::TreeModelColumn<bool> 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<Gtk::TreeStore> model;
KeyEditorColumns columns;
}; };
Gtk::VBox vpacker; friend class Tab;
Gtk::ScrolledWindow scroller;
Gtk::TreeView view; Gtk::VBox vpacker;
Glib::RefPtr<Gtk::TreeStore> model; Gtk::Notebook notebook;
KeyEditorColumns columns;
Gtk::Button unbind_button; Gtk::Button unbind_button;
Gtk::HButtonBox unbind_box; Gtk::HButtonBox unbind_box;
Gtk::HBox reset_box; Gtk::HBox reset_box;
Gtk::Button reset_button; Gtk::Button reset_button;
Gtk::Label reset_label; Gtk::Label reset_label;
void unbind ();
guint last_keyval; guint last_keyval;
void action_selected (); typedef std::vector<Tab*> Tabs;
void populate ();
Tabs tabs;
Tab* current_tab();
void unbind ();
void reset (); void reset ();
void page_change (GtkNotebookPage*, guint);
}; };
#endif /* __ardour_gtk_key_editor_h__ */ #endif /* __ardour_gtk_key_editor_h__ */