From 2a45807b4db3cf6fa1f11633b8dc4e83ab8622c5 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sun, 13 Jan 2013 18:40:21 +0000 Subject: Add two connect modes for fast chaining and fanning. git-svn-id: http://svn.drobilla.net/lad/trunk/machina@4962 a436a847-0d15-0410-975c-d299462d15a1 --- src/gui/MachinaCanvas.cpp | 52 ++++++++++++++++++++++++---------------- src/gui/MachinaCanvas.hpp | 8 ++++--- src/gui/MachinaGUI.cpp | 30 ++++++++++++++++++++--- src/gui/MachinaGUI.hpp | 14 ++++++++--- src/gui/NodeView.cpp | 2 +- src/gui/machina.ui | 61 +++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 136 insertions(+), 31 deletions(-) diff --git a/src/gui/MachinaCanvas.cpp b/src/gui/MachinaCanvas.cpp index 1a95b1c..15aaf57 100644 --- a/src/gui/MachinaCanvas.cpp +++ b/src/gui/MachinaCanvas.cpp @@ -38,45 +38,55 @@ namespace gui { MachinaCanvas::MachinaCanvas(MachinaGUI* app, int width, int height) : Canvas(width, height) , _app(app) - , _last_clicked(NULL) + , _connect_node(NULL) + , _did_connect(false) { widget().grab_focus(); - signal_event.connect( - sigc::mem_fun(this, &MachinaCanvas::on_event)); + signal_event.connect(sigc::mem_fun(this, &MachinaCanvas::on_event)); +} + +void +MachinaCanvas::connect_nodes(GanvNode* node, void* data) +{ + NodeView* view = dynamic_cast(Glib::wrap(node)); + if (!view) { + std::cerr << "error: Connect of node with no view" << std::endl; + return; + } + MachinaCanvas* canvas = (MachinaCanvas*)data; + if (canvas->get_edge(view, canvas->_connect_node)) { + canvas->action_disconnect(view, canvas->_connect_node); + canvas->_did_connect = true; + } else if (!canvas->get_edge(canvas->_connect_node, view)) { + canvas->action_connect(view, canvas->_connect_node); + canvas->_did_connect = true; + } } bool MachinaCanvas::node_clicked(NodeView* node, GdkEventButton* event) { - if (event->state & GDK_CONTROL_MASK) { + if (event->state & (GDK_CONTROL_MASK|GDK_SHIFT_MASK)) { return false; - } - if (event->button == 2) { + } else if (event->button == 2) { // Middle click: learn _app->controller()->learn(_app->maid(), node->node()->id()); return false; } else if (event->button == 1) { // Left click: connect/disconnect - if (_last_clicked) { - if (node != _last_clicked) { - if (get_edge(_last_clicked, node)) { - action_disconnect(_last_clicked, node); - } else { - action_connect(_last_clicked, node); - } - } - - _last_clicked->set_default_colors(); - _last_clicked = NULL; - + _connect_node = node; + for_each_selected_node(connect_nodes, this); + const bool handled = _did_connect; + _connect_node = NULL; + _did_connect = false; + if (_app->chain_mode()) { + return false; // Cause Ganv to select as usual } else { - _last_clicked = node; + return handled; // If we did something, stop event here } - - return true; } return false; diff --git a/src/gui/MachinaCanvas.hpp b/src/gui/MachinaCanvas.hpp index 155bdfc..f32e6cb 100644 --- a/src/gui/MachinaCanvas.hpp +++ b/src/gui/MachinaCanvas.hpp @@ -33,8 +33,7 @@ namespace gui { class MachinaGUI; class NodeView; -class MachinaCanvas - : public Canvas +class MachinaCanvas : public Canvas { public: MachinaCanvas(MachinaGUI* app, int width, int height); @@ -54,8 +53,11 @@ private: void action_connect(NodeView* tail, NodeView* head); void action_disconnect(NodeView* tail, NodeView* head); + static void connect_nodes(GanvNode* node, void* data); + MachinaGUI* _app; - NodeView* _last_clicked; + NodeView* _connect_node; + bool _did_connect; }; } // namespace machina diff --git a/src/gui/MachinaGUI.cpp b/src/gui/MachinaGUI.cpp index e283530..cc22cf8 100644 --- a/src/gui/MachinaGUI.cpp +++ b/src/gui/MachinaGUI.cpp @@ -41,13 +41,14 @@ namespace machina { namespace gui { MachinaGUI::MachinaGUI(SPtr engine) - : _refresh(false) - , _evolve(false) - , _unit(TimeUnit::BEATS, 19200) + : _unit(TimeUnit::BEATS, 19200) , _engine(engine) , _client_model(new machina::client::ClientModel()) , _controller(new machina::Controller(_engine, *_client_model.get())) , _maid(new Raul::Maid()) + , _refresh(false) + , _evolve(false) + , _chain_mode(true) { _canvas = SPtr(new MachinaCanvas(this, 1600*2, 1200*2)); @@ -80,6 +81,8 @@ MachinaGUI::MachinaGUI(SPtr engine) xml->get_widget("zoom_normal_but", _zoom_normal_button); xml->get_widget("zoom_full_but", _zoom_full_button); xml->get_widget("arrange_but", _arrange_button); + xml->get_widget("chain_but", _chain_button); + xml->get_widget("fan_but", _fan_button); xml->get_widget("load_target_but", _load_target_button); xml->get_widget("evolve_toolbar", _evolve_toolbar); xml->get_widget("evolve_but", _evolve_button); @@ -115,6 +118,11 @@ MachinaGUI::MachinaGUI(SPtr engine) _arrange_button->signal_clicked().connect( sigc::mem_fun(this, &MachinaGUI::arrange)); + _chain_button->signal_toggled().connect( + sigc::mem_fun(this, &MachinaGUI::chain_toggled)); + _fan_button->signal_toggled().connect( + sigc::mem_fun(this, &MachinaGUI::fan_toggled)); + _menu_file_open->signal_activate().connect( sigc::mem_fun(this, &MachinaGUI::menu_file_open)); _menu_file_save->signal_activate().connect( @@ -686,6 +694,22 @@ MachinaGUI::record_toggled() } } +void +MachinaGUI::chain_toggled() +{ + if (_chain_button->get_active()) { + _chain_mode = true; + } +} + +void +MachinaGUI::fan_toggled() +{ + if (_fan_button->get_active()) { + _chain_mode = false; + } +} + void MachinaGUI::on_new_object(SPtr object) { diff --git a/src/gui/MachinaGUI.hpp b/src/gui/MachinaGUI.hpp index d71c556..3ebbd04 100644 --- a/src/gui/MachinaGUI.hpp +++ b/src/gui/MachinaGUI.hpp @@ -62,6 +62,8 @@ public: void attach(); void quit() { _main_window->hide(); } + bool chain_mode() const { return _chain_mode; } + SPtr controller() { return _controller; } inline void queue_refresh() { _refresh = true; } @@ -108,12 +110,12 @@ protected: void play_toggled(); void record_toggled(); + void chain_toggled(); + void fan_toggled(); + void quantize_changed(); void tempo_changed(); - bool _refresh; - bool _evolve; - string _save_uri; string _target_filename; @@ -160,6 +162,8 @@ protected: Gtk::ToolButton* _zoom_normal_button; Gtk::ToolButton* _zoom_full_button; Gtk::ToolButton* _arrange_button; + Gtk::RadioButton* _chain_button; + Gtk::RadioButton* _fan_button; Gtk::ToolButton* _load_target_button; Gtk::Toolbar* _evolve_toolbar; Gtk::ToggleToolButton* _evolve_button; @@ -171,6 +175,10 @@ protected: Gtk::ToolButton* _add_edge_button; Gtk::ToolButton* _remove_edge_button; Gtk::ToolButton* _adjust_edge_button; + + bool _refresh; + bool _evolve; + bool _chain_mode; }; } // namespace machina diff --git a/src/gui/NodeView.cpp b/src/gui/NodeView.cpp index 6132f8c..38e5ea7 100644 --- a/src/gui/NodeView.cpp +++ b/src/gui/NodeView.cpp @@ -92,7 +92,7 @@ NodeView::on_event(GdkEvent* event) return true; } } else { - _signal_clicked.emit(&event->button); + return _signal_clicked.emit(&event->button); } } else if (event->type == GDK_2BUTTON_PRESS) { return on_double_click(&event->button); diff --git a/src/gui/machina.ui b/src/gui/machina.ui index 88c1c0b..75c4c1f 100644 --- a/src/gui/machina.ui +++ b/src/gui/machina.ui @@ -619,6 +619,67 @@ press stop or play and the new nodes will be added to the machine. True + + + True + False + + + False + + + + + False + True + False + + + True + False + 4 + + + Chain + False + True + True + False + Move selection to head node after connection + True + True + + + True + True + 0 + + + + + Fan + False + True + True + False + Keep selection on tail node after connection + True + True + chain_but + + + True + True + 1 + + + + + + + False + + True -- cgit v1.2.1