aboutsummaryrefslogtreecommitdiffstats
path: root/src/gui/MachinaCanvas.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/MachinaCanvas.cpp')
-rw-r--r--src/gui/MachinaCanvas.cpp211
1 files changed, 211 insertions, 0 deletions
diff --git a/src/gui/MachinaCanvas.cpp b/src/gui/MachinaCanvas.cpp
new file mode 100644
index 0000000..a9e51c4
--- /dev/null
+++ b/src/gui/MachinaCanvas.cpp
@@ -0,0 +1,211 @@
+/*
+ This file is part of Machina.
+ Copyright 2007-2014 David Robillard <http://drobilla.net>
+
+ 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 3 of the License, or any later version.
+
+ Machina is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Machina. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <map>
+
+#include "raul/TimeStamp.hpp"
+
+#include "client/ClientModel.hpp"
+#include "client/ClientObject.hpp"
+#include "machina/Controller.hpp"
+#include "machina/Engine.hpp"
+#include "machina/types.hpp"
+
+#include "EdgeView.hpp"
+#include "MachinaCanvas.hpp"
+#include "MachinaGUI.hpp"
+#include "NodeView.hpp"
+
+using namespace Raul;
+using namespace Ganv;
+
+namespace machina {
+namespace gui {
+
+MachinaCanvas::MachinaCanvas(MachinaGUI* app, int width, int height)
+ : Canvas(width, height)
+ , _app(app)
+ , _connect_node(NULL)
+ , _did_connect(false)
+{
+ widget().grab_focus();
+
+ signal_event.connect(sigc::mem_fun(this, &MachinaCanvas::on_event));
+}
+
+void
+MachinaCanvas::connect_nodes(GanvNode* node, void* data)
+{
+ MachinaCanvas* canvas = (MachinaCanvas*)data;
+ NodeView* view = dynamic_cast<NodeView*>(Glib::wrap(node));
+ if (!view || view == canvas->_connect_node) {
+ return;
+ }
+ 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|GDK_SHIFT_MASK)) {
+ return false;
+
+ } 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
+ _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 {
+ return handled; // If we did something, stop event here
+ }
+ }
+
+ return false;
+}
+
+bool
+MachinaCanvas::on_event(GdkEvent* event)
+{
+ if (event->type == GDK_BUTTON_RELEASE
+ && event->button.button == 3
+ && !(event->button.state & (GDK_CONTROL_MASK))) {
+
+ action_create_node(event->button.x, event->button.y);
+ return true;
+ }
+ return false;
+}
+
+void
+MachinaCanvas::on_new_object(SPtr<client::ClientObject> object)
+{
+ const machina::URIs& uris = URIs::instance();
+ const Atom& type = object->get(uris.rdf_type);
+ if (!type.is_valid()) {
+ return;
+ }
+
+ if (type.get<URIInt>() == uris.machina_Node) {
+ const Atom& node_x = object->get(uris.machina_canvas_x);
+ const 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 + 128.0;
+ y = scroll_y + 128.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),
+ view));
+
+ object->set_view(view);
+
+ } else if (type.get<URIInt>() == uris.machina_Edge) {
+ SPtr<machina::client::ClientObject> tail = _app->client_model()->find(
+ object->get(uris.machina_tail_id).get<int32_t>());
+ SPtr<machina::client::ClientObject> head = _app->client_model()->find(
+ object->get(uris.machina_head_id).get<int32_t>());
+
+ if (!tail || !head) {
+ std::cerr << "Invalid arc "
+ << object->get(uris.machina_tail_id).get<int32_t>()
+ << " => "
+ << object->get(uris.machina_head_id).get<int32_t>()
+ << std::endl;
+ return;
+ }
+
+ NodeView* tail_view = dynamic_cast<NodeView*>(tail->view());
+ NodeView* head_view = dynamic_cast<NodeView*>(head->view());
+
+ object->set_view(new EdgeView(*this, tail_view, head_view, object));
+
+ } else {
+ std::cerr << "Unknown object type " << type.get<URIInt>() << std::endl;
+ }
+}
+
+void
+MachinaCanvas::on_erase_object(SPtr<client::ClientObject> object)
+{
+ const Atom& type = object->get(URIs::instance().rdf_type);
+ if (type.get<URIInt>() == URIs::instance().machina_Node) {
+ delete object->view();
+ object->set_view(NULL);
+ } else if (type.get<URIInt>() == URIs::instance().machina_Edge) {
+ remove_edge(dynamic_cast<Ganv::Edge*>(object->view()));
+ object->set_view(NULL);
+ } else {
+ std::cerr << "Unknown object type" << std::endl;
+ }
+}
+
+void
+MachinaCanvas::action_create_node(double x, double y)
+{
+ const Properties props = {
+ { URIs::instance().rdf_type,
+ _app->forge().make_urid(URIs::instance().machina_Node) },
+ { URIs::instance().machina_canvas_x,
+ _app->forge().make((float)x) },
+ { URIs::instance().machina_canvas_y,
+ _app->forge().make((float)y) },
+ { URIs::instance().machina_duration,
+ _app->forge().make((float)_app->default_length()) } };
+
+ _app->controller()->create(props);
+}
+
+void
+MachinaCanvas::action_connect(NodeView* tail, NodeView* head)
+{
+ _app->controller()->connect(tail->node()->id(), head->node()->id());
+}
+
+void
+MachinaCanvas::action_disconnect(NodeView* tail, NodeView* head)
+{
+ _app->controller()->disconnect(tail->node()->id(), head->node()->id());
+}
+
+} // namespace machina
+} // namespace gui