graph_displayer_canvas-event.cc
author alpar
Mon, 30 Oct 2006 12:16:25 +0000
changeset 174 95872af46fc4
parent 160 14a76109b561
child 178 a96d2a540454
permissions -rwxr-xr-x
Add copyright headers
     1 /* -*- C++ -*-
     2  *
     3  * This file is a part of LEMON, a generic C++ optimization library
     4  *
     5  * Copyright (C) 2003-2006
     6  * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
     7  * (Egervary Research Group on Combinatorial Optimization, EGRES).
     8  *
     9  * Permission to use, modify and distribute this software is granted
    10  * provided that this copyright notice appears in all copies. For
    11  * precise terms see the accompanying LICENSE file.
    12  *
    13  * This software is provided "AS IS" with no warranty of any kind,
    14  * express or implied, and with no claim as to its suitability for any
    15  * purpose.
    16  *
    17  */
    18 
    19 #include "graph_displayer_canvas.h"
    20 #include <cmath>
    21 
    22 
    23 bool GraphDisplayerCanvas::on_expose_event(GdkEventExpose *event)
    24 {
    25   Gnome::Canvas::CanvasAA::on_expose_event(event);
    26   //usleep(10000);
    27   //rezoom();
    28   return true;
    29 }
    30 
    31 void GraphDisplayerCanvas::changeEditorialTool(int newtool)
    32 {
    33   if(actual_tool!=newtool)
    34     {
    35 
    36       actual_handler.disconnect();
    37 
    38       switch(actual_tool)
    39 	{
    40 	case CREATE_EDGE:
    41 	  {
    42 	    GdkEvent * generated=new GdkEvent();
    43 	    generated->type=GDK_BUTTON_RELEASE;
    44 	    generated->button.button=3;
    45 	    createEdgeEventHandler(generated);      
    46 	    break;
    47 	  }
    48 	case MAP_EDIT:
    49 	  {
    50 	    break;
    51 	  }
    52 	default:
    53 	  break;
    54 	}
    55 
    56       active_item=NULL; 
    57       target_item=NULL; 
    58       active_edge=INVALID;	
    59       active_node=INVALID;	
    60 
    61 
    62       actual_tool=newtool;
    63   
    64       switch(newtool)
    65 	{
    66 	case MOVE:
    67 	  actual_handler=signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::moveEventHandler), false);
    68 	  break;
    69 
    70 	case CREATE_NODE:
    71 	  actual_handler=signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::createNodeEventHandler), false);
    72 	  break;
    73 
    74 	case CREATE_EDGE:
    75 	  actual_handler=signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::createEdgeEventHandler), false);
    76 	  break;
    77 
    78 	case ERASER:
    79 	  actual_handler=signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::eraserEventHandler), false);
    80 	  break;
    81 
    82 	case MAP_EDIT:
    83 	  grab_focus();
    84 	  actual_handler=signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::mapEditEventHandler), false);
    85 	  break;
    86 
    87 	default:
    88 	  break;
    89 	}
    90     }
    91 }
    92 
    93 int GraphDisplayerCanvas::getActualTool()
    94 {
    95   return actual_tool;
    96 }
    97 
    98 bool GraphDisplayerCanvas::moveEventHandler(GdkEvent* e)
    99 {
   100   static Gnome::Canvas::Text *coord_text = 0;
   101   switch(e->type)
   102     {
   103     case GDK_BUTTON_PRESS:
   104       //we mark the location of the event to be able to calculate parameters of dragging
   105       window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
   106       
   107       active_item=(get_item_at(clicked_x, clicked_y));
   108       active_node=INVALID;
   109       for (NodeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
   110 	{
   111 	  if(nodesmap[i]==active_item)
   112 	    {
   113 	      active_node=i;
   114 	    }
   115 	}
   116       isbutton=e->button.button;
   117       break;
   118     case GDK_BUTTON_RELEASE:
   119       if (coord_text)
   120 	{
   121 	  delete coord_text;
   122 	  coord_text = 0;
   123 	}
   124       isbutton=0;
   125       active_item=NULL;
   126       active_node=INVALID;
   127       break;
   128     case GDK_MOTION_NOTIFY:
   129       //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
   130       if(active_node!=INVALID)
   131 	{
   132 	  (mytab.mapstorage).modified = true;
   133 	  
   134 	  //new coordinates will be the old values,
   135 	  //because the item will be moved to the
   136 	  //new coordinate therefore the new movement
   137 	  //has to be calculated from here
   138 	  
   139 	  double new_x, new_y;
   140 	  
   141 	  window_to_world (e->motion.x, e->motion.y, new_x, new_y);
   142 	  
   143 	  double dx=new_x-clicked_x;
   144 	  double dy=new_y-clicked_y;
   145 	  
   146 	  moveNode(dx, dy);
   147 
   148 	  clicked_x=new_x;
   149 	  clicked_y=new_y;
   150 
   151 	  // reposition the coordinates text
   152 	  std::ostringstream ostr;
   153 	  ostr << "(" <<
   154 	    (mytab.mapstorage).coords[active_node].x << ", " <<
   155 	    (mytab.mapstorage).coords[active_node].y << ")";
   156 	  double radius =
   157 	    (nodesmap[active_node]->property_x2().get_value() -
   158 	     nodesmap[active_node]->property_x1().get_value()) / 2.0;
   159 	  if (coord_text)
   160 	    {
   161 	      coord_text->property_text().set_value(ostr.str());
   162 	      coord_text->property_x().set_value((mytab.mapstorage).coords[active_node].x +
   163 						 radius);
   164 	      coord_text->property_y().set_value((mytab.mapstorage).coords[active_node].y -
   165 						 radius);
   166 	    }
   167 	  else
   168 	    {
   169 	      coord_text = new Gnome::Canvas::Text(
   170 						   displayed_graph,
   171 						   (mytab.mapstorage).coords[active_node].x + radius,
   172 						   (mytab.mapstorage).coords[active_node].y - radius,
   173 						   ostr.str());
   174 	      coord_text->property_fill_color().set_value("black");
   175 	      coord_text->property_anchor().set_value(Gtk::ANCHOR_SOUTH_WEST);
   176 	    }
   177 
   178 
   179 	}
   180     default: break;
   181     }
   182 
   183 return false;
   184 }
   185 
   186 XY GraphDisplayerCanvas::calcArrowPos(XY moved_node_1, XY moved_node_2, XY fix_node, XY old_arrow_pos, int move_code)
   187 {
   188   switch(move_code)
   189     {
   190     case 1:
   191       return XY((moved_node_2.x + fix_node.x) / 2.0, (moved_node_2.y + fix_node.y) / 2.0);
   192       break;
   193     case 2:
   194       return old_arrow_pos;
   195       break;
   196     case 3:
   197       {
   198 	//////////////////////////////////////////////////////////////////////////////////////////////////////
   199 	/////////// keeps shape-with scalar multiplication - version 2.
   200 	//////////////////////////////////////////////////////////////////////////////////////////////////////
   201 
   202 	//old vector from one to the other node - a
   203 	XY a_v(moved_node_1.x-fix_node.x,moved_node_1.y-fix_node.y);
   204 	//new vector from one to the other node - b
   205 	XY b_v(moved_node_2.x-fix_node.x,moved_node_2.y-fix_node.y);
   206 
   207 	double absa=sqrt(a_v.normSquare());
   208 	double absb=sqrt(b_v.normSquare());
   209 
   210 	if ((absa == 0.0) || (absb == 0.0))
   211 	  {
   212 	    return old_arrow_pos;
   213 	  }
   214 	else
   215 	  {
   216 	    //old vector from one node to the breakpoint - c
   217 	    XY c_v(old_arrow_pos.x-fix_node.x,old_arrow_pos.y-fix_node.y);
   218 
   219 	    //unit vector with the same direction to a_v
   220 	    XY a_v_u(a_v.x/absa,a_v.y/absa);
   221 
   222 	    //normal vector of unit vector with the same direction to a_v
   223 	    XY a_v_u_n(((-1)*a_v_u.y),a_v_u.x);
   224 
   225 	    //unit vector with the same direction to b_v
   226 	    XY b_v_u(b_v.x/absb,b_v.y/absb);
   227 
   228 	    //normal vector of unit vector with the same direction to b_v
   229 	    XY b_v_u_n(((-1)*b_v_u.y),b_v_u.x);
   230 
   231 	    //vector c in a_v_u and a_v_u_n co-ordinate system
   232 	    XY c_a(c_v*a_v_u,c_v*a_v_u_n);
   233 
   234 	    //new vector from one node to the breakpoint - d - we have to calculate this one
   235 	    XY d_v=absb/absa*(c_a.x*b_v_u+c_a.y*b_v_u_n);
   236 
   237 	    return XY(d_v.x+fix_node.x,d_v.y+fix_node.y);
   238 	  }
   239 	break;
   240       }
   241     default:
   242       break;
   243     }
   244 }
   245 
   246 
   247 bool GraphDisplayerCanvas::createNodeEventHandler(GdkEvent* e)
   248 {
   249   switch(e->type)
   250   {
   251     //move the new node
   252     case GDK_MOTION_NOTIFY:
   253       {
   254         GdkEvent * generated=new GdkEvent();
   255         generated->motion.x=e->motion.x;
   256         generated->motion.y=e->motion.y;
   257         generated->type=GDK_MOTION_NOTIFY;
   258         moveEventHandler(generated);      
   259         break;
   260       }
   261 
   262     case GDK_BUTTON_RELEASE:
   263       (mytab.mapstorage).modified = true;
   264 
   265       isbutton=1;
   266 
   267       active_node=(mytab.mapstorage).graph.addNode();
   268 
   269       //initiating values corresponding to new node in maps
   270 
   271       window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
   272 
   273       // update coordinates
   274       (mytab.mapstorage).coords.set(active_node, XY(clicked_x, clicked_y));
   275 
   276       // update all other maps
   277       for (std::map<std::string, Graph::NodeMap<double>*>::const_iterator it =
   278           (mytab.mapstorage).nodemap_storage.begin(); it !=
   279           (mytab.mapstorage).nodemap_storage.end(); ++it)
   280       {
   281         if ((it->first != "coordinates_x") &&
   282             (it->first != "coordinates_y"))
   283         {
   284           (*(it->second))[active_node] =
   285             (mytab.mapstorage).nodemap_default[it->first];
   286         }
   287       }
   288       // increment the id map's default value
   289       (mytab.mapstorage).nodemap_default["label"] += 1.0;
   290 
   291       nodesmap[active_node]=new Gnome::Canvas::Ellipse(displayed_graph,
   292           clicked_x-20, clicked_y-20, clicked_x+20, clicked_y+20);
   293       active_item=(Gnome::Canvas::Item *)(nodesmap[active_node]);
   294       *(nodesmap[active_node]) <<
   295         Gnome::Canvas::Properties::fill_color("blue");
   296       *(nodesmap[active_node]) <<
   297         Gnome::Canvas::Properties::outline_color("black");
   298       active_item->raise_to_top();
   299 
   300       (nodesmap[active_node])->show();
   301 
   302       nodetextmap[active_node]=new Gnome::Canvas::Text(displayed_graph,
   303           clicked_x+node_property_defaults[N_RADIUS]+5,
   304           clicked_y+node_property_defaults[N_RADIUS]+5, "");
   305       nodetextmap[active_node]->property_fill_color().set_value("darkblue");
   306       nodetextmap[active_node]->raise_to_top();
   307 
   308 //       mapwin.updateNode(active_node);
   309       propertyUpdate(active_node);
   310 
   311       isbutton=0;
   312       target_item=NULL;
   313       active_item=NULL;
   314       active_node=INVALID;
   315       break;
   316     default:
   317       break;
   318   }
   319   return false;
   320 }
   321 
   322 bool GraphDisplayerCanvas::createEdgeEventHandler(GdkEvent* e)
   323 {
   324   switch(e->type)
   325   {
   326     case GDK_BUTTON_PRESS:
   327       //in edge creation right button has special meaning
   328       if(e->button.button!=3)
   329       {
   330         //there is not yet selected node
   331         if(active_node==INVALID)
   332         {
   333           //we mark the location of the event to be able to calculate parameters of dragging
   334 
   335           window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
   336 
   337           active_item=(get_item_at(clicked_x, clicked_y));
   338           active_node=INVALID;
   339           for (NodeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
   340           {
   341             if(nodesmap[i]==active_item)
   342             {
   343               active_node=i;
   344             }
   345           }
   346           //the clicked item is really a node
   347           if(active_node!=INVALID)
   348           {
   349             *(nodesmap[active_node]) << Gnome::Canvas::Properties::fill_color("red");
   350             isbutton=1;
   351           }
   352           //clicked item was not a node. It could be e.g. edge.
   353           else
   354           {
   355             active_item=NULL;
   356           }
   357         }
   358         //we only have to do sg. if the mouse button
   359         // is pressed already once AND the click was
   360         // on a node that was found in the set of 
   361         //nodes, and now we only search for the second 
   362         //node
   363         else
   364         {
   365           window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
   366           target_item=(get_item_at(clicked_x, clicked_y));
   367           Node target_node=INVALID;
   368           for (NodeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
   369           {
   370             if(nodesmap[i]==target_item)
   371             {
   372               target_node=i;
   373             }
   374           }
   375           //the clicked item is a node, the edge can be drawn
   376           if(target_node!=INVALID)
   377           {
   378             (mytab.mapstorage).modified = true;
   379 
   380             *(nodesmap[target_node]) <<
   381               Gnome::Canvas::Properties::fill_color("red");
   382 
   383             //creating new edge
   384             active_edge=(mytab.mapstorage).graph.addEdge(active_node,
   385                 target_node);
   386 
   387             // update maps
   388             for (std::map<std::string,
   389                 Graph::EdgeMap<double>*>::const_iterator it =
   390                 (mytab.mapstorage).edgemap_storage.begin(); it !=
   391                 (mytab.mapstorage).edgemap_storage.end(); ++it)
   392             {
   393               (*(it->second))[active_edge] =
   394                 (mytab.mapstorage).edgemap_default[it->first];
   395             }
   396             // increment the id map's default value
   397             (mytab.mapstorage).edgemap_default["label"] += 1.0;
   398 
   399             if(target_node!=active_node)		
   400             {
   401               // set the coordinates of the arrow on the new edge
   402               MapStorage& ms = mytab.mapstorage;
   403               ms.arrow_pos.set(active_edge,
   404                   (ms.coords[ms.graph.source(active_edge)] +
   405                    ms.coords[ms.graph.target(active_edge)])/ 2.0);
   406 
   407               //drawing new edge
   408               edgesmap[active_edge]=new BrokenEdge(displayed_graph, active_edge,
   409                   *this);
   410             }
   411             else
   412             {
   413               // set the coordinates of the arrow on the new edge
   414               MapStorage& ms = mytab.mapstorage;
   415               ms.arrow_pos.set(active_edge,
   416                   (ms.coords[ms.graph.source(active_edge)] +
   417                    XY(0.0, 80.0)));
   418 
   419               //drawing new edge
   420               edgesmap[active_edge]=new LoopEdge(displayed_graph, active_edge,
   421                   *this);
   422             }
   423 
   424             //initializing edge-text as well, to empty string
   425             XY text_pos=mytab.mapstorage.arrow_pos[active_edge];
   426             text_pos+=(XY(10,10));
   427 
   428             edgetextmap[active_edge]=new Gnome::Canvas::Text(displayed_graph,
   429                 text_pos.x, text_pos.y, "");
   430             edgetextmap[active_edge]->property_fill_color().set_value(
   431                 "darkgreen");
   432             edgetextmap[active_edge]->raise_to_top();
   433 
   434             propertyUpdate(active_edge);
   435           }
   436           //clicked item was not a node. it could be an e.g. edge. we do not
   437           //deal with it furthermore.
   438           else
   439           {
   440             target_item=NULL;
   441           }
   442         }
   443       }
   444       break;
   445     case GDK_BUTTON_RELEASE:
   446       isbutton=0;
   447       //we clear settings in two cases
   448       //1: the edge is ready (target_item has valid value)
   449       //2: the edge creation is cancelled with right button
   450       if((target_item)||(e->button.button==3))
   451       {
   452         if(active_item)
   453         {
   454           *active_item << Gnome::Canvas::Properties::fill_color("blue");
   455           active_item=NULL;
   456         }
   457         if(target_item)
   458         {
   459           *target_item << Gnome::Canvas::Properties::fill_color("blue");
   460           target_item=NULL;
   461         }
   462         active_node=INVALID;
   463         active_edge=INVALID;
   464       }
   465       break;
   466     default:
   467       break;
   468   }
   469   return false;
   470 }
   471 
   472 bool GraphDisplayerCanvas::eraserEventHandler(GdkEvent* e)
   473 {
   474   switch(e->type)
   475     {
   476     case GDK_BUTTON_PRESS:
   477       //finding the clicked items
   478       window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
   479       active_item=(get_item_at(clicked_x, clicked_y));
   480       active_node=INVALID;
   481       active_edge=INVALID;
   482       //was it a node?
   483       for (NodeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
   484 	{
   485 	  if(nodesmap[i]==active_item)
   486 	    {
   487 	      active_node=i;
   488 	    }
   489 	}
   490       //or was it an edge?
   491       if(active_node==INVALID)
   492 	{
   493 	  for (EdgeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
   494 	    {
   495 	      if(edgesmap[i]->getLine()==active_item)
   496 		{
   497 		  active_edge=i;
   498 		}
   499 	    }
   500 	}
   501 
   502       // return if the clicked object is neither an edge nor a node
   503       if (active_edge == INVALID) return false;
   504       
   505       //recolor activated item
   506       if(active_item)
   507 	{
   508 	  *active_item << Gnome::Canvas::Properties::fill_color("red");
   509 	}
   510       break;
   511 
   512     case GDK_BUTTON_RELEASE:
   513       window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
   514       if(active_item)
   515 	{
   516 	  //the cursor was not moved since pressing it
   517 	  if( active_item == ( get_item_at (clicked_x, clicked_y) ) )
   518 	    {
   519 	      //a node was found
   520 	      if(active_node!=INVALID)
   521 		{
   522                   (mytab.mapstorage).modified = true;
   523 
   524 		  std::set<Graph::Edge> edges_to_delete;
   525 
   526 		  for(OutEdgeIt e((mytab.mapstorage).graph,active_node);e!=INVALID;++e)
   527 		    {
   528 		      edges_to_delete.insert(e);
   529 		    }
   530 		  
   531 		  for(InEdgeIt e((mytab.mapstorage).graph,active_node);e!=INVALID;++e)
   532 		    {
   533 		      edges_to_delete.insert(e);
   534 		    }
   535 		  
   536 		  //deleting collected edges
   537 		  for(std::set<Graph::Edge>::iterator
   538 			edge_set_it=edges_to_delete.begin();
   539 		      edge_set_it!=edges_to_delete.end();
   540 		      ++edge_set_it)
   541 		    {
   542 		      deleteItem(*edge_set_it);
   543 		    }
   544 		  deleteItem(active_node);
   545 		}
   546 	      //a simple edge was chosen
   547 	      else if (active_edge != INVALID)
   548 		{
   549 		  deleteItem(active_edge);
   550 		}
   551 	    }
   552 	  //pointer was moved, deletion is cancelled
   553 	  else
   554 	    {
   555 	      if(active_node!=INVALID)
   556 		{
   557 		  *active_item << Gnome::Canvas::Properties::fill_color("blue");
   558 		}
   559 	      else if (active_edge != INVALID)
   560 		{
   561 		  *active_item << Gnome::Canvas::Properties::fill_color("green");
   562 		}
   563 	    }
   564 	}
   565       //reseting datas
   566       active_item=NULL;
   567       active_edge=INVALID;
   568       active_node=INVALID;
   569       break;
   570 
   571     case GDK_MOTION_NOTIFY:
   572       break;
   573 
   574     default:
   575       break;
   576     }
   577   return false;
   578 }
   579 
   580 bool GraphDisplayerCanvas::mapEditEventHandler(GdkEvent* e)
   581 {
   582   if(actual_tool==MAP_EDIT)
   583     {
   584       switch(e->type)
   585 	{
   586 	case GDK_BUTTON_PRESS:
   587 	  {
   588 	    //for determine, whether it was an edge
   589 	    Edge clicked_edge=INVALID;
   590 	    //for determine, whether it was a node
   591 	    Node clicked_node=INVALID;
   592 
   593 	    window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
   594 	    active_item=(get_item_at(clicked_x, clicked_y));
   595 
   596 	    //find the activated item between text of nodes
   597 	    for (NodeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
   598 	      {
   599 		//at the same time only one can be active
   600 		if(nodetextmap[i]==active_item)
   601 		  {
   602 		    clicked_node=i;
   603 		  }
   604 	      }
   605 
   606 	    //if there was not, search for it between nodes
   607 	    if(clicked_node==INVALID)
   608 	      {
   609 		for (NodeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
   610 		  {
   611 		    //at the same time only one can be active
   612 		    if(nodesmap[i]==active_item)
   613 		      {
   614 			clicked_node=i;
   615 		      }
   616 		  }
   617 	      }
   618 
   619 	    if(clicked_node==INVALID)
   620 	      {
   621 		//find the activated item between texts
   622 		for (EdgeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
   623 		  {
   624 		    //at the same time only one can be active
   625 		    if(edgetextmap[i]==active_item)
   626 		      {
   627 			clicked_edge=i;
   628 		      }
   629 		  }
   630 
   631 		//if it was not between texts, search for it between edges
   632 		if(clicked_edge==INVALID)
   633 		  {
   634 		    for (EdgeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
   635 		      {
   636 			//at the same time only one can be active
   637 			if((edgesmap[i]->getLine())==active_item)
   638 			  {
   639 			    clicked_edge=i;
   640 			  }
   641 		      }
   642 		  }
   643 	      }
   644 
   645 	    //if it was really a node...
   646 	    if(clicked_node!=INVALID)
   647 	      {
   648 		// the id map is not editable
   649 		if (nodemap_to_edit == "label") return 0;
   650 
   651 		//and there is activated map
   652 		if(nodetextmap[clicked_node]->property_text().get_value()!="")
   653 		  {
   654 		    //activate the general variable for it
   655 		    active_node=clicked_node;
   656 
   657 		    //create a dialog
   658 		    Gtk::Dialog dialog("Edit value", true);
   659 		    dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
   660 		    dialog.add_button(Gtk::Stock::OK, Gtk::RESPONSE_ACCEPT);
   661 		    Gtk::VBox* vbox = dialog.get_vbox();
   662 		    Gtk::SpinButton spin(0.0, 4);
   663 		    spin.set_increments(1.0, 10.0);
   664 		    spin.set_range(-1000000.0, 1000000.0);
   665 		    spin.set_numeric(true);
   666 		    spin.set_value(atof(nodetextmap[active_node]->property_text().get_value().c_str()));
   667 		    vbox->add(spin);
   668 		    spin.show();
   669 		    switch (dialog.run())
   670 		      {
   671 		      case Gtk::RESPONSE_NONE:
   672 		      case Gtk::RESPONSE_CANCEL:
   673 			break;
   674 		      case Gtk::RESPONSE_ACCEPT:
   675 			double new_value = spin.get_value();
   676 			(*(mytab.mapstorage).nodemap_storage[nodemap_to_edit])[active_node] =
   677 			  new_value;
   678 			std::ostringstream ostr;
   679 			ostr << new_value;
   680 			nodetextmap[active_node]->property_text().set_value(ostr.str());
   681 			//mapwin.updateNode(active_node);
   682 			//mapwin.updateNode(Node(INVALID));
   683 			propertyUpdate(Node(INVALID));
   684 		      }
   685 		  }
   686 	      }
   687 	    else
   688 	      //if it was really an edge...
   689 	      if(clicked_edge!=INVALID)
   690 		{
   691 		  // the id map is not editable
   692 		  if (edgemap_to_edit == "label") return 0;
   693 
   694 		  //and there is activated map
   695 		  if(edgetextmap[clicked_edge]->property_text().get_value()!="")
   696 		    {
   697 		      //activate the general variable for it
   698 		      active_edge=clicked_edge;
   699 
   700 		      //create a dialog
   701 		      Gtk::Dialog dialog("Edit value", true);
   702 		      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
   703 		      dialog.add_button(Gtk::Stock::OK, Gtk::RESPONSE_ACCEPT);
   704 		      Gtk::VBox* vbox = dialog.get_vbox();
   705 		      Gtk::SpinButton spin(0.0, 4);
   706 		      spin.set_increments(1.0, 10.0);
   707 		      spin.set_range(-1000000.0, 1000000.0);
   708 		      spin.set_numeric(true);
   709 		      spin.set_value(atof(edgetextmap[active_edge]->property_text().get_value().c_str()));
   710 		      vbox->add(spin);
   711 		      spin.show();
   712 		      switch (dialog.run())
   713 			{
   714 			case Gtk::RESPONSE_NONE:
   715 			case Gtk::RESPONSE_CANCEL:
   716 			  break;
   717 			case Gtk::RESPONSE_ACCEPT:
   718 			  double new_value = spin.get_value();
   719 			  (*(mytab.mapstorage).edgemap_storage[edgemap_to_edit])[active_edge] =
   720 			    new_value;
   721 			  std::ostringstream ostr;
   722 			  ostr << new_value;
   723 			  edgetextmap[active_edge]->property_text().set_value(
   724 									      ostr.str());
   725 			  //mapwin.updateEdge(active_edge);
   726 			  //                   mapwin.updateEdge(Edge(INVALID));
   727 			  propertyUpdate(Edge(INVALID));
   728 			}
   729 		    }
   730 		}
   731 	    break;
   732 	  }
   733 	default:
   734 	  break;
   735 	}
   736     }
   737   return false;  
   738 }
   739 
   740 void GraphDisplayerCanvas::deleteItem(Node node_to_delete)
   741 {
   742   delete(nodetextmap[node_to_delete]);
   743   delete(nodesmap[node_to_delete]);
   744   (mytab.mapstorage).graph.erase(node_to_delete);
   745 }
   746 
   747 void GraphDisplayerCanvas::deleteItem(Edge edge_to_delete)
   748 {
   749   delete(edgetextmap[edge_to_delete]);
   750   delete(edgesmap[edge_to_delete]);
   751   (mytab.mapstorage).graph.erase(edge_to_delete);
   752 }
   753 
   754 void GraphDisplayerCanvas::textReposition(XY new_place)
   755 {
   756   new_place+=(XY(10,10));
   757   edgetextmap[forming_edge]->property_x().set_value(new_place.x);
   758   edgetextmap[forming_edge]->property_y().set_value(new_place.y);
   759 }
   760 
   761 void GraphDisplayerCanvas::toggleEdgeActivity(EdgeBase* active_bre, bool on)
   762 {
   763   if(on)
   764   {
   765     if(forming_edge!=INVALID)
   766     {
   767       std::cerr << "ERROR!!!! Valid edge found!" << std::endl;
   768     }
   769     else
   770     {
   771       for (EdgeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
   772       {
   773         if(edgesmap[i]==active_bre)
   774         {
   775           forming_edge=i;
   776         }
   777       }
   778     }
   779   }
   780   else
   781     {
   782       if(forming_edge!=INVALID)
   783 	{
   784 	  forming_edge=INVALID;
   785 	}
   786       else
   787 	{
   788 	  std::cerr << "ERROR!!!! Invalid edge found!" << std::endl;
   789 	}
   790     }
   791 }
   792 
   793 void GraphDisplayerCanvas::moveNode(double dx, double dy, Gnome::Canvas::Item * item, Node node)
   794 {
   795   Gnome::Canvas::Item * moved_item=item;
   796   Node moved_node=node;
   797 
   798   if(item==NULL && node==INVALID)
   799     {
   800       moved_item=active_item;
   801       moved_node=active_node;
   802     }
   803   else
   804     {
   805       isbutton=1;
   806     }
   807 
   808   //repositioning node and its text
   809   moved_item->move(dx, dy);
   810   nodetextmap[moved_node]->move(dx, dy);
   811 
   812   // the new coordinates of the centre of the node 
   813   double coord_x = dx + (mytab.mapstorage).coords[moved_node].x;
   814   double coord_y = dy + (mytab.mapstorage).coords[moved_node].y;
   815 
   816   // write back the new coordinates to the coords map
   817   (mytab.mapstorage).coords.set(moved_node, XY(coord_x, coord_y));
   818 
   819   //all the edges connected to the moved point has to be redrawn
   820   for(OutEdgeIt ei((mytab.mapstorage).graph,moved_node);ei!=INVALID;++ei)
   821     {
   822       XY arrow_pos;
   823 
   824       if (mytab.mapstorage.graph.source(ei) == mytab.mapstorage.graph.target(ei))
   825 	{
   826 	  arrow_pos = mytab.mapstorage.arrow_pos[ei] + XY(dx, dy);
   827 	}
   828       else
   829 	{
   830 	  XY moved_node_1(coord_x - dx, coord_y - dy);
   831 	  XY moved_node_2(coord_x, coord_y);
   832 	  Node target = mytab.mapstorage.graph.target(ei);
   833 	  XY fix_node(mytab.mapstorage.coords[target].x,
   834 		      mytab.mapstorage.coords[target].y);
   835 	  XY old_arrow_pos(mytab.mapstorage.arrow_pos[ei]);
   836 
   837 	  arrow_pos = calcArrowPos(moved_node_1, moved_node_2, fix_node, old_arrow_pos, isbutton);
   838 	}
   839 
   840       mytab.mapstorage.arrow_pos.set(ei, arrow_pos);
   841       edgesmap[ei]->draw();
   842 
   843       //reposition of edgetext
   844       XY text_pos=mytab.mapstorage.arrow_pos[ei];
   845       text_pos+=(XY(10,10));
   846       edgetextmap[ei]->property_x().set_value(text_pos.x);
   847       edgetextmap[ei]->property_y().set_value(text_pos.y);
   848     }
   849 
   850   for(InEdgeIt ei((mytab.mapstorage).graph,moved_node);ei!=INVALID;++ei)
   851     {
   852       if (mytab.mapstorage.graph.source(ei) != mytab.mapstorage.graph.target(ei))
   853 	{
   854 	  XY moved_node_1(coord_x - dx, coord_y - dy);
   855 	  XY moved_node_2(coord_x, coord_y);
   856 	  Node source = mytab.mapstorage.graph.source(ei);
   857 	  XY fix_node(mytab.mapstorage.coords[source].x,
   858 		      mytab.mapstorage.coords[source].y);
   859 	  XY old_arrow_pos(mytab.mapstorage.arrow_pos[ei]);
   860 
   861 	  XY arrow_pos;
   862 	  arrow_pos = calcArrowPos(moved_node_1, moved_node_2, fix_node, old_arrow_pos, isbutton);
   863 
   864 	  mytab.mapstorage.arrow_pos.set(ei, arrow_pos);
   865 	  edgesmap[ei]->draw();
   866 
   867 	  //reposition of edgetext
   868 	  XY text_pos=mytab.mapstorage.arrow_pos[ei];
   869 	  text_pos+=(XY(10,10));
   870 	  edgetextmap[ei]->property_x().set_value(text_pos.x);
   871 	  edgetextmap[ei]->property_y().set_value(text_pos.y);
   872 	}
   873     }
   874 }