graph_displayer_canvas-event.cc
author ladanyi
Wed, 10 Jan 2007 14:37:46 +0000
changeset 184 4e8704aae278
parent 178 a96d2a540454
child 187 b465e2c34f23
permissions -rwxr-xr-x
Added support for setting the background form an image file.
     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       is_drawn=true;
   266 
   267       isbutton=1;
   268 
   269       active_node=(mytab.mapstorage).graph.addNode();
   270 
   271       //initiating values corresponding to new node in maps
   272 
   273       window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
   274 
   275       // update coordinates
   276       (mytab.mapstorage).coords.set(active_node, XY(clicked_x, clicked_y));
   277 
   278       // update all other maps
   279       for (std::map<std::string, Graph::NodeMap<double>*>::const_iterator it =
   280           (mytab.mapstorage).nodemap_storage.begin(); it !=
   281           (mytab.mapstorage).nodemap_storage.end(); ++it)
   282       {
   283         if ((it->first != "coordinates_x") &&
   284             (it->first != "coordinates_y"))
   285         {
   286           (*(it->second))[active_node] =
   287             (mytab.mapstorage).nodemap_default[it->first];
   288         }
   289       }
   290       // increment the id map's default value
   291       (mytab.mapstorage).nodemap_default["label"] += 1.0;
   292 
   293       nodesmap[active_node]=new Gnome::Canvas::Ellipse(displayed_graph,
   294           clicked_x-20, clicked_y-20, clicked_x+20, clicked_y+20);
   295       active_item=(Gnome::Canvas::Item *)(nodesmap[active_node]);
   296       *(nodesmap[active_node]) <<
   297         Gnome::Canvas::Properties::fill_color("blue");
   298       *(nodesmap[active_node]) <<
   299         Gnome::Canvas::Properties::outline_color("black");
   300       active_item->raise_to_top();
   301 
   302       (nodesmap[active_node])->show();
   303 
   304       nodetextmap[active_node]=new Gnome::Canvas::Text(displayed_graph,
   305           clicked_x+node_property_defaults[N_RADIUS]+5,
   306           clicked_y+node_property_defaults[N_RADIUS]+5, "");
   307       nodetextmap[active_node]->property_fill_color().set_value("darkblue");
   308       nodetextmap[active_node]->raise_to_top();
   309 
   310 //       mapwin.updateNode(active_node);
   311       propertyUpdate(active_node);
   312 
   313       isbutton=0;
   314       target_item=NULL;
   315       active_item=NULL;
   316       active_node=INVALID;
   317       break;
   318     default:
   319       break;
   320   }
   321   return false;
   322 }
   323 
   324 bool GraphDisplayerCanvas::createEdgeEventHandler(GdkEvent* e)
   325 {
   326   switch(e->type)
   327   {
   328     case GDK_BUTTON_PRESS:
   329       //in edge creation right button has special meaning
   330       if(e->button.button!=3)
   331       {
   332         //there is not yet selected node
   333         if(active_node==INVALID)
   334         {
   335           //we mark the location of the event to be able to calculate parameters of dragging
   336 
   337           window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
   338 
   339           active_item=(get_item_at(clicked_x, clicked_y));
   340           active_node=INVALID;
   341           for (NodeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
   342           {
   343             if(nodesmap[i]==active_item)
   344             {
   345               active_node=i;
   346             }
   347           }
   348           //the clicked item is really a node
   349           if(active_node!=INVALID)
   350           {
   351             *(nodesmap[active_node]) << Gnome::Canvas::Properties::fill_color("red");
   352             isbutton=1;
   353           }
   354           //clicked item was not a node. It could be e.g. edge.
   355           else
   356           {
   357             active_item=NULL;
   358           }
   359         }
   360         //we only have to do sg. if the mouse button
   361         // is pressed already once AND the click was
   362         // on a node that was found in the set of 
   363         //nodes, and now we only search for the second 
   364         //node
   365         else
   366         {
   367           window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
   368           target_item=(get_item_at(clicked_x, clicked_y));
   369           Node target_node=INVALID;
   370           for (NodeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
   371           {
   372             if(nodesmap[i]==target_item)
   373             {
   374               target_node=i;
   375             }
   376           }
   377           //the clicked item is a node, the edge can be drawn
   378           if(target_node!=INVALID)
   379           {
   380             (mytab.mapstorage).modified = true;
   381 
   382             *(nodesmap[target_node]) <<
   383               Gnome::Canvas::Properties::fill_color("red");
   384 
   385             //creating new edge
   386             active_edge=(mytab.mapstorage).graph.addEdge(active_node,
   387                 target_node);
   388 
   389             // update maps
   390             for (std::map<std::string,
   391                 Graph::EdgeMap<double>*>::const_iterator it =
   392                 (mytab.mapstorage).edgemap_storage.begin(); it !=
   393                 (mytab.mapstorage).edgemap_storage.end(); ++it)
   394             {
   395               (*(it->second))[active_edge] =
   396                 (mytab.mapstorage).edgemap_default[it->first];
   397             }
   398             // increment the id map's default value
   399             (mytab.mapstorage).edgemap_default["label"] += 1.0;
   400 
   401             if(target_node!=active_node)		
   402             {
   403               // set the coordinates of the arrow on the new edge
   404               MapStorage& ms = mytab.mapstorage;
   405               ms.arrow_pos.set(active_edge,
   406                   (ms.coords[ms.graph.source(active_edge)] +
   407                    ms.coords[ms.graph.target(active_edge)])/ 2.0);
   408 
   409               //drawing new edge
   410               edgesmap[active_edge]=new BrokenEdge(displayed_graph, active_edge,
   411                   *this);
   412             }
   413             else
   414             {
   415               // set the coordinates of the arrow on the new edge
   416               MapStorage& ms = mytab.mapstorage;
   417               ms.arrow_pos.set(active_edge,
   418                   (ms.coords[ms.graph.source(active_edge)] +
   419                    XY(0.0, 80.0)));
   420 
   421               //drawing new edge
   422               edgesmap[active_edge]=new LoopEdge(displayed_graph, active_edge,
   423                   *this);
   424             }
   425 
   426             //initializing edge-text as well, to empty string
   427             XY text_pos=mytab.mapstorage.arrow_pos[active_edge];
   428             text_pos+=(XY(10,10));
   429 
   430             edgetextmap[active_edge]=new Gnome::Canvas::Text(displayed_graph,
   431                 text_pos.x, text_pos.y, "");
   432             edgetextmap[active_edge]->property_fill_color().set_value(
   433                 "darkgreen");
   434             edgetextmap[active_edge]->raise_to_top();
   435 
   436             propertyUpdate(active_edge);
   437           }
   438           //clicked item was not a node. it could be an e.g. edge. we do not
   439           //deal with it furthermore.
   440           else
   441           {
   442             target_item=NULL;
   443           }
   444         }
   445       }
   446       break;
   447     case GDK_BUTTON_RELEASE:
   448       isbutton=0;
   449       //we clear settings in two cases
   450       //1: the edge is ready (target_item has valid value)
   451       //2: the edge creation is cancelled with right button
   452       if((target_item)||(e->button.button==3))
   453       {
   454         if(active_item)
   455         {
   456 	  propertyUpdate(active_node,N_COLOR);
   457           active_item=NULL;
   458         }
   459         if(target_item)
   460         {
   461 	  propertyUpdate((mytab.mapstorage).graph.target(active_edge),N_COLOR);
   462           target_item=NULL;
   463         }
   464         active_node=INVALID;
   465         active_edge=INVALID;
   466       }
   467       break;
   468     default:
   469       break;
   470   }
   471   return false;
   472 }
   473 
   474 bool GraphDisplayerCanvas::eraserEventHandler(GdkEvent* e)
   475 {
   476   switch(e->type)
   477     {
   478     case GDK_BUTTON_PRESS:
   479       //finding the clicked items
   480       window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
   481       active_item=(get_item_at(clicked_x, clicked_y));
   482       active_node=INVALID;
   483       active_edge=INVALID;
   484       //was it a node?
   485       for (NodeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
   486 	{
   487 	  if(nodesmap[i]==active_item)
   488 	    {
   489 	      active_node=i;
   490 	    }
   491 	}
   492       //or was it an edge?
   493       if(active_node==INVALID)
   494 	{
   495 	  for (EdgeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
   496 	    {
   497 	      if(edgesmap[i]->getLine()==active_item)
   498 		{
   499 		  active_edge=i;
   500 		}
   501 	    }
   502 	}
   503 
   504       // return if the clicked object is neither an edge nor a node
   505       if (active_edge == INVALID) return false;
   506       
   507       //recolor activated item
   508       if(active_item)
   509 	{
   510 	  *active_item << Gnome::Canvas::Properties::fill_color("red");
   511 	}
   512       break;
   513 
   514     case GDK_BUTTON_RELEASE:
   515       window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
   516       if(active_item)
   517 	{
   518 	  //the cursor was not moved since pressing it
   519 	  if( active_item == ( get_item_at (clicked_x, clicked_y) ) )
   520 	    {
   521 	      //a node was found
   522 	      if(active_node!=INVALID)
   523 		{
   524                   (mytab.mapstorage).modified = true;
   525 
   526 		  std::set<Graph::Edge> edges_to_delete;
   527 
   528 		  for(OutEdgeIt e((mytab.mapstorage).graph,active_node);e!=INVALID;++e)
   529 		    {
   530 		      edges_to_delete.insert(e);
   531 		    }
   532 		  
   533 		  for(InEdgeIt e((mytab.mapstorage).graph,active_node);e!=INVALID;++e)
   534 		    {
   535 		      edges_to_delete.insert(e);
   536 		    }
   537 		  
   538 		  //deleting collected edges
   539 		  for(std::set<Graph::Edge>::iterator
   540 			edge_set_it=edges_to_delete.begin();
   541 		      edge_set_it!=edges_to_delete.end();
   542 		      ++edge_set_it)
   543 		    {
   544 		      deleteItem(*edge_set_it);
   545 		    }
   546 		  deleteItem(active_node);
   547 		}
   548 	      //a simple edge was chosen
   549 	      else if (active_edge != INVALID)
   550 		{
   551 		  deleteItem(active_edge);
   552 		}
   553 	    }
   554 	  //pointer was moved, deletion is cancelled
   555 	  else
   556 	    {
   557 	      if(active_node!=INVALID)
   558 		{
   559 		  *active_item << Gnome::Canvas::Properties::fill_color("blue");
   560 		}
   561 	      else if (active_edge != INVALID)
   562 		{
   563 		  *active_item << Gnome::Canvas::Properties::fill_color("green");
   564 		}
   565 	    }
   566 	}
   567       //reseting datas
   568       active_item=NULL;
   569       active_edge=INVALID;
   570       active_node=INVALID;
   571       break;
   572 
   573     case GDK_MOTION_NOTIFY:
   574       break;
   575 
   576     default:
   577       break;
   578     }
   579   return false;
   580 }
   581 
   582 bool GraphDisplayerCanvas::mapEditEventHandler(GdkEvent* e)
   583 {
   584   if(actual_tool==MAP_EDIT)
   585     {
   586       switch(e->type)
   587 	{
   588 	case GDK_BUTTON_PRESS:
   589 	  {
   590 	    //for determine, whether it was an edge
   591 	    Edge clicked_edge=INVALID;
   592 	    //for determine, whether it was a node
   593 	    Node clicked_node=INVALID;
   594 
   595 	    window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
   596 	    active_item=(get_item_at(clicked_x, clicked_y));
   597 
   598 	    //find the activated item between text of nodes
   599 	    for (NodeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
   600 	      {
   601 		//at the same time only one can be active
   602 		if(nodetextmap[i]==active_item)
   603 		  {
   604 		    clicked_node=i;
   605 		  }
   606 	      }
   607 
   608 	    //if there was not, search for it between nodes
   609 	    if(clicked_node==INVALID)
   610 	      {
   611 		for (NodeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
   612 		  {
   613 		    //at the same time only one can be active
   614 		    if(nodesmap[i]==active_item)
   615 		      {
   616 			clicked_node=i;
   617 		      }
   618 		  }
   619 	      }
   620 
   621 	    if(clicked_node==INVALID)
   622 	      {
   623 		//find the activated item between texts
   624 		for (EdgeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
   625 		  {
   626 		    //at the same time only one can be active
   627 		    if(edgetextmap[i]==active_item)
   628 		      {
   629 			clicked_edge=i;
   630 		      }
   631 		  }
   632 
   633 		//if it was not between texts, search for it between edges
   634 		if(clicked_edge==INVALID)
   635 		  {
   636 		    for (EdgeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
   637 		      {
   638 			//at the same time only one can be active
   639 			if((edgesmap[i]->getLine())==active_item)
   640 			  {
   641 			    clicked_edge=i;
   642 			  }
   643 		      }
   644 		  }
   645 	      }
   646 
   647 	    //if it was really a node...
   648 	    if(clicked_node!=INVALID)
   649 	      {
   650 		// the id map is not editable
   651 		if (nodemap_to_edit == "label") return 0;
   652 
   653 		//and there is activated map
   654 		if(nodetextmap[clicked_node]->property_text().get_value()!="")
   655 		  {
   656 		    //activate the general variable for it
   657 		    active_node=clicked_node;
   658 
   659 		    //create a dialog
   660 		    Gtk::Dialog dialog("Edit value", true);
   661 		    dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
   662 		    dialog.add_button(Gtk::Stock::OK, Gtk::RESPONSE_ACCEPT);
   663 		    Gtk::VBox* vbox = dialog.get_vbox();
   664 		    Gtk::SpinButton spin(0.0, 4);
   665 		    spin.set_increments(1.0, 10.0);
   666 		    spin.set_range(-1000000.0, 1000000.0);
   667 		    spin.set_numeric(true);
   668 		    spin.set_value(atof(nodetextmap[active_node]->property_text().get_value().c_str()));
   669 		    vbox->add(spin);
   670 		    spin.show();
   671 		    switch (dialog.run())
   672 		      {
   673 		      case Gtk::RESPONSE_NONE:
   674 		      case Gtk::RESPONSE_CANCEL:
   675 			break;
   676 		      case Gtk::RESPONSE_ACCEPT:
   677 			double new_value = spin.get_value();
   678 			(*(mytab.mapstorage).nodemap_storage[nodemap_to_edit])[active_node] =
   679 			  new_value;
   680 			std::ostringstream ostr;
   681 			ostr << new_value;
   682 			nodetextmap[active_node]->property_text().set_value(ostr.str());
   683 			//mapwin.updateNode(active_node);
   684 			//mapwin.updateNode(Node(INVALID));
   685 			propertyUpdate(Node(INVALID));
   686 		      }
   687 		  }
   688 	      }
   689 	    else
   690 	      //if it was really an edge...
   691 	      if(clicked_edge!=INVALID)
   692 		{
   693 		  // the id map is not editable
   694 		  if (edgemap_to_edit == "label") return 0;
   695 
   696 		  //and there is activated map
   697 		  if(edgetextmap[clicked_edge]->property_text().get_value()!="")
   698 		    {
   699 		      //activate the general variable for it
   700 		      active_edge=clicked_edge;
   701 
   702 		      //create a dialog
   703 		      Gtk::Dialog dialog("Edit value", true);
   704 		      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
   705 		      dialog.add_button(Gtk::Stock::OK, Gtk::RESPONSE_ACCEPT);
   706 		      Gtk::VBox* vbox = dialog.get_vbox();
   707 		      Gtk::SpinButton spin(0.0, 4);
   708 		      spin.set_increments(1.0, 10.0);
   709 		      spin.set_range(-1000000.0, 1000000.0);
   710 		      spin.set_numeric(true);
   711 		      spin.set_value(atof(edgetextmap[active_edge]->property_text().get_value().c_str()));
   712 		      vbox->add(spin);
   713 		      spin.show();
   714 		      switch (dialog.run())
   715 			{
   716 			case Gtk::RESPONSE_NONE:
   717 			case Gtk::RESPONSE_CANCEL:
   718 			  break;
   719 			case Gtk::RESPONSE_ACCEPT:
   720 			  double new_value = spin.get_value();
   721 			  (*(mytab.mapstorage).edgemap_storage[edgemap_to_edit])[active_edge] =
   722 			    new_value;
   723 			  std::ostringstream ostr;
   724 			  ostr << new_value;
   725 			  edgetextmap[active_edge]->property_text().set_value(
   726 									      ostr.str());
   727 			  //mapwin.updateEdge(active_edge);
   728 			  //                   mapwin.updateEdge(Edge(INVALID));
   729 			  propertyUpdate(Edge(INVALID));
   730 			}
   731 		    }
   732 		}
   733 	    break;
   734 	  }
   735 	default:
   736 	  break;
   737 	}
   738     }
   739   return false;  
   740 }
   741 
   742 void GraphDisplayerCanvas::deleteItem(Node node_to_delete)
   743 {
   744   delete(nodetextmap[node_to_delete]);
   745   delete(nodesmap[node_to_delete]);
   746   (mytab.mapstorage).graph.erase(node_to_delete);
   747 }
   748 
   749 void GraphDisplayerCanvas::deleteItem(Edge edge_to_delete)
   750 {
   751   delete(edgetextmap[edge_to_delete]);
   752   delete(edgesmap[edge_to_delete]);
   753   (mytab.mapstorage).graph.erase(edge_to_delete);
   754 }
   755 
   756 void GraphDisplayerCanvas::textReposition(XY new_place)
   757 {
   758   new_place+=(XY(10,10));
   759   edgetextmap[forming_edge]->property_x().set_value(new_place.x);
   760   edgetextmap[forming_edge]->property_y().set_value(new_place.y);
   761 }
   762 
   763 void GraphDisplayerCanvas::toggleEdgeActivity(EdgeBase* active_bre, bool on)
   764 {
   765   if(on)
   766   {
   767     if(forming_edge!=INVALID)
   768     {
   769       std::cerr << "ERROR!!!! Valid edge found!" << std::endl;
   770     }
   771     else
   772     {
   773       for (EdgeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
   774       {
   775         if(edgesmap[i]==active_bre)
   776         {
   777           forming_edge=i;
   778         }
   779       }
   780     }
   781   }
   782   else
   783     {
   784       if(forming_edge!=INVALID)
   785 	{
   786 	  forming_edge=INVALID;
   787 	}
   788       else
   789 	{
   790 	  std::cerr << "ERROR!!!! Invalid edge found!" << std::endl;
   791 	}
   792     }
   793 }
   794 
   795 void GraphDisplayerCanvas::moveNode(double dx, double dy, Gnome::Canvas::Item * item, Node node)
   796 {
   797   Gnome::Canvas::Item * moved_item=item;
   798   Node moved_node=node;
   799 
   800   if(item==NULL && node==INVALID)
   801     {
   802       moved_item=active_item;
   803       moved_node=active_node;
   804     }
   805   else
   806     {
   807       isbutton=1;
   808     }
   809 
   810   //repositioning node and its text
   811   moved_item->move(dx, dy);
   812   nodetextmap[moved_node]->move(dx, dy);
   813 
   814   // the new coordinates of the centre of the node 
   815   double coord_x = dx + (mytab.mapstorage).coords[moved_node].x;
   816   double coord_y = dy + (mytab.mapstorage).coords[moved_node].y;
   817 
   818   // write back the new coordinates to the coords map
   819   (mytab.mapstorage).coords.set(moved_node, XY(coord_x, coord_y));
   820 
   821   //all the edges connected to the moved point has to be redrawn
   822   for(OutEdgeIt ei((mytab.mapstorage).graph,moved_node);ei!=INVALID;++ei)
   823     {
   824       XY arrow_pos;
   825 
   826       if (mytab.mapstorage.graph.source(ei) == mytab.mapstorage.graph.target(ei))
   827 	{
   828 	  arrow_pos = mytab.mapstorage.arrow_pos[ei] + XY(dx, dy);
   829 	}
   830       else
   831 	{
   832 	  XY moved_node_1(coord_x - dx, coord_y - dy);
   833 	  XY moved_node_2(coord_x, coord_y);
   834 	  Node target = mytab.mapstorage.graph.target(ei);
   835 	  XY fix_node(mytab.mapstorage.coords[target].x,
   836 		      mytab.mapstorage.coords[target].y);
   837 	  XY old_arrow_pos(mytab.mapstorage.arrow_pos[ei]);
   838 
   839 	  arrow_pos = calcArrowPos(moved_node_1, moved_node_2, fix_node, old_arrow_pos, isbutton);
   840 	}
   841 
   842       mytab.mapstorage.arrow_pos.set(ei, arrow_pos);
   843       edgesmap[ei]->draw();
   844 
   845       //reposition of edgetext
   846       XY text_pos=mytab.mapstorage.arrow_pos[ei];
   847       text_pos+=(XY(10,10));
   848       edgetextmap[ei]->property_x().set_value(text_pos.x);
   849       edgetextmap[ei]->property_y().set_value(text_pos.y);
   850     }
   851 
   852   for(InEdgeIt ei((mytab.mapstorage).graph,moved_node);ei!=INVALID;++ei)
   853     {
   854       if (mytab.mapstorage.graph.source(ei) != mytab.mapstorage.graph.target(ei))
   855 	{
   856 	  XY moved_node_1(coord_x - dx, coord_y - dy);
   857 	  XY moved_node_2(coord_x, coord_y);
   858 	  Node source = mytab.mapstorage.graph.source(ei);
   859 	  XY fix_node(mytab.mapstorage.coords[source].x,
   860 		      mytab.mapstorage.coords[source].y);
   861 	  XY old_arrow_pos(mytab.mapstorage.arrow_pos[ei]);
   862 
   863 	  XY arrow_pos;
   864 	  arrow_pos = calcArrowPos(moved_node_1, moved_node_2, fix_node, old_arrow_pos, isbutton);
   865 
   866 	  mytab.mapstorage.arrow_pos.set(ei, arrow_pos);
   867 	  edgesmap[ei]->draw();
   868 
   869 	  //reposition of edgetext
   870 	  XY text_pos=mytab.mapstorage.arrow_pos[ei];
   871 	  text_pos+=(XY(10,10));
   872 	  edgetextmap[ei]->property_x().set_value(text_pos.x);
   873 	  edgetextmap[ei]->property_y().set_value(text_pos.y);
   874 	}
   875     }
   876 }
   877 
   878 Gdk::Color GraphDisplayerCanvas::rainbowColorCounter(double min, double max, double w)
   879 {
   880   Gdk::Color color;
   881 
   882   double pos=(w-min)/(max-min);
   883   int phase=0;
   884 
   885   //rainbow transitions contain 6 phase
   886   //in each phase only one color is changed
   887   //first we determine the phase, in which
   888   //the actual value belongs to
   889   for (int i=0;i<=5;i++)
   890     {
   891       if(((double)i/6<pos)&&(pos<=(double(i+1)/6)))
   892 	{
   893 	  phase=i;
   894 	}
   895     }
   896   if(phase<6)
   897     {
   898       //within its 1/6 long phase the relativ position
   899       //determines the power of the color changed in
   900       //that phase
   901       //we normalize that to one, to be able to give percentage
   902       //value for the function
   903       double rel_pos=(pos-(phase/6))*6;
   904 
   905       switch(phase)
   906 	{
   907 	case 0:
   908 	  color.set_rgb_p (1, 0, 1-rel_pos);
   909 	  break;
   910 	case 1:
   911 	  color.set_rgb_p (1, rel_pos, 0);
   912 	  break;
   913 	case 2:
   914 	  color.set_rgb_p (1-rel_pos, 1, 0);
   915 	  break;
   916 	case 3:
   917 	  color.set_rgb_p (0, 1, rel_pos);
   918 	  break;
   919 	case 4:
   920 	  color.set_rgb_p (0, 1-rel_pos, 1);
   921 	  break;
   922 	case 5:
   923 	  color.set_rgb_p ((rel_pos/3), 0, 1);
   924 	  break;
   925 	default:
   926 	  std::cout << "Wrong phase: " << phase << " " << pos << std::endl;
   927 	}
   928     }
   929   else
   930     {
   931       std::cout << "Wrong phase: " << phase << " " << pos << std::endl;
   932     }
   933   return color;
   934 }