redesign key editor to work with tabbed notebook, one tab per set of bindings
This commit is contained in:
parent
0f748492b3
commit
e35e26fa9b
|
@ -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()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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__ */
|
||||||
|
|
Loading…
Reference in New Issue
Block a user