1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/graph_displayer_canvas-event.cc Mon Jul 07 08:10:39 2008 -0500
1.3 @@ -0,0 +1,967 @@
1.4 +/* -*- C++ -*-
1.5 + *
1.6 + * This file is a part of LEMON, a generic C++ optimization library
1.7 + *
1.8 + * Copyright (C) 2003-2006
1.9 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
1.10 + * (Egervary Research Group on Combinatorial Optimization, EGRES).
1.11 + *
1.12 + * Permission to use, modify and distribute this software is granted
1.13 + * provided that this copyright notice appears in all copies. For
1.14 + * precise terms see the accompanying LICENSE file.
1.15 + *
1.16 + * This software is provided "AS IS" with no warranty of any kind,
1.17 + * express or implied, and with no claim as to its suitability for any
1.18 + * purpose.
1.19 + *
1.20 + */
1.21 +
1.22 +#include <graph_displayer_canvas.h>
1.23 +#include <mapstorage.h>
1.24 +#include <nbtab.h>
1.25 +#include <cmath>
1.26 +#include <set>
1.27 +
1.28 +bool DigraphDisplayerCanvas::on_expose_event(GdkEventExpose *event)
1.29 +{
1.30 + Gnome::Canvas::CanvasAA::on_expose_event(event);
1.31 + //usleep(10000);
1.32 + //rezoom();
1.33 + return true;
1.34 +}
1.35 +
1.36 +void DigraphDisplayerCanvas::changeEditorialTool(int newtool)
1.37 +{
1.38 + if(actual_tool!=newtool)
1.39 + {
1.40 +
1.41 + actual_handler.disconnect();
1.42 +
1.43 + switch(actual_tool)
1.44 + {
1.45 + case CREATE_EDGE:
1.46 + {
1.47 + GdkEvent * generated=new GdkEvent();
1.48 + generated->type=GDK_BUTTON_RELEASE;
1.49 + generated->button.button=3;
1.50 + createArcEventHandler(generated);
1.51 + break;
1.52 + }
1.53 + case MAP_EDIT:
1.54 + {
1.55 + break;
1.56 + }
1.57 + default:
1.58 + break;
1.59 + }
1.60 +
1.61 + active_item=NULL;
1.62 + target_item=NULL;
1.63 + active_arc=INVALID;
1.64 + active_node=INVALID;
1.65 +
1.66 +
1.67 + actual_tool=newtool;
1.68 +
1.69 + switch(newtool)
1.70 + {
1.71 + case MOVE:
1.72 + actual_handler=signal_event().connect(sigc::mem_fun(*this, &DigraphDisplayerCanvas::moveEventHandler), false);
1.73 + break;
1.74 +
1.75 + case CREATE_NODE:
1.76 + actual_handler=signal_event().connect(sigc::mem_fun(*this, &DigraphDisplayerCanvas::createNodeEventHandler), false);
1.77 + break;
1.78 +
1.79 + case CREATE_EDGE:
1.80 + actual_handler=signal_event().connect(sigc::mem_fun(*this, &DigraphDisplayerCanvas::createArcEventHandler), false);
1.81 + break;
1.82 +
1.83 + case ERASER:
1.84 + actual_handler=signal_event().connect(sigc::mem_fun(*this, &DigraphDisplayerCanvas::eraserEventHandler), false);
1.85 + break;
1.86 +
1.87 + case MAP_EDIT:
1.88 + grab_focus();
1.89 + actual_handler=signal_event().connect(sigc::mem_fun(*this, &DigraphDisplayerCanvas::mapEditEventHandler), false);
1.90 + break;
1.91 +
1.92 + default:
1.93 + break;
1.94 + }
1.95 + }
1.96 +}
1.97 +
1.98 +int DigraphDisplayerCanvas::getActualTool()
1.99 +{
1.100 + return actual_tool;
1.101 +}
1.102 +
1.103 +bool DigraphDisplayerCanvas::scrollEventHandler(GdkEvent* e)
1.104 +{
1.105 + bool handled=false;
1.106 + if(e->type==GDK_SCROLL)
1.107 + {
1.108 +
1.109 + //pointer shows this win point before zoom
1.110 + XY win_coord(((GdkEventScroll*)e)->x, ((GdkEventScroll*)e)->y);
1.111 +
1.112 + //the original scroll settings
1.113 + int scroll_offset_x, scroll_offset_y;
1.114 + get_scroll_offsets(scroll_offset_x, scroll_offset_y);
1.115 +
1.116 + //pointer shows this canvas point before zoom
1.117 + XY canvas_coord;
1.118 + window_to_world(win_coord.x, win_coord.y, canvas_coord.x, canvas_coord.y);
1.119 +
1.120 + if(((GdkEventScroll*)e)->direction) //IN
1.121 + {
1.122 + zoomIn();
1.123 + }
1.124 + else
1.125 + {
1.126 + zoomOut();
1.127 + }
1.128 +
1.129 + //pointer shows this window point after zoom
1.130 + XY post_win_coord;
1.131 + world_to_window(canvas_coord.x, canvas_coord.y, post_win_coord.x, post_win_coord.y);
1.132 +
1.133 + //we have to add the difference between new and old window point to original scroll offset
1.134 + scroll_to(scroll_offset_x+(int)(post_win_coord.x-win_coord.x),scroll_offset_y+(int)(post_win_coord.y-win_coord.y));
1.135 +
1.136 + //no other eventhandler is needed
1.137 + handled=true;
1.138 + }
1.139 + return handled;
1.140 +}
1.141 +
1.142 +bool DigraphDisplayerCanvas::moveEventHandler(GdkEvent* e)
1.143 +{
1.144 + MapStorage& ms = *mytab.mapstorage;
1.145 +
1.146 + static Gnome::Canvas::Text *coord_text = 0;
1.147 + switch(e->type)
1.148 + {
1.149 + case GDK_BUTTON_PRESS:
1.150 + //we mark the location of the event to be able to calculate parameters of dragging
1.151 + window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
1.152 +
1.153 + active_item=(get_item_at(clicked_x, clicked_y));
1.154 + active_node=INVALID;
1.155 + for (NodeIt i(ms.digraph); i!=INVALID; ++i)
1.156 + {
1.157 + if(nodesmap[i]==active_item)
1.158 + {
1.159 + active_node=i;
1.160 + }
1.161 + }
1.162 + isbutton=e->button.button;
1.163 + break;
1.164 + case GDK_BUTTON_RELEASE:
1.165 + if (coord_text)
1.166 + {
1.167 + delete coord_text;
1.168 + coord_text = 0;
1.169 + }
1.170 + isbutton=0;
1.171 + active_item=NULL;
1.172 + active_node=INVALID;
1.173 + break;
1.174 + case GDK_MOTION_NOTIFY:
1.175 + //we only have to do sg. if the mouse button is pressed AND the click was on a node that was found in the set of nodes
1.176 + if(active_node!=INVALID)
1.177 + {
1.178 + ms.setModified();
1.179 +
1.180 + //new coordinates will be the old values,
1.181 + //because the item will be moved to the
1.182 + //new coordinate therefore the new movement
1.183 + //has to be calculated from here
1.184 +
1.185 + double new_x, new_y;
1.186 +
1.187 + window_to_world (e->motion.x, e->motion.y, new_x, new_y);
1.188 +
1.189 + double dx=new_x-clicked_x;
1.190 + double dy=new_y-clicked_y;
1.191 +
1.192 + moveNode(dx, dy);
1.193 +
1.194 + clicked_x=new_x;
1.195 + clicked_y=new_y;
1.196 +
1.197 + // reposition the coordinates text
1.198 + std::ostringstream ostr;
1.199 + ostr << "(" <<
1.200 + ms.getNodeCoords(active_node).x << ", " <<
1.201 + ms.getNodeCoords(active_node).y << ")";
1.202 + double radius =
1.203 + (nodesmap[active_node]->property_x2().get_value() -
1.204 + nodesmap[active_node]->property_x1().get_value()) / 2.0;
1.205 + if (coord_text)
1.206 + {
1.207 + coord_text->property_text().set_value(ostr.str());
1.208 + coord_text->property_x().set_value(
1.209 + ms.getNodeCoords(active_node).x + radius);
1.210 + coord_text->property_y().set_value(
1.211 + ms.getNodeCoords(active_node).y - radius);
1.212 + }
1.213 + else
1.214 + {
1.215 + coord_text = new Gnome::Canvas::Text(
1.216 + displayed_graph,
1.217 + ms.getNodeCoords(active_node).x + radius,
1.218 + ms.getNodeCoords(active_node).y - radius,
1.219 + ostr.str());
1.220 + coord_text->property_fill_color().set_value("black");
1.221 + coord_text->property_anchor().set_value(Gtk::ANCHOR_SOUTH_WEST);
1.222 + }
1.223 +
1.224 +
1.225 + }
1.226 + default: break;
1.227 + }
1.228 +
1.229 + return false;
1.230 +}
1.231 +
1.232 +XY DigraphDisplayerCanvas::calcArrowPos(XY moved_node_1, XY moved_node_2, XY fix_node, XY old_arrow_pos, int move_code)
1.233 +{
1.234 + switch(move_code)
1.235 + {
1.236 + case 1:
1.237 + return XY((moved_node_2.x + fix_node.x) / 2.0, (moved_node_2.y + fix_node.y) / 2.0);
1.238 + break;
1.239 + case 2:
1.240 + return old_arrow_pos;
1.241 + break;
1.242 + case 3:
1.243 + {
1.244 + //////////////////////////////////////////////////////////////////////////////////////////////////////
1.245 + /////////// keeps shape-with scalar multiplication - version 2.
1.246 + //////////////////////////////////////////////////////////////////////////////////////////////////////
1.247 +
1.248 + //old vector from one to the other node - a
1.249 + XY a_v(moved_node_1.x-fix_node.x,moved_node_1.y-fix_node.y);
1.250 + //new vector from one to the other node - b
1.251 + XY b_v(moved_node_2.x-fix_node.x,moved_node_2.y-fix_node.y);
1.252 +
1.253 + double absa=sqrt(a_v.normSquare());
1.254 + double absb=sqrt(b_v.normSquare());
1.255 +
1.256 + if ((absa == 0.0) || (absb == 0.0))
1.257 + {
1.258 + return old_arrow_pos;
1.259 + }
1.260 + else
1.261 + {
1.262 + //old vector from one node to the breakpoint - c
1.263 + XY c_v(old_arrow_pos.x-fix_node.x,old_arrow_pos.y-fix_node.y);
1.264 +
1.265 + //unit vector with the same direction to a_v
1.266 + XY a_v_u(a_v.x/absa,a_v.y/absa);
1.267 +
1.268 + //normal vector of unit vector with the same direction to a_v
1.269 + XY a_v_u_n(((-1)*a_v_u.y),a_v_u.x);
1.270 +
1.271 + //unit vector with the same direction to b_v
1.272 + XY b_v_u(b_v.x/absb,b_v.y/absb);
1.273 +
1.274 + //normal vector of unit vector with the same direction to b_v
1.275 + XY b_v_u_n(((-1)*b_v_u.y),b_v_u.x);
1.276 +
1.277 + //vector c in a_v_u and a_v_u_n co-ordinate system
1.278 + XY c_a(c_v*a_v_u,c_v*a_v_u_n);
1.279 +
1.280 + //new vector from one node to the breakpoint - d - we have to calculate this one
1.281 + XY d_v=absb/absa*(c_a.x*b_v_u+c_a.y*b_v_u_n);
1.282 +
1.283 + return XY(d_v.x+fix_node.x,d_v.y+fix_node.y);
1.284 + }
1.285 + break;
1.286 + }
1.287 + default:
1.288 + break;
1.289 + }
1.290 +}
1.291 +
1.292 +
1.293 +bool DigraphDisplayerCanvas::createNodeEventHandler(GdkEvent* e)
1.294 +{
1.295 + MapStorage& ms = *mytab.mapstorage;
1.296 +
1.297 + switch(e->type)
1.298 + {
1.299 + //move the new node
1.300 + case GDK_MOTION_NOTIFY:
1.301 + {
1.302 + GdkEvent * generated=new GdkEvent();
1.303 + generated->motion.x=e->motion.x;
1.304 + generated->motion.y=e->motion.y;
1.305 + generated->type=GDK_MOTION_NOTIFY;
1.306 + moveEventHandler(generated);
1.307 + break;
1.308 + }
1.309 +
1.310 + case GDK_BUTTON_RELEASE:
1.311 + ms.setModified();
1.312 +
1.313 + is_drawn=true;
1.314 +
1.315 + isbutton=1;
1.316 +
1.317 + window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
1.318 +
1.319 + active_node = ms.addNode(XY(clicked_x, clicked_y));
1.320 +
1.321 + nodesmap[active_node]=new Gnome::Canvas::Ellipse(displayed_graph,
1.322 + clicked_x-20, clicked_y-20, clicked_x+20, clicked_y+20);
1.323 + active_item=(Gnome::Canvas::Item *)(nodesmap[active_node]);
1.324 + *(nodesmap[active_node]) <<
1.325 + Gnome::Canvas::Properties::fill_color("blue");
1.326 + *(nodesmap[active_node]) <<
1.327 + Gnome::Canvas::Properties::outline_color("black");
1.328 + active_item->raise_to_top();
1.329 +
1.330 + (nodesmap[active_node])->show();
1.331 +
1.332 + nodetextmap[active_node]=new Gnome::Canvas::Text(displayed_graph,
1.333 + clicked_x+node_property_defaults[N_RADIUS]+5,
1.334 + clicked_y+node_property_defaults[N_RADIUS]+5, "");
1.335 + nodetextmap[active_node]->property_fill_color().set_value("darkblue");
1.336 + nodetextmap[active_node]->raise_to_top();
1.337 +
1.338 + // mapwin.updateNode(active_node);
1.339 + propertyUpdate(active_node);
1.340 +
1.341 + isbutton=0;
1.342 + target_item=NULL;
1.343 + active_item=NULL;
1.344 + active_node=INVALID;
1.345 + break;
1.346 + default:
1.347 + break;
1.348 + }
1.349 + return false;
1.350 +}
1.351 +
1.352 +bool DigraphDisplayerCanvas::createArcEventHandler(GdkEvent* e)
1.353 +{
1.354 + MapStorage& ms = *mytab.mapstorage;
1.355 +
1.356 + switch(e->type)
1.357 + {
1.358 + case GDK_BUTTON_PRESS:
1.359 + //in arc creation right button has special meaning
1.360 + if(e->button.button!=3)
1.361 + {
1.362 + //there is not yet selected node
1.363 + if(active_node==INVALID)
1.364 + {
1.365 + //we mark the location of the event to be able to calculate parameters of dragging
1.366 +
1.367 + window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
1.368 +
1.369 + active_item=(get_item_at(clicked_x, clicked_y));
1.370 + active_node=INVALID;
1.371 + for (NodeIt i(ms.digraph); i!=INVALID; ++i)
1.372 + {
1.373 + if(nodesmap[i]==active_item)
1.374 + {
1.375 + active_node=i;
1.376 + }
1.377 + }
1.378 + //the clicked item is really a node
1.379 + if(active_node!=INVALID)
1.380 + {
1.381 + *(nodesmap[active_node]) << Gnome::Canvas::Properties::fill_color("red");
1.382 + isbutton=1;
1.383 + }
1.384 + //clicked item was not a node. It could be e.g. arc.
1.385 + else
1.386 + {
1.387 + active_item=NULL;
1.388 + }
1.389 + }
1.390 + //we only have to do sg. if the mouse button
1.391 + // is pressed already once AND the click was
1.392 + // on a node that was found in the set of
1.393 + //nodes, and now we only search for the second
1.394 + //node
1.395 + else
1.396 + {
1.397 + window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
1.398 + target_item=(get_item_at(clicked_x, clicked_y));
1.399 + Node target_node=INVALID;
1.400 + for (NodeIt i(ms.digraph); i!=INVALID; ++i)
1.401 + {
1.402 + if(nodesmap[i]==target_item)
1.403 + {
1.404 + target_node=i;
1.405 + }
1.406 + }
1.407 + //the clicked item is a node, the arc can be drawn
1.408 + if(target_node!=INVALID)
1.409 + {
1.410 + ms.setModified();
1.411 +
1.412 + *(nodesmap[target_node]) <<
1.413 + Gnome::Canvas::Properties::fill_color("red");
1.414 +
1.415 + active_arc = ms.addArc(active_node, target_node);
1.416 +
1.417 + if(target_node!=active_node)
1.418 + {
1.419 + arcsmap[active_arc]=new BrokenArc(displayed_graph, active_arc, *this);
1.420 + }
1.421 + else
1.422 + {
1.423 + arcsmap[active_arc]=new LoopArc(displayed_graph, active_arc, *this);
1.424 + }
1.425 +
1.426 + //initializing arc-text as well, to empty string
1.427 + XY text_pos=ms.getArrowCoords(active_arc);
1.428 + text_pos+=(XY(10,10));
1.429 +
1.430 + arctextmap[active_arc]=new Gnome::Canvas::Text(displayed_graph,
1.431 + text_pos.x, text_pos.y, "");
1.432 + arctextmap[active_arc]->property_fill_color().set_value(
1.433 + "darkgreen");
1.434 + arctextmap[active_arc]->raise_to_top();
1.435 +
1.436 + propertyUpdate(active_arc);
1.437 + }
1.438 + //clicked item was not a node. it could be an e.g. arc. we do not
1.439 + //deal with it furthermore.
1.440 + else
1.441 + {
1.442 + target_item=NULL;
1.443 + }
1.444 + }
1.445 + }
1.446 + break;
1.447 + case GDK_BUTTON_RELEASE:
1.448 + isbutton=0;
1.449 + //we clear settings in two cases
1.450 + //1: the arc is ready (target_item has valid value)
1.451 + //2: the arc creation is cancelled with right button
1.452 + if((target_item)||(e->button.button==3))
1.453 + {
1.454 + if(active_item)
1.455 + {
1.456 + propertyUpdate(active_node,N_COLOR);
1.457 + active_item=NULL;
1.458 + }
1.459 + if(target_item)
1.460 + {
1.461 + propertyUpdate(ms.digraph.target(active_arc),N_COLOR);
1.462 + target_item=NULL;
1.463 + }
1.464 + active_node=INVALID;
1.465 + active_arc=INVALID;
1.466 + }
1.467 + break;
1.468 + default:
1.469 + break;
1.470 + }
1.471 + return false;
1.472 +}
1.473 +
1.474 +bool DigraphDisplayerCanvas::eraserEventHandler(GdkEvent* e)
1.475 +{
1.476 + MapStorage& ms = *mytab.mapstorage;
1.477 +
1.478 + switch(e->type)
1.479 + {
1.480 + case GDK_BUTTON_PRESS:
1.481 + //finding the clicked items
1.482 + window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
1.483 + active_item=(get_item_at(clicked_x, clicked_y));
1.484 + active_node=INVALID;
1.485 + active_arc=INVALID;
1.486 + //was it a node?
1.487 + for (NodeIt i(ms.digraph); i!=INVALID; ++i)
1.488 + {
1.489 + if(nodesmap[i]==active_item)
1.490 + {
1.491 + active_node=i;
1.492 + }
1.493 + }
1.494 + //or was it an arc?
1.495 + if(active_node==INVALID)
1.496 + {
1.497 + for (ArcIt i(ms.digraph); i!=INVALID; ++i)
1.498 + {
1.499 + if(arcsmap[i]->getLine()==active_item)
1.500 + {
1.501 + active_arc=i;
1.502 + }
1.503 + }
1.504 + }
1.505 +
1.506 + // return if the clicked object is neither an arc nor a node
1.507 + if (active_arc == INVALID) return false;
1.508 +
1.509 + //recolor activated item
1.510 + if(active_item)
1.511 + {
1.512 + *active_item << Gnome::Canvas::Properties::fill_color("red");
1.513 + }
1.514 + break;
1.515 +
1.516 + case GDK_BUTTON_RELEASE:
1.517 + window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
1.518 + if(active_item)
1.519 + {
1.520 + //the cursor was not moved since pressing it
1.521 + if( active_item == ( get_item_at (clicked_x, clicked_y) ) )
1.522 + {
1.523 + //a node was found
1.524 + if(active_node!=INVALID)
1.525 + {
1.526 + ms.setModified();
1.527 +
1.528 + std::set<Digraph::Arc> arcs_to_delete;
1.529 +
1.530 + for(OutArcIt e(ms.digraph,active_node);e!=INVALID;++e)
1.531 + {
1.532 + arcs_to_delete.insert(e);
1.533 + }
1.534 +
1.535 + for(InArcIt e(ms.digraph,active_node);e!=INVALID;++e)
1.536 + {
1.537 + arcs_to_delete.insert(e);
1.538 + }
1.539 +
1.540 + //deleting collected arcs
1.541 + for(std::set<Digraph::Arc>::iterator
1.542 + arc_set_it=arcs_to_delete.begin();
1.543 + arc_set_it!=arcs_to_delete.end();
1.544 + ++arc_set_it)
1.545 + {
1.546 + deleteItem(*arc_set_it);
1.547 + }
1.548 + deleteItem(active_node);
1.549 + }
1.550 + //a simple arc was chosen
1.551 + else if (active_arc != INVALID)
1.552 + {
1.553 + deleteItem(active_arc);
1.554 + }
1.555 + }
1.556 + //pointer was moved, deletion is cancelled
1.557 + else
1.558 + {
1.559 + if(active_node!=INVALID)
1.560 + {
1.561 + *active_item << Gnome::Canvas::Properties::fill_color("blue");
1.562 + }
1.563 + else if (active_arc != INVALID)
1.564 + {
1.565 + *active_item << Gnome::Canvas::Properties::fill_color("green");
1.566 + }
1.567 + }
1.568 + }
1.569 + //reseting datas
1.570 + active_item=NULL;
1.571 + active_arc=INVALID;
1.572 + active_node=INVALID;
1.573 + break;
1.574 +
1.575 + case GDK_MOTION_NOTIFY:
1.576 + break;
1.577 +
1.578 + default:
1.579 + break;
1.580 + }
1.581 + return false;
1.582 +}
1.583 +
1.584 +bool DigraphDisplayerCanvas::mapEditEventHandler(GdkEvent* e)
1.585 +{
1.586 + MapStorage& ms = *mytab.mapstorage;
1.587 +
1.588 + if(actual_tool==MAP_EDIT)
1.589 + {
1.590 + switch(e->type)
1.591 + {
1.592 + case GDK_BUTTON_PRESS:
1.593 + {
1.594 + //for determine, whether it was an arc
1.595 + Arc clicked_arc=INVALID;
1.596 + //for determine, whether it was a node
1.597 + Node clicked_node=INVALID;
1.598 +
1.599 + window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
1.600 + active_item=(get_item_at(clicked_x, clicked_y));
1.601 +
1.602 + //find the activated item between text of nodes
1.603 + for (NodeIt i(ms.digraph); i!=INVALID; ++i)
1.604 + {
1.605 + //at the same time only one can be active
1.606 + if(nodetextmap[i]==active_item)
1.607 + {
1.608 + clicked_node=i;
1.609 + }
1.610 + }
1.611 +
1.612 + //if there was not, search for it between nodes
1.613 + if(clicked_node==INVALID)
1.614 + {
1.615 + for (NodeIt i(ms.digraph); i!=INVALID; ++i)
1.616 + {
1.617 + //at the same time only one can be active
1.618 + if(nodesmap[i]==active_item)
1.619 + {
1.620 + clicked_node=i;
1.621 + }
1.622 + }
1.623 + }
1.624 +
1.625 + if(clicked_node==INVALID)
1.626 + {
1.627 + //find the activated item between texts
1.628 + for (ArcIt i(ms.digraph); i!=INVALID; ++i)
1.629 + {
1.630 + //at the same time only one can be active
1.631 + if(arctextmap[i]==active_item)
1.632 + {
1.633 + clicked_arc=i;
1.634 + }
1.635 + }
1.636 +
1.637 + //if it was not between texts, search for it between arcs
1.638 + if(clicked_arc==INVALID)
1.639 + {
1.640 + for (ArcIt i(ms.digraph); i!=INVALID; ++i)
1.641 + {
1.642 + //at the same time only one can be active
1.643 + if((arcsmap[i]->getLine())==active_item)
1.644 + {
1.645 + clicked_arc=i;
1.646 + }
1.647 + }
1.648 + }
1.649 + }
1.650 +
1.651 + //if it was really a node...
1.652 + if(clicked_node!=INVALID)
1.653 + {
1.654 + // the id map is not editable
1.655 + if (nodemap_to_edit == "label") return 0;
1.656 +
1.657 + //and there is activated map
1.658 + if(nodetextmap[clicked_node]->property_text().get_value()!="")
1.659 + {
1.660 + //activate the general variable for it
1.661 + active_node=clicked_node;
1.662 +
1.663 + //create a dialog
1.664 + Gtk::Dialog dialog("Edit value", true);
1.665 + dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1.666 + dialog.add_button(Gtk::Stock::OK, Gtk::RESPONSE_ACCEPT);
1.667 + Gtk::VBox* vbox = dialog.get_vbox();
1.668 +
1.669 + /*
1.670 + Gtk::SpinButton spin(0.0, 4);
1.671 + spin.set_increments(1.0, 10.0);
1.672 + spin.set_range(-1000000.0, 1000000.0);
1.673 + spin.set_numeric(true);
1.674 + spin.set_value(atof(nodetextmap[active_node]->property_text().get_value().c_str()));
1.675 + vbox->add(spin);
1.676 + spin.show();
1.677 + */
1.678 + Gtk::Entry entry;
1.679 + entry.set_text(nodetextmap[active_node]->property_text().get_value());
1.680 + vbox->add(entry);
1.681 + entry.show();
1.682 +
1.683 + switch (dialog.run())
1.684 + {
1.685 + case Gtk::RESPONSE_NONE:
1.686 + case Gtk::RESPONSE_CANCEL:
1.687 + break;
1.688 + case Gtk::RESPONSE_ACCEPT:
1.689 + switch (ms.getNodeMapElementType(nodemap_to_edit))
1.690 + {
1.691 + case MapValue::NUMERIC:
1.692 + ms.set(nodemap_to_edit, active_node,
1.693 + atof(entry.get_text().c_str()));
1.694 + break;
1.695 + case MapValue::STRING:
1.696 + ms.set(nodemap_to_edit, active_node,
1.697 + static_cast<std::string>(entry.get_text()));
1.698 + break;
1.699 + }
1.700 + nodetextmap[active_node]->property_text().set_value(
1.701 + static_cast<std::string>(ms.get(nodemap_to_edit, active_node)));
1.702 +
1.703 + //mapwin.updateNode(active_node);
1.704 + //mapwin.updateNode(Node(INVALID));
1.705 + propertyUpdate(Node(INVALID));
1.706 + }
1.707 + }
1.708 + }
1.709 + else
1.710 + //if it was really an arc...
1.711 + if(clicked_arc!=INVALID)
1.712 + {
1.713 + // the id map is not editable
1.714 + if (arcmap_to_edit == "label") return 0;
1.715 +
1.716 + //and there is activated map
1.717 + if(arctextmap[clicked_arc]->property_text().get_value()!="")
1.718 + {
1.719 + //activate the general variable for it
1.720 + active_arc=clicked_arc;
1.721 +
1.722 + //create a dialog
1.723 + Gtk::Dialog dialog("Edit value", true);
1.724 + dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1.725 + dialog.add_button(Gtk::Stock::OK, Gtk::RESPONSE_ACCEPT);
1.726 + Gtk::VBox* vbox = dialog.get_vbox();
1.727 +
1.728 + /*
1.729 + Gtk::SpinButton spin(0.0, 4);
1.730 + spin.set_increments(1.0, 10.0);
1.731 + spin.set_range(-1000000.0, 1000000.0);
1.732 + spin.set_numeric(true);
1.733 + spin.set_value(atof(arctextmap[active_arc]->property_text().get_value().c_str()));
1.734 + vbox->add(spin);
1.735 + spin.show();
1.736 + */
1.737 + Gtk::Entry entry;
1.738 + entry.set_text(arctextmap[active_arc]->property_text().get_value());
1.739 + vbox->add(entry);
1.740 + entry.show();
1.741 +
1.742 + std::cout << arcmap_to_edit << std::endl;
1.743 + switch (dialog.run())
1.744 + {
1.745 + case Gtk::RESPONSE_NONE:
1.746 + case Gtk::RESPONSE_CANCEL:
1.747 + break;
1.748 + case Gtk::RESPONSE_ACCEPT:
1.749 + switch (ms.getArcMapElementType(arcmap_to_edit))
1.750 + {
1.751 + case MapValue::NUMERIC:
1.752 + ms.set(arcmap_to_edit, active_arc,
1.753 + atof(entry.get_text().c_str()));
1.754 + break;
1.755 + case MapValue::STRING:
1.756 + ms.set(arcmap_to_edit, active_arc,
1.757 + static_cast<std::string>(entry.get_text()));
1.758 + break;
1.759 + }
1.760 + arctextmap[active_arc]->property_text().set_value(
1.761 + static_cast<std::string>(ms.get(arcmap_to_edit, active_arc)));
1.762 +
1.763 + //mapwin.updateArc(active_arc);
1.764 + // mapwin.updateArc(Arc(INVALID));
1.765 + propertyUpdate(Arc(INVALID));
1.766 + }
1.767 + }
1.768 + }
1.769 + break;
1.770 + }
1.771 + default:
1.772 + break;
1.773 + }
1.774 + }
1.775 + return false;
1.776 +}
1.777 +
1.778 +void DigraphDisplayerCanvas::deleteItem(Node node_to_delete)
1.779 +{
1.780 + delete(nodetextmap[node_to_delete]);
1.781 + delete(nodesmap[node_to_delete]);
1.782 + mytab.mapstorage->digraph.erase(node_to_delete);
1.783 +}
1.784 +
1.785 +void DigraphDisplayerCanvas::deleteItem(Arc arc_to_delete)
1.786 +{
1.787 + delete(arctextmap[arc_to_delete]);
1.788 + delete(arcsmap[arc_to_delete]);
1.789 + mytab.mapstorage->digraph.erase(arc_to_delete);
1.790 +}
1.791 +
1.792 +void DigraphDisplayerCanvas::textReposition(XY new_place)
1.793 +{
1.794 + new_place+=(XY(10,10));
1.795 + arctextmap[forming_arc]->property_x().set_value(new_place.x);
1.796 + arctextmap[forming_arc]->property_y().set_value(new_place.y);
1.797 +}
1.798 +
1.799 +void DigraphDisplayerCanvas::toggleArcActivity(ArcBase* active_bre, bool on)
1.800 +{
1.801 + if(on)
1.802 + {
1.803 + if(forming_arc!=INVALID)
1.804 + {
1.805 + std::cerr << "ERROR!!!! Valid arc found!" << std::endl;
1.806 + }
1.807 + else
1.808 + {
1.809 + for (ArcIt i(mytab.mapstorage->digraph); i!=INVALID; ++i)
1.810 + {
1.811 + if(arcsmap[i]==active_bre)
1.812 + {
1.813 + forming_arc=i;
1.814 + }
1.815 + }
1.816 + }
1.817 + }
1.818 + else
1.819 + {
1.820 + if(forming_arc!=INVALID)
1.821 + {
1.822 + forming_arc=INVALID;
1.823 + }
1.824 + else
1.825 + {
1.826 + std::cerr << "ERROR!!!! Invalid arc found!" << std::endl;
1.827 + }
1.828 + }
1.829 +}
1.830 +
1.831 +void DigraphDisplayerCanvas::moveNode(double dx, double dy, Gnome::Canvas::Item * item, Node node)
1.832 +{
1.833 + MapStorage& ms = *mytab.mapstorage;
1.834 +
1.835 + Gnome::Canvas::Item * moved_item=item;
1.836 + Node moved_node=node;
1.837 +
1.838 + if(item==NULL && node==INVALID)
1.839 + {
1.840 + moved_item=active_item;
1.841 + moved_node=active_node;
1.842 + }
1.843 + else
1.844 + {
1.845 + isbutton=1;
1.846 + }
1.847 +
1.848 + //repositioning node and its text
1.849 + moved_item->move(dx, dy);
1.850 + nodetextmap[moved_node]->move(dx, dy);
1.851 +
1.852 + // the new coordinates of the centre of the node
1.853 + double coord_x = dx + ms.getNodeCoords(moved_node).x;
1.854 + double coord_y = dy + ms.getNodeCoords(moved_node).y;
1.855 +
1.856 + // write back the new coordinates to the coords map
1.857 + ms.setNodeCoords(moved_node, XY(coord_x, coord_y));
1.858 +
1.859 + //all the arcs connected to the moved point has to be redrawn
1.860 + for(OutArcIt ei(ms.digraph,moved_node);ei!=INVALID;++ei)
1.861 + {
1.862 + XY arrow_pos;
1.863 +
1.864 + if (ms.digraph.source(ei) == ms.digraph.target(ei))
1.865 + {
1.866 + arrow_pos = ms.getArrowCoords(ei) + XY(dx, dy);
1.867 + }
1.868 + else
1.869 + {
1.870 + XY moved_node_1(coord_x - dx, coord_y - dy);
1.871 + XY moved_node_2(coord_x, coord_y);
1.872 + Node target = ms.digraph.target(ei);
1.873 + XY fix_node = ms.getNodeCoords(target);
1.874 + XY old_arrow_pos(ms.getArrowCoords(ei));
1.875 +
1.876 + arrow_pos = calcArrowPos(moved_node_1, moved_node_2, fix_node, old_arrow_pos, isbutton);
1.877 + }
1.878 +
1.879 + ms.setArrowCoords(ei, arrow_pos);
1.880 + arcsmap[ei]->draw();
1.881 +
1.882 + //reposition of arctext
1.883 + XY text_pos=ms.getArrowCoords(ei);
1.884 + text_pos+=(XY(10,10));
1.885 + arctextmap[ei]->property_x().set_value(text_pos.x);
1.886 + arctextmap[ei]->property_y().set_value(text_pos.y);
1.887 + }
1.888 +
1.889 + for(InArcIt ei(ms.digraph,moved_node);ei!=INVALID;++ei)
1.890 + {
1.891 + if (ms.digraph.source(ei) != ms.digraph.target(ei))
1.892 + {
1.893 + XY moved_node_1(coord_x - dx, coord_y - dy);
1.894 + XY moved_node_2(coord_x, coord_y);
1.895 + Node source = ms.digraph.source(ei);
1.896 + XY fix_node = ms.getNodeCoords(source);
1.897 + XY old_arrow_pos(ms.getArrowCoords(ei));
1.898 +
1.899 + XY arrow_pos;
1.900 + arrow_pos = calcArrowPos(moved_node_1, moved_node_2, fix_node, old_arrow_pos, isbutton);
1.901 +
1.902 + ms.setArrowCoords(ei, arrow_pos);
1.903 + arcsmap[ei]->draw();
1.904 +
1.905 + //reposition of arctext
1.906 + XY text_pos=ms.getArrowCoords(ei);
1.907 + text_pos+=(XY(10,10));
1.908 + arctextmap[ei]->property_x().set_value(text_pos.x);
1.909 + arctextmap[ei]->property_y().set_value(text_pos.y);
1.910 + }
1.911 + }
1.912 +}
1.913 +
1.914 +Gdk::Color DigraphDisplayerCanvas::rainbowColorCounter(double min, double max, double w)
1.915 +{
1.916 + Gdk::Color color;
1.917 +
1.918 + double pos=(w-min)/(max-min);
1.919 + int phase=0;
1.920 +
1.921 + //rainbow transitions contain 6 phase
1.922 + //in each phase only one color is changed
1.923 + //first we determine the phase, in which
1.924 + //the actual value belongs to
1.925 + for (int i=0;i<=5;i++)
1.926 + {
1.927 + if(((double)i/6<pos)&&(pos<=(double(i+1)/6)))
1.928 + {
1.929 + phase=i;
1.930 + }
1.931 + }
1.932 + if(phase<6)
1.933 + {
1.934 + //within its 1/6 long phase the relativ position
1.935 + //determines the power of the color changed in
1.936 + //that phase
1.937 + //we normalize that to one, to be able to give percentage
1.938 + //value for the function
1.939 + double rel_pos=(pos-(phase/6.0))*6.0;
1.940 +
1.941 + switch(phase)
1.942 + {
1.943 + case 0:
1.944 + color.set_rgb_p (1, 0, 1-rel_pos);
1.945 + break;
1.946 + case 1:
1.947 + color.set_rgb_p (1, rel_pos, 0);
1.948 + break;
1.949 + case 2:
1.950 + color.set_rgb_p (1-rel_pos, 1, 0);
1.951 + break;
1.952 + case 3:
1.953 + color.set_rgb_p (0, 1, rel_pos);
1.954 + break;
1.955 + case 4:
1.956 + color.set_rgb_p (0, 1-rel_pos, 1);
1.957 + break;
1.958 + case 5:
1.959 + color.set_rgb_p ((rel_pos/3.0), 0, 1);
1.960 + break;
1.961 + default:
1.962 + std::cout << "Wrong phase: " << phase << " " << pos << std::endl;
1.963 + }
1.964 + }
1.965 + else
1.966 + {
1.967 + std::cout << "Wrong phase: " << phase << " " << pos << std::endl;
1.968 + }
1.969 + return color;
1.970 +}