/* 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/log.hpp" #include "raul/SharedPtr.hpp" #include "raul/TimeStamp.hpp" #include "machina/Engine.hpp" #include "machina/Controller.hpp" #include "client/ClientObject.hpp" #include "client/ClientModel.hpp" #include "EdgeView.hpp" #include "MachinaCanvas.hpp" #include "MachinaGUI.hpp" #include "NodeView.hpp" using namespace Raul; using namespace Ganv; using namespace Machina; MachinaCanvas::MachinaCanvas(MachinaGUI* app, int width, int height) : Canvas(width, height) , _app(app) { widget().grab_focus(); } bool MachinaCanvas::node_clicked(WeakPtr item, GdkEventButton* event) { SharedPtr node = PtrCast(item.lock()); if (!node) return false; 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 == 3) { // Right click: connect/disconnect SharedPtr last = _last_clicked.lock(); if (last) { if (node != last) { if (get_edge(last.get(), node.get())) action_disconnect(last, node); else action_connect(last, node); } last->set_default_colors(); _last_clicked.reset(); } else { _last_clicked = node; node->set_fill_color(0xFF0000FF); } 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(SharedPtr object) { const Machina::URIs& uris = URIs::instance(); const Raul::Atom& type = object->get(uris.rdf_type); if (type == "machina:Node") { SharedPtr view( new NodeView(_app->window(), *this, object, object->get(uris.machina_canvas_x).get_float(), object->get(uris.machina_canvas_y).get_float())); //if ( ! node->enter_action() && ! node->exit_action() ) // view->set_base_color(0x101010FF); view->signal_click().connect( sigc::bind<0>(sigc::mem_fun(this, &MachinaCanvas::node_clicked), WeakPtr(view))); object->set_view(view); } else if (type == "machina:Edge") { SharedPtr tail = _app->client_model()->find( object->get(uris.machina_tail_id).get_int32()); SharedPtr head = _app->client_model()->find( object->get(uris.machina_head_id).get_int32()); SharedPtr tail_view = PtrCast(tail->view()); SharedPtr head_view = PtrCast(head->view()); SharedPtr view( new EdgeView(*this, tail_view, head_view, object)); object->set_view(view); } else { Raul::error << "Unknown object type " << type << std::endl; } } void MachinaCanvas::on_erase_object(SharedPtr object) { const Raul::Atom& type = object->get(URIs::instance().rdf_type); if (type == "machina:Node") { // Destruction of the view will remove from the canvas } else if (type == "machina:Edge") { object->set_view(SharedPtr()); } else { Raul::error << "Unknown object type " << type << std::endl; } } void MachinaCanvas::action_create_node(double x, double y) { Machina::Client::ClientObject obj(0); obj.set(URIs::instance().rdf_type, "machina:Node"); obj.set(URIs::instance().machina_canvas_x, Raul::Atom((float)x)); obj.set(URIs::instance().machina_canvas_y, Raul::Atom((float)y)); obj.set(URIs::instance().machina_duration, Raul::Atom((float)1.0)); _app->controller()->create(obj); } void MachinaCanvas::action_connect(boost::shared_ptr src, boost::shared_ptr head) { _app->controller()->connect(src->node()->id(), head->node()->id()); } void MachinaCanvas::action_disconnect(boost::shared_ptr src, boost::shared_ptr head) { _app->controller()->disconnect(src->node()->id(), head->node()->id()); }