diff options
Diffstat (limited to 'src/gui')
-rw-r--r-- | src/gui/EdgeView.cpp | 11 | ||||
-rw-r--r-- | src/gui/EdgeView.hpp | 6 | ||||
-rw-r--r-- | src/gui/MachinaCanvas.cpp | 65 | ||||
-rw-r--r-- | src/gui/MachinaCanvas.hpp | 19 | ||||
-rw-r--r-- | src/gui/MachinaGUI.cpp | 74 | ||||
-rw-r--r-- | src/gui/MachinaGUI.hpp | 7 | ||||
-rw-r--r-- | src/gui/NodeView.cpp | 20 | ||||
-rw-r--r-- | src/gui/NodeView.hpp | 2 | ||||
-rw-r--r-- | src/gui/machina.ui | 66 |
9 files changed, 145 insertions, 125 deletions
diff --git a/src/gui/EdgeView.cpp b/src/gui/EdgeView.cpp index ec77a7b..da267e8 100644 --- a/src/gui/EdgeView.cpp +++ b/src/gui/EdgeView.cpp @@ -65,10 +65,10 @@ inline static uint32_t edge_color(float prob) using namespace Ganv; EdgeView::EdgeView(Canvas& canvas, - SPtr<NodeView> src, - SPtr<NodeView> dst, + NodeView* src, + NodeView* dst, SPtr<machina::client::ClientObject> edge) - : Ganv::Edge(canvas, src.get(), dst.get(), 0x9FA0A0F4, true, false) + : Ganv::Edge(canvas, src, dst, 0x9FA0A0F4, true, false) , _edge(edge) { set_color(edge_color(probability())); @@ -80,6 +80,11 @@ EdgeView::EdgeView(Canvas& canvas, sigc::mem_fun(this, &EdgeView::on_event)); } +EdgeView::~EdgeView() +{ + _edge->set_view(NULL); +} + float EdgeView::probability() const { diff --git a/src/gui/EdgeView.hpp b/src/gui/EdgeView.hpp index 6d51427..dbf4476 100644 --- a/src/gui/EdgeView.hpp +++ b/src/gui/EdgeView.hpp @@ -35,10 +35,12 @@ class EdgeView { public: EdgeView(Ganv::Canvas& canvas, - SPtr<NodeView> src, - SPtr<NodeView> dst, + NodeView* src, + NodeView* dst, SPtr<machina::client::ClientObject> edge); + ~EdgeView(); + void show_label(bool show); virtual double length_hint() const; diff --git a/src/gui/MachinaCanvas.cpp b/src/gui/MachinaCanvas.cpp index 627eb09..7a7efa9 100644 --- a/src/gui/MachinaCanvas.cpp +++ b/src/gui/MachinaCanvas.cpp @@ -39,6 +39,7 @@ namespace gui { MachinaCanvas::MachinaCanvas(MachinaGUI* app, int width, int height) : Canvas(width, height) , _app(app) + , _last_clicked(NULL) { widget().grab_focus(); @@ -47,13 +48,8 @@ MachinaCanvas::MachinaCanvas(MachinaGUI* app, int width, int height) } bool -MachinaCanvas::node_clicked(WPtr<NodeView> item, GdkEventButton* event) +MachinaCanvas::node_clicked(NodeView* node, GdkEventButton* event) { - SPtr<NodeView> node = dynamic_ptr_cast<NodeView>(item.lock()); - if (!node) { - return false; - } - if (event->state & GDK_CONTROL_MASK) { return false; } @@ -65,19 +61,17 @@ MachinaCanvas::node_clicked(WPtr<NodeView> item, GdkEventButton* event) } else if (event->button == 1) { // Left click: connect/disconnect - SPtr<NodeView> last = _last_clicked.lock(); - - if (last) { - if (node != last) { - if (get_edge(last.get(), node.get())) { - action_disconnect(last, node); + if (_last_clicked) { + if (node != _last_clicked) { + if (get_edge(_last_clicked, node)) { + action_disconnect(_last_clicked, node); } else { - action_connect(last, node); + action_connect(_last_clicked, node); } } - last->set_default_colors(); - _last_clicked.reset(); + _last_clicked->set_default_colors(); + _last_clicked = NULL; } else { _last_clicked = node; @@ -112,17 +106,28 @@ MachinaCanvas::on_new_object(SPtr<client::ClientObject> object) } if (type.get<URIInt>() == uris.machina_Node) { - SPtr<NodeView> view( - new NodeView(_app->window(), *this, object, - object->get(uris.machina_canvas_x).get_float(), - object->get(uris.machina_canvas_y).get_float())); + const Raul::Atom& node_x = object->get(uris.machina_canvas_x); + const Raul::Atom& node_y = object->get(uris.machina_canvas_y); + float x, y; + if (node_x.type() == _app->forge().Float && + node_y.type() == _app->forge().Float) { + x = node_x.get_float(); + y = node_y.get_float(); + } else { + int scroll_x, scroll_y; + get_scroll_offsets(scroll_x, scroll_y); + x = scroll_x + 64.0; + y = scroll_y + 64.0; + } + + NodeView* view = new NodeView(_app->window(), *this, object, x, y); //if ( ! node->enter_action() && ! node->exit_action() ) // view->set_base_color(0x101010FF); view->signal_clicked().connect( sigc::bind<0>(sigc::mem_fun(this, &MachinaCanvas::node_clicked), - WPtr<NodeView>(view))); + view)); object->set_view(view); @@ -141,12 +146,10 @@ MachinaCanvas::on_new_object(SPtr<client::ClientObject> object) return; } - SPtr<NodeView> tail_view = dynamic_ptr_cast<NodeView>(tail->view()); - SPtr<NodeView> head_view = dynamic_ptr_cast<NodeView>(head->view()); + NodeView* tail_view = dynamic_cast<NodeView*>(tail->view()); + NodeView* head_view = dynamic_cast<NodeView*>(head->view()); - SPtr<EdgeView> view(new EdgeView(*this, tail_view, head_view, object)); - - object->set_view(view); + object->set_view(new EdgeView(*this, tail_view, head_view, object)); } else { std::cerr << "Unknown object type " << type.get<URIInt>() << std::endl; @@ -160,7 +163,7 @@ MachinaCanvas::on_erase_object(SPtr<client::ClientObject> object) if (type.get<URIInt>() == URIs::instance().machina_Node) { // Destruction of the view will remove from the canvas } else if (type.get<URIInt>() == URIs::instance().machina_Edge) { - object->set_view(SPtr<client::ClientObject::View>()); + object->set_view(NULL); } else { std::cerr << "Unknown object type" << std::endl; } @@ -179,17 +182,15 @@ MachinaCanvas::action_create_node(double x, double y) } void -MachinaCanvas::action_connect(SPtr<NodeView> src, - SPtr<NodeView> head) +MachinaCanvas::action_connect(NodeView* tail, NodeView* head) { - _app->controller()->connect(src->node()->id(), head->node()->id()); + _app->controller()->connect(tail->node()->id(), head->node()->id()); } void -MachinaCanvas::action_disconnect(SPtr<NodeView> src, - SPtr<NodeView> head) +MachinaCanvas::action_disconnect(NodeView* tail, NodeView* head) { - _app->controller()->disconnect(src->node()->id(), head->node()->id()); + _app->controller()->disconnect(tail->node()->id(), head->node()->id()); } } // namespace machina diff --git a/src/gui/MachinaCanvas.hpp b/src/gui/MachinaCanvas.hpp index c396931..52e2d74 100644 --- a/src/gui/MachinaCanvas.hpp +++ b/src/gui/MachinaCanvas.hpp @@ -40,9 +40,6 @@ class MachinaCanvas public: MachinaCanvas(MachinaGUI* app, int width, int height); - //void build(SPtr<const machina::Machine> machine, bool show_labels); - //void update_edges(); - void on_new_object(SPtr<machina::client::ClientObject> object); void on_erase_object(SPtr<machina::client::ClientObject> object); @@ -51,21 +48,15 @@ public: protected: bool on_event(GdkEvent* event); - bool node_clicked(WPtr<NodeView> item, GdkEventButton* ev); + bool node_clicked(NodeView* node, GdkEventButton* ev); private: - //SPtr<NodeView> create_node_view(SPtr<machina::Node> node); - void action_create_node(double x, double y); + void action_connect(NodeView* tail, NodeView* head); + void action_disconnect(NodeView* tail, NodeView* head); - void action_connect(SPtr<NodeView> port1, - SPtr<NodeView> port2); - - void action_disconnect(SPtr<NodeView> port1, - SPtr<NodeView> port2); - - MachinaGUI* _app; - WPtr<NodeView> _last_clicked; + MachinaGUI* _app; + NodeView* _last_clicked; }; } // namespace machina diff --git a/src/gui/MachinaGUI.cpp b/src/gui/MachinaGUI.cpp index 63cbb76..f95eec2 100644 --- a/src/gui/MachinaGUI.cpp +++ b/src/gui/MachinaGUI.cpp @@ -102,8 +102,8 @@ MachinaGUI::MachinaGUI(SPtr<machina::Engine> engine) _record_button->signal_toggled().connect( sigc::mem_fun(this, &MachinaGUI::record_toggled)); - _stop_button->signal_clicked().connect( - sigc::mem_fun(this, &MachinaGUI::stop_clicked)); + _stop_button->signal_toggled().connect( + sigc::mem_fun(this, &MachinaGUI::stop_toggled)); _play_button->signal_toggled().connect( sigc::mem_fun(this, &MachinaGUI::play_toggled)); @@ -199,13 +199,12 @@ MachinaGUI::MachinaGUI(SPtr<machina::Engine> engine) _evolve_toolbar->set_sensitive(false); #endif - _controller->announce(engine->machine()); - _canvas->arrange(); - _client_model->signal_new_object.connect( sigc::mem_fun(this, &MachinaGUI::on_new_object)); _client_model->signal_erase_object.connect( sigc::mem_fun(this, &MachinaGUI::on_erase_object)); + + rebuild_canvas(); } MachinaGUI::~MachinaGUI() @@ -294,7 +293,7 @@ MachinaGUI::evolve_toggled() _evolver = SPtr<Evolver>( new Evolver(_unit, _target_filename, _engine->machine())); _evolve = true; - stop_clicked(); + stop_toggled(); _engine->driver()->set_machine(SPtr<Machine>()); _evolver->start(); } else { @@ -365,16 +364,24 @@ MachinaGUI::mutate(SPtr<Machine> machine, unsigned mutation) void MachinaGUI::update_toolbar() { - _record_button->set_active(_engine->driver()->recording()); - _play_button->set_active(_engine->machine()->is_activated()); + const Driver::PlayState state = _engine->driver()->play_state(); + _record_button->set_active(state == Driver::PlayState::RECORDING); + _play_button->set_active(state == Driver::PlayState::PLAYING); _quantize_spinbutton->set_sensitive(_quantize_checkbutton->get_active()); } void +MachinaGUI::rebuild_canvas() +{ + _controller->announce(_engine->machine()); + _canvas->arrange(); +} + +void MachinaGUI::quantize_changed() { if (_quantize_checkbutton->get_active()) { - _engine->set_quantization(1/(double)_quantize_spinbutton->get_value_as_int()); + _engine->set_quantization(1.0 / _quantize_spinbutton->get_value()); } else { _engine->set_quantization(0.0); } @@ -426,9 +433,7 @@ MachinaGUI::menu_file_open() if (result == Gtk::RESPONSE_OK) { SPtr<machina::Machine> new_machine = _engine->load_machine(dialog.get_uri()); if (new_machine) { - _canvas->destroy(); - _controller->announce(new_machine); - _canvas->arrange(); + rebuild_canvas(); _save_uri = dialog.get_uri(); } } @@ -536,10 +541,9 @@ MachinaGUI::menu_import_midi() if (machine) { dialog.hide(); - machine->activate(); machine->reset(NULL, machine->time()); _engine->driver()->set_machine(machine); - _controller->announce(machine); + rebuild_canvas(); } else { Gtk::MessageDialog msg_dialog(dialog, "Error loading MIDI file", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); @@ -651,41 +655,35 @@ MachinaGUI::menu_help_help() } void -MachinaGUI::record_toggled() +MachinaGUI::stop_toggled() { - if (_record_button->get_active() && ! _engine->driver()->recording()) { - _engine->driver()->start_record(_step_record_checkbutton->get_active()); - } else if (_engine->driver()->recording()) { - _engine->driver()->finish_record(); - _controller->announce(_engine->machine()); - update_toolbar(); + if (_stop_button->get_active()) { + const Driver::PlayState old_state = _engine->driver()->play_state(); + _engine->driver()->set_play_state(Driver::PlayState::STOPPED); + if (old_state == Driver::PlayState::RECORDING) { + rebuild_canvas(); + } } } void -MachinaGUI::stop_clicked() +MachinaGUI::play_toggled() { - _play_button->set_active(false); - - if (_engine->driver()->recording()) { - _engine->driver()->stop(); - _engine->machine()->deactivate(); - _controller->announce(_engine->machine()); - } else { - _engine->driver()->stop(); - _engine->machine()->deactivate(); + if (_play_button->get_active()) { + const Driver::PlayState old_state = _engine->driver()->play_state(); + _engine->driver()->set_play_state(Driver::PlayState::PLAYING); + if (old_state == Driver::PlayState::RECORDING) { + rebuild_canvas(); + } } - - update_toolbar(); } void -MachinaGUI::play_toggled() +MachinaGUI::record_toggled() { - if (_play_button->get_active()) - _engine->machine()->activate(); - else - _engine->machine()->deactivate(); + if (_record_button->get_active()) { + _engine->driver()->set_play_state(Driver::PlayState::RECORDING); + } } void diff --git a/src/gui/MachinaGUI.hpp b/src/gui/MachinaGUI.hpp index 6c85dca..c06d6b3 100644 --- a/src/gui/MachinaGUI.hpp +++ b/src/gui/MachinaGUI.hpp @@ -95,6 +95,7 @@ protected: void mutate(SPtr<machina::Machine> machine, unsigned mutation); void zoom(double z); void update_toolbar(); + void rebuild_canvas(); bool scrolled_window_event(GdkEvent* ev); bool idle_callback(); @@ -104,9 +105,9 @@ protected: bool evolve_callback(); #endif - void record_toggled(); - void stop_clicked(); + void stop_toggled(); void play_toggled(); + void record_toggled(); void quantize_changed(); void tempo_changed(); @@ -155,7 +156,7 @@ protected: Gtk::CheckButton* _quantize_checkbutton; Gtk::SpinButton* _quantize_spinbutton; Gtk::ToggleToolButton* _record_button; - Gtk::ToolButton* _stop_button; + Gtk::ToggleToolButton* _stop_button; Gtk::ToggleToolButton* _play_button; Gtk::ToolButton* _zoom_normal_button; Gtk::ToolButton* _zoom_full_button; diff --git a/src/gui/NodeView.cpp b/src/gui/NodeView.cpp index a73b996..d1bd913 100644 --- a/src/gui/NodeView.cpp +++ b/src/gui/NodeView.cpp @@ -45,6 +45,12 @@ NodeView::NodeView(Gtk::Window* window, signal_event().connect( sigc::mem_fun(this, &NodeView::on_event)); + MachinaCanvas* mcanvas = dynamic_cast<MachinaCanvas*>(&canvas); + if (is(mcanvas->app()->forge(), URIs::instance().machina_initial)) { + set_border_width(4.0); + set_label("init"); + } + node->signal_property.connect( sigc::mem_fun(this, &NodeView::on_property)); @@ -53,6 +59,11 @@ NodeView::NodeView(Gtk::Window* window, } } +NodeView::~NodeView() +{ + _node->set_view(NULL); +} + bool NodeView::on_double_click(GdkEventButton*) { @@ -77,12 +88,6 @@ NodeView::on_event(GdkEvent* event) if (event->button.button == 1) { canvas->app()->controller()->set_property( _node->id(), - URIs::instance().machina_initial, - forge.make(!is(forge, URIs::instance().machina_initial))); - return true; - } else if (event->button.button == 3) { - canvas->app()->controller()->set_property( - _node->id(), URIs::instance().machina_selector, forge.make(!is(forge, URIs::instance().machina_selector))); return true; @@ -133,7 +138,6 @@ NodeView::on_property(machina::URIInt key, const Raul::Atom& value) static const uint32_t active_border_color = 0x00FF00FF; if (key == URIs::instance().machina_selector) { - //_node.property_dash() = value.get_bool() ? selector_dash() : 0; if (value.get_bool()) { set_dash_length(4.0); } else { @@ -162,8 +166,6 @@ NodeView::on_property(machina::URIInt key, const Raul::Atom& value) on_action_property(i.first, i.second); } } - } else { - cout << "Unknown property " << key << endl; } } diff --git a/src/gui/NodeView.hpp b/src/gui/NodeView.hpp index 17f8c44..6ad68fb 100644 --- a/src/gui/NodeView.hpp +++ b/src/gui/NodeView.hpp @@ -38,6 +38,8 @@ public: double x, double y); + ~NodeView(); + SPtr<machina::client::ClientObject> node() { return _node; } void show_label(bool show); diff --git a/src/gui/machina.ui b/src/gui/machina.ui index b48df7d..bb1b711 100644 --- a/src/gui/machina.ui +++ b/src/gui/machina.ui @@ -2,15 +2,29 @@ <interface> <requires lib="gtk+" version="2.16"/> <!-- interface-naming-policy toplevel-contextual --> + <object class="GtkRadioAction" id="record_action"> + <property name="stock_id">gtk-media-record</property> + <property name="draw_as_radio">True</property> + </object> + <object class="GtkRadioAction" id="play_action"> + <property name="stock_id">gtk-media-play</property> + <property name="draw_as_radio">True</property> + <property name="group">record_action</property> + </object> + <object class="GtkRadioAction" id="stop_action"> + <property name="stock_id">gtk-media-stop</property> + <property name="draw_as_radio">True</property> + <property name="group">record_action</property> + </object> <object class="GtkAboutDialog" id="about_win"> <property name="can_focus">False</property> <property name="destroy_with_parent">True</property> <property name="type_hint">normal</property> + <property name="program_name">Machina</property> <property name="copyright" translatable="yes">© 2013 David Robillard <http://drobilla.net></property> <property name="comments" translatable="yes">A MIDI sequencer based on probabilistic finite-state automata</property> <property name="website">http://drobilla.net/software/machina</property> - <property name="website_label" translatable="yes">Website:</property> <property name="license" translatable="yes">Machina is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or @@ -99,17 +113,24 @@ along with Machina; if not, write to the Free Software Foundation, Inc., <property name="can_focus">False</property> <property name="xalign">0</property> <property name="yalign">0</property> - <property name="label" translatable="yes">Initial nodes are shown with a thick border. -Selector nodes are shown in green. + <property name="label" translatable="yes">Nodes represent notes, which have a pitch and duration. When a node is +highlighted green, it is playing. After a node is finished playing, play +travels along the outgoing arcs, depending on their probability. + +Nodes with dashed borders are selectors. Only one successor is played after a +selector, i.e. only one outgoing arc is traversed. + +A machine can be constructed with the mouse or by recording MIDI input. To +record, press the record button and play some MIDI notes. To finish recording, +press stop or play and the new nodes will be added to the machine. -- Right click canvas to create a new node -- Middle click nodes to learn a MIDI note for that node -- Right click two nodes in succession to connect nodes -- Double click a node to show its properties dialog -- Ctrl+Left click a node to make it an initial node -- Ctrl+Right click a node to make it a selector node -- Ctrl+Left click edge probabilities to decrease -- Ctrl+Right click edge probabilities to increase</property> +• Right click the canvas to create a new node +• Middle click a node to learn a MIDI note +• Click two nodes in succession to connect them +• Double click a node to show its properties dialog +• Ctrl+Left click a node to make it a selector +• Ctrl+Left click an edge to decrease its probability +• Ctrl+Right click an edge to increase its probability</property> </object> <packing> <property name="expand">True</property> @@ -353,12 +374,11 @@ Selector nodes are shown in green. <property name="toolbar_style">icons</property> <property name="show_arrow">False</property> <child> - <object class="GtkToggleToolButton" id="record_but"> - <property name="use_action_appearance">False</property> + <object class="GtkToggleToolButton" id="stop_but"> + <property name="related_action">stop_action</property> <property name="visible">True</property> <property name="can_focus">False</property> - <property name="tooltip_text" translatable="yes">Record</property> - <property name="stock_id">gtk-media-record</property> + <property name="use_underline">True</property> </object> <packing> <property name="expand">False</property> @@ -366,12 +386,12 @@ Selector nodes are shown in green. </packing> </child> <child> - <object class="GtkToolButton" id="stop_but"> - <property name="use_action_appearance">False</property> + <object class="GtkToggleToolButton" id="play_but"> + <property name="related_action">play_action</property> <property name="visible">True</property> <property name="can_focus">False</property> - <property name="tooltip_text" translatable="yes">Stop</property> - <property name="stock_id">gtk-media-stop</property> + <property name="tooltip_text" translatable="yes">Play</property> + <property name="active">True</property> </object> <packing> <property name="expand">False</property> @@ -379,13 +399,11 @@ Selector nodes are shown in green. </packing> </child> <child> - <object class="GtkToggleToolButton" id="play_but"> - <property name="use_action_appearance">False</property> + <object class="GtkToggleToolButton" id="record_but"> + <property name="related_action">record_action</property> <property name="visible">True</property> <property name="can_focus">False</property> - <property name="tooltip_text" translatable="yes">Play</property> - <property name="stock_id">gtk-media-play</property> - <property name="active">True</property> + <property name="tooltip_text" translatable="yes">Record</property> </object> <packing> <property name="expand">False</property> |