aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2013-01-13 18:40:21 +0000
committerDavid Robillard <d@drobilla.net>2013-01-13 18:40:21 +0000
commit2a45807b4db3cf6fa1f11633b8dc4e83ab8622c5 (patch)
tree493cdade8dc9d875d430e669ac564069d209f97f
parent9c146cabc8bb9fe63c07a6ce1b72c7410af229c4 (diff)
downloadmachina-2a45807b4db3cf6fa1f11633b8dc4e83ab8622c5.tar.gz
machina-2a45807b4db3cf6fa1f11633b8dc4e83ab8622c5.tar.bz2
machina-2a45807b4db3cf6fa1f11633b8dc4e83ab8622c5.zip
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
-rw-r--r--src/gui/MachinaCanvas.cpp52
-rw-r--r--src/gui/MachinaCanvas.hpp8
-rw-r--r--src/gui/MachinaGUI.cpp30
-rw-r--r--src/gui/MachinaGUI.hpp14
-rw-r--r--src/gui/NodeView.cpp2
-rw-r--r--src/gui/machina.ui61
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<NodeView*>(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<machina::Engine> 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<MachinaCanvas>(new MachinaCanvas(this, 1600*2, 1200*2));
@@ -80,6 +81,8 @@ MachinaGUI::MachinaGUI(SPtr<machina::Engine> 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<machina::Engine> 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(
@@ -687,6 +695,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<client::ClientObject> object)
{
_canvas->on_new_object(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<machina::Controller> 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.
<property name="homogeneous">True</property>
</packing>
</child>
+ <child>
+ <object class="GtkSeparatorToolItem" id="separatortoolitem5">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolItem" id="toolitem2">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkHBox" id="hbox1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="border_width">4</property>
+ <child>
+ <object class="GtkRadioButton" id="chain_but">
+ <property name="label" translatable="yes">Chain</property>
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="tooltip_text" translatable="yes">Move selection to head node after connection</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="fan_but">
+ <property name="label" translatable="yes">Fan</property>
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="tooltip_text" translatable="yes">Keep selection on tail node after connection</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">chain_but</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
</object>
<packing>
<property name="expand">True</property>