// Copyright (C) 2001 Jean-Marc Valin
#include <iostream>
#include "GUILink.h"
#include "GUITerminal.h"
#include "GUINetwork.h"
#include "vflow.h"
#include <sstream>
using namespace std;
namespace FD {
static gint link_handler (GnomeCanvasItem *item, GdkEvent *event, gpointer data)
{
return ((GUILink *)(data))->event(event);
}
GUILink::GUILink(UITerminal *_from, UITerminal *_to, const char *points_str)
: UILink (_from, _to, points_str), MIN_POINT_DISTANCE(10.0) {
GnomeCanvasPoints *points = gnome_canvas_points_new(m_points.size());
int pos = 0;
for (list<GUILinkPoint*>::iterator iter = m_points.begin();
iter != m_points.end(); iter++) {
points->coords[pos++] = (*iter)->x;
points->coords[pos++] = (*iter)->y;
}
//gnome_canvas_item_set(item, "points", points, NULL);
group = GNOME_CANVAS_GROUP (gnome_canvas_item_new (dynamic_cast<GUINetwork *> (net)->getGroup(),
gnome_canvas_group_get_type(),
"x", 0,
"y", 0,
NULL));
item = gnome_canvas_item_new(group,
gnome_canvas_line_get_type(),
"points" , points,
"fill_color", "black",
"width_units", 2.0,
"cap_style",GDK_CAP_ROUND,
"last_arrowhead", TRUE,
"arrow_shape_a", 9.0,
"arrow_shape_b", 15.0,
"arrow_shape_c", 5.0,
NULL);
gnome_canvas_points_unref(points);
gtk_signal_connect(GTK_OBJECT(item), "event",
(GtkSignalFunc) link_handler,
this);
//link object type checking
if (from != NULL && to !=NULL) {
if (from->getType() != "any" &&
to->getType () != "any" &&
from->getType() != to->getType()) {
//wrong types, changing link color!
gnome_canvas_item_set(item,"fill_color","red",NULL);
}
}
}
GUILink::~GUILink()
{
gtk_object_destroy(GTK_OBJECT(item));
gtk_object_destroy(GTK_OBJECT(group));
while (!m_points.empty()) {
delete m_points.front();
m_points.pop_front();
}
}
void GUILink::grab(guint32 etime)
{
gnome_canvas_item_ungrab(item,etime);
GdkCursor *fleur = gdk_cursor_new(GDK_PLUS);
gnome_canvas_item_grab(item,
GDK_POINTER_MOTION_MASK |
GDK_BUTTON_RELEASE_MASK |
GDK_BUTTON_PRESS_MASK,
fleur,
etime);
gdk_cursor_destroy(fleur);
}
gint GUILink::event(GdkEvent *event)
{
//return TRUE;
static GUILinkPoint *my_point = NULL;
double new_x, new_y;
GdkCursor *fleur;
double item_x, item_y;
GnomeCanvasPoints *points;
stringstream text;
item_x = event->button.x;
item_y = event->button.y;
gnome_canvas_item_w2i(item->parent, &item_x, &item_y);
switch (event->type)
{
case GDK_BUTTON_PRESS:
//cerr<<"button press event"<<endl;
switch(event->button.button)
{
case 1:
if (event->button.state & GDK_SHIFT_MASK)
{
delete this;
return TRUE;
}
if (complete) {
int pos = 0;
GUILinkPoint p1(item_x,item_y);
if (m_points.size() == 2) {
if (p1.dist(*m_points.front()) > MIN_POINT_DISTANCE &&
p1.dist(*m_points.back()) > MIN_POINT_DISTANCE) {
//creating new point
my_point = new GUILinkPoint(item_x,item_y);
list<GUILinkPoint*>::iterator iter_end = m_points.end();
//inserting in the list
m_points.insert(--iter_end,my_point);
}
else {
//nothing to do
my_point = NULL;
}
}//m_points size == 2
else {
//adding to the list if far enough
my_point = NULL;
list<GUILinkPoint*>::iterator iter_end = m_points.end();
iter_end--;
//This loop makes us find where the click is
for (list<GUILinkPoint*>::iterator iter = m_points.begin();
iter != iter_end; iter++) {
list<GUILinkPoint*>::iterator iter1 = iter;
GUILinkPoint pfirst ((*iter1)->x,(*iter1)->y);
iter1++;
GUILinkPoint psecond ((*iter1)->x,(*iter1)->y);
double dist1 = p1.dist(pfirst);
double dist2 = p1.dist(psecond);
if (p1.between(pfirst,psecond)) {
if (dist1 > MIN_POINT_DISTANCE &&
dist2 > MIN_POINT_DISTANCE) {
//creating new point
my_point = new GUILinkPoint(item_x,item_y);
//inserting in the list
m_points.insert(iter1,my_point);
break;
} else {
//We're moving a point instead of creating one
if (dist1 < dist2)
{
if (iter != m_points.begin())
my_point = *iter;
break;
} else {
if (iter1 != iter_end)
my_point = *iter1;
break;
}
}
}//between
}//for
}//else
}//complete
break;
case 2:
if (event->button.state & GDK_SHIFT_MASK) {
cerr<<"We should add a new input or output!"<<endl;
}
break;
case 3:
//restoring link to only 2 points
while (!m_points.empty()) {
delete m_points.front();
m_points.pop_front();
}
m_points.push_back(new GUILinkPoint(x1,y1));
m_points.push_back(new GUILinkPoint(x2,y2));
points = gnome_canvas_points_new(2);
points->coords[0] = x1;
points->coords[1] = y1;
points->coords[2] = x2;
points->coords[3] = y2;
gnome_canvas_item_set(item, "points", points, NULL);
gnome_canvas_points_unref(points);
break;
default:
break;
}
break;
case GDK_MOTION_NOTIFY:
//cerr<<"motion notify event"<<endl;
//change status to display what the link is
if (from && to) {
text<<"GUILink : from : "<<from->getNode()->getName()<<":"<<from->getName() <<
" to : "<<to->getNode()->getName()<<":"<<to->getName();
vflowGUI::instance()->display_statusbar_text(text.str());
}
if (!complete && (event->motion.state & GDK_BUTTON1_MASK))
{
//gtk_object_get(new_line, "points", points, NULL);
points = gnome_canvas_points_new(2);
points->coords[0]=x1;
points->coords[1]=y1;
points->coords[2]=x2;
points->coords[3]=y2;
if (!from)
{
x1=item_x;
y1=item_y;
points->coords[0]=item_x;
points->coords[1]=item_y;
} else {
x2=item_x;
y2=item_y;
points->coords[2]=item_x;
points->coords[3]=item_y;
}
//updating our list
m_points.front()->x = points->coords[0];
m_points.front()->y = points->coords[1];
m_points.back()->x = points->coords[2];
m_points.back()->y = points->coords[3];
gnome_canvas_item_set(item, "points", points, NULL);
dynamic_cast<GUINetwork*>(net)->auto_scroll(item_x,item_y);
gnome_canvas_points_unref(points);
}
else {
if (event->motion.state & GDK_BUTTON1_MASK) {
//updating
if (my_point) {
my_point->x = item_x;
my_point->y = item_y;
}
points = gnome_canvas_points_new(m_points.size());
int pos = 0;
for (list<GUILinkPoint*>::iterator iter = m_points.begin();
iter != m_points.end(); iter++) {
points->coords[pos++] = (*iter)->x;
points->coords[pos++] = (*iter)->y;
}
gnome_canvas_item_set(item, "points", points, NULL);
gnome_canvas_points_unref(points);
}
}
break;
case GDK_BUTTON_RELEASE:
//cerr<<"button release event"<<endl;
gnome_canvas_item_ungrab(item, event->button.time);
if (!complete)
{
//gnome_canvas_item_ungrab(item, event->button.time);
//gnome_canvas_item_ungrab(item, event->button.time);
if (!from)
{
UITerminal *term = dynamic_cast<GUINetwork *>(net)->isNearOutputTerminal(x1,y1);
if (term)
{
from = term;
term->connect(this);
complete = true;
} else {
/*committing suicide*/
delete this;
return TRUE;
}
} else {
UITerminal *term = dynamic_cast<GUINetwork *>(net)->isNearInputTerminal(x2,y2);
if (term)
{
to = term;
if (term->isConnected())
{
delete this;
return TRUE;
}
term->connect(this);
complete = true;
} else {
/*committing suicide*/
delete this;
return TRUE;
}
}
net->addLink(this);
complete = true;
//link object type checking
if (from != NULL && to !=NULL) {
if (from->getType() != "any" &&
to->getType () != "any" &&
from->getType() != to->getType()) {
//wrong types, changing link color!
gnome_canvas_item_set(item,"fill_color","red",NULL);
}
}
}
else {
my_point = NULL;
net->setModified();
}
break;
default:
break;
}
return FALSE;
}
void GUILink::move (bool isInput, double dx,double dy)
{
GUINetwork *my_net = dynamic_cast<GUINetwork*>(net);
GUINode *my_from = dynamic_cast<GUINode*>(from->getNode());
GUINode *my_to = dynamic_cast<GUINode*>(to->getNode());
int pos = 0;
if (my_net->isNodeSelected(my_from) &&
my_net->isNodeSelected(my_to)) {
if (isInput) {
GnomeCanvasPoints *points = gnome_canvas_points_new(m_points.size());
x1+=dx;
y1+=dy;
x2+=dx;
y2+=dy;
for (list<GUILinkPoint*>::iterator iter = m_points.begin();
iter != m_points.end(); iter++) {
(*iter)->x += dx;
(*iter)->y += dy;
points->coords[pos++] = (*iter)->x;
points->coords[pos++] = (*iter)->y;
}
gnome_canvas_item_set(item, "points", points, NULL);
gnome_canvas_points_unref(points);
}
}
else {
GnomeCanvasPoints *points = gnome_canvas_points_new(m_points.size());
if (!isInput) {
x1+=dx;
y1+=dy;
}
else {
x2+=dx;
y2+=dy;
}
m_points.front()->setxy(x1,y1);
m_points.back()->setxy(x2,y2);
for (list<GUILinkPoint*>::iterator iter = m_points.begin();
iter != m_points.end(); iter++) {
points->coords[pos++] = (*iter)->x;
points->coords[pos++] = (*iter)->y;
}
gnome_canvas_item_set(item, "points", points, NULL);
gnome_canvas_points_unref(points);
}
}
void GUILink::update() {
GnomeCanvasPoints *points = gnome_canvas_points_new(m_points.size());
m_points.front()->setxy(x1,y1);
m_points.back()->setxy(x2,y2);
int pos = 0;
for (list<GUILinkPoint*>::iterator iter = m_points.begin();
iter != m_points.end(); iter++) {
points->coords[pos++] = (*iter)->x;
points->coords[pos++] = (*iter)->y;
}
gnome_canvas_item_set(item, "points", points, NULL);
gnome_canvas_points_unref(points);
}
}//namespace FD
syntax highlighted by Code2HTML, v. 0.9.1