/* This file is part of Machina. * Copyright 2007-2011 David Robillard * * 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 * (at your option) 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 . */ #include #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) , _last_clicked(NULL) { widget().grab_focus(); signal_event.connect( sigc::mem_fun(this, &MachinaCanvas::on_event)); } bool MachinaCanvas::node_clicked(NodeView* node, GdkEventButton* event) { if (event->state & GDK_CONTROL_MASK) { return false; } 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; } else { _last_clicked = node; } return true; } 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 object) { const machina::URIs& uris = URIs::instance(); const Raul::Atom& type = object->get(uris.rdf_type); if (!type.is_valid()) { return; } if (type.get() == uris.machina_Node) { 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), view)); object->set_view(view); } else if (type.get() == uris.machina_Edge) { SPtr tail = _app->client_model()->find( object->get(uris.machina_tail_id).get_int32()); SPtr head = _app->client_model()->find( object->get(uris.machina_head_id).get_int32()); if (!tail || !head) { std::cerr << "Invalid arc " << object->get(uris.machina_tail_id).get_int32() << " => " << object->get(uris.machina_head_id).get_int32() << std::endl; return; } NodeView* tail_view = dynamic_cast(tail->view()); NodeView* head_view = dynamic_cast(head->view()); object->set_view(new EdgeView(*this, tail_view, head_view, object)); } else { std::cerr << "Unknown object type " << type.get() << std::endl; } } void MachinaCanvas::on_erase_object(SPtr object) { const Raul::Atom& type = object->get(URIs::instance().rdf_type); if (type.get() == URIs::instance().machina_Node) { // Destruction of the view will remove from the canvas } else if (type.get() == URIs::instance().machina_Edge) { object->set_view(NULL); } else { std::cerr << "Unknown object type" << std::endl; } } void MachinaCanvas::action_create_node(double x, double y) { machina::client::ClientObject obj(0); obj.set(URIs::instance().rdf_type, _app->forge().make_urid(URIs::instance().machina_Node)); obj.set(URIs::instance().machina_canvas_x, _app->forge().make((float)x)); obj.set(URIs::instance().machina_canvas_y, _app->forge().make((float)y)); obj.set(URIs::instance().machina_duration, _app->forge().make(1.0f)); _app->controller()->create(obj); } 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