graph_displayer_canvas-event.cc
changeset 1 67188bd752db
     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 +}