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/uimanager.h>
#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<string> paths;
vector<string> labels;
vector<string> tooltips;
vector<string> keys;
vector<AccelKey> bindings;
vector<Gtkmm2ext::KeyboardKey> binds;
typedef std::map<string,TreeIter> 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<string>::iterator k;
vector<string>::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<Tab*> (notebook.get_nth_page (notebook.get_current_page()));
}

View File

@ -23,56 +23,85 @@
#include <string>
#include <gtkmm/buttonbox.h>
#include <gtkmm/notebook.h>
#include <gtkmm/scrolledwindow.h>
#include <gtkmm/treeview.h>
#include <gtkmm/treestore.h>
#include <gtkmm/scrolledwindow.h>
#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<std::string> action;
Gtk::TreeModelColumn<std::string> binding;
Gtk::TreeModelColumn<std::string> path;
Gtk::TreeModelColumn<bool> 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<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;
Gtk::ScrolledWindow scroller;
Gtk::TreeView view;
Glib::RefPtr<Gtk::TreeStore> 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<Tab*> Tabs;
Tabs tabs;
Tab* current_tab();
void unbind ();
void reset ();
void page_change (GtkNotebookPage*, guint);
};
#endif /* __ardour_gtk_key_editor_h__ */