ladish/gui/flowcanvas/Item.cpp

238 lines
5.0 KiB
C++

/* This file is part of FlowCanvas.
* Copyright (C) 2007-2009 David Robillard <http://drobilla.net>
*
* FlowCanvas 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 (at your option) any later
* version.
*
* FlowCanvas 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 details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <list>
#include <string>
#include <boost/shared_ptr.hpp>
#include "Canvas.hpp"
#include "Item.hpp"
using std::string;
using std::list;
namespace FlowCanvas {
Item::Item(boost::shared_ptr<Canvas> canvas,
const string& name,
double x,
double y,
uint32_t color)
: Gnome::Canvas::Group(*canvas->root(), x, y)
, _canvas(canvas)
, _menu(NULL)
, _name(name)
, _minimum_width(0.0)
, _width(1.0)
, _height(1.0)
, _border_color(color)
, _color(color)
, _selected(false)
{
}
void
Item::set_selected(bool s)
{
_selected = s;
if (s)
signal_selected.emit();
else
signal_unselected.emit();
}
/** Event handler to fire (higher level, abstracted) Item signals from Gtk events.
*/
bool
Item::on_event(GdkEvent* event)
{
boost::shared_ptr<Canvas> canvas = _canvas.lock();
if (!canvas || !event)
return false;
static double x, y;
static double drag_start_x, drag_start_y;
static bool double_click = false;
static bool dragging = false;
double click_x, click_y;
click_x = event->button.x;
click_y = event->button.y;
property_parent().get_value()->w2i(click_x, click_y);
switch (event->type) {
case GDK_2BUTTON_PRESS:
if (dragging) {
ungrab(event->button.time);
dragging = false;
}
on_double_click(&event->button);
double_click = true;
break;
case GDK_BUTTON_PRESS:
if (!canvas->locked() && event->button.button == 1) {
x = click_x;
y = click_y;
// Set these so we can tell on a button release if a drag actually
// happened (if not, it's just a click)
drag_start_x = x;
drag_start_y = y;
grab(GDK_POINTER_MOTION_MASK|GDK_BUTTON_RELEASE_MASK|GDK_BUTTON_PRESS_MASK,
Gdk::Cursor(Gdk::FLEUR), event->button.time);
dragging = true;
}
break;
case GDK_MOTION_NOTIFY:
if ((dragging && (event->motion.state & GDK_BUTTON1_MASK))) {
double new_x = click_x;
double new_y = click_y;
if (event->motion.is_hint) {
int t_x;
int t_y;
GdkModifierType state;
gdk_window_get_pointer(event->motion.window, &t_x, &t_y, &state);
new_x = t_x;
new_y = t_y;
}
on_drag(new_x - x, new_y - y);
x = new_x;
y = new_y;
}
break;
case GDK_BUTTON_RELEASE:
if (dragging) {
ungrab(event->button.time);
dragging = false;
if (click_x != drag_start_x || click_y != drag_start_y) {
on_drop();
} else if (!double_click) {
on_click(&event->button);
}
} else if (!double_click) {
on_click(&event->button);
}
double_click = false;
break;
case GDK_ENTER_NOTIFY:
canvas->signal_item_entered.emit(this);
raise_to_top();
break;
case GDK_LEAVE_NOTIFY:
canvas->signal_item_left.emit(this);
break;
default:
break;
}
// Never stop event propagation so derived classes have full access
// to GTK events.
return false;
}
void
Item::on_click(GdkEventButton* event)
{
boost::shared_ptr<Canvas> canvas = _canvas.lock();
if (!canvas)
return;
if (event->button == 1) {
if (_selected) {
canvas->unselect_item(shared_from_this());
assert(!_selected);
} else {
if ( !(event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)))
canvas->clear_selection();
canvas->select_item(shared_from_this());
}
}
if (event->button == 3 && popup_menu(event->button, event->time))
return;
signal_clicked.emit(event);
}
void
Item::on_double_click(GdkEventButton* ev)
{
boost::shared_ptr<Canvas> canvas = _canvas.lock();
if (canvas)
canvas->clear_selection();
signal_double_clicked.emit(ev);
}
void
Item::on_drag(double dx, double dy)
{
boost::shared_ptr<Canvas> canvas = _canvas.lock();
if (!canvas)
return;
// Move any other selected modules if we're selected
if (_selected) {
for (list<boost::shared_ptr<Item> >::iterator i = canvas->selected_items().begin();
i != canvas->selected_items().end(); ++i) {
(*i)->move(dx, dy);
}
} else {
move(dx, dy);
}
signal_dragged.emit(dx, dy);
}
void
Item::on_drop()
{
boost::shared_ptr<Canvas> canvas = _canvas.lock();
if (!canvas)
return;
if (_selected) {
for (list<boost::shared_ptr<Item> >::iterator i = canvas->selected_items().begin();
i != canvas->selected_items().end(); ++i) {
(*i)->store_location();
}
} else {
store_location();
}
}
} // namespace FlowCanvas