graph_displayer_canvas-event.cc
author hegyi
Tue, 20 Feb 2007 15:46:19 +0000
changeset 189 8b69c54d5bf0
parent 179 1f436ea3ef4f
child 194 6b2b718420eb
child 204 8fec6a6472fe
permissions -rwxr-xr-x
No segmentation fault will be occured if two nodes are exactly overlap each other, AND they are connected.
     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::scrollEventHandler(GdkEvent* e)
    99 {
   100   bool handled=false;
   101   if(e->type==GDK_SCROLL)
   102     {
   103 
   104       //pointer shows this win point before zoom
   105       XY win_coord(((GdkEventScroll*)e)->x, ((GdkEventScroll*)e)->y);
   106 
   107       //the original scroll settings
   108       int scroll_offset_x, scroll_offset_y;
   109       get_scroll_offsets(scroll_offset_x, scroll_offset_y);
   110 
   111       //pointer shows this canvas point before zoom
   112       XY canvas_coord;
   113       window_to_world(win_coord.x, win_coord.y, canvas_coord.x, canvas_coord.y);
   114 
   115       if(((GdkEventScroll*)e)->direction) //IN
   116 	{
   117 	  zoomIn();
   118 	}
   119       else
   120 	{
   121 	  zoomOut();
   122 	}
   123 
   124       //pointer shows this window point after zoom
   125       XY post_win_coord;
   126       world_to_window(canvas_coord.x, canvas_coord.y, post_win_coord.x, post_win_coord.y);
   127 
   128       //we have to add the difference between new and old window point to original scroll offset
   129       scroll_to(scroll_offset_x+(int)(post_win_coord.x-win_coord.x),scroll_offset_y+(int)(post_win_coord.y-win_coord.y));
   130       
   131       //no other eventhandler is needed
   132       handled=true;
   133     }
   134   return handled;
   135 }
   136 
   137 bool GraphDisplayerCanvas::moveEventHandler(GdkEvent* e)
   138 {
   139   static Gnome::Canvas::Text *coord_text = 0;
   140   switch(e->type)
   141     {
   142     case GDK_BUTTON_PRESS:
   143       //we mark the location of the event to be able to calculate parameters of dragging
   144       window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
   145       
   146       active_item=(get_item_at(clicked_x, clicked_y));
   147       active_node=INVALID;
   148       for (NodeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
   149 	{
   150 	  if(nodesmap[i]==active_item)
   151 	    {
   152 	      active_node=i;
   153 	    }
   154 	}
   155       isbutton=e->button.button;
   156       break;
   157     case GDK_BUTTON_RELEASE:
   158       if (coord_text)
   159 	{
   160 	  delete coord_text;
   161 	  coord_text = 0;
   162 	}
   163       isbutton=0;
   164       active_item=NULL;
   165       active_node=INVALID;
   166       break;
   167     case GDK_MOTION_NOTIFY:
   168       //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
   169       if(active_node!=INVALID)
   170 	{
   171 	  (mytab.mapstorage).modified = true;
   172 	  
   173 	  //new coordinates will be the old values,
   174 	  //because the item will be moved to the
   175 	  //new coordinate therefore the new movement
   176 	  //has to be calculated from here
   177 	  
   178 	  double new_x, new_y;
   179 	  
   180 	  window_to_world (e->motion.x, e->motion.y, new_x, new_y);
   181 	  
   182 	  double dx=new_x-clicked_x;
   183 	  double dy=new_y-clicked_y;
   184 	  
   185 	  moveNode(dx, dy);
   186 
   187 	  clicked_x=new_x;
   188 	  clicked_y=new_y;
   189 
   190 	  // reposition the coordinates text
   191 	  std::ostringstream ostr;
   192 	  ostr << "(" <<
   193 	    (mytab.mapstorage).coords[active_node].x << ", " <<
   194 	    (mytab.mapstorage).coords[active_node].y << ")";
   195 	  double radius =
   196 	    (nodesmap[active_node]->property_x2().get_value() -
   197 	     nodesmap[active_node]->property_x1().get_value()) / 2.0;
   198 	  if (coord_text)
   199 	    {
   200 	      coord_text->property_text().set_value(ostr.str());
   201 	      coord_text->property_x().set_value((mytab.mapstorage).coords[active_node].x +
   202 						 radius);
   203 	      coord_text->property_y().set_value((mytab.mapstorage).coords[active_node].y -
   204 						 radius);
   205 	    }
   206 	  else
   207 	    {
   208 	      coord_text = new Gnome::Canvas::Text(
   209 						   displayed_graph,
   210 						   (mytab.mapstorage).coords[active_node].x + radius,
   211 						   (mytab.mapstorage).coords[active_node].y - radius,
   212 						   ostr.str());
   213 	      coord_text->property_fill_color().set_value("black");
   214 	      coord_text->property_anchor().set_value(Gtk::ANCHOR_SOUTH_WEST);
   215 	    }
   216 
   217 
   218 	}
   219     default: break;
   220     }
   221 
   222 return false;
   223 }
   224 
   225 XY GraphDisplayerCanvas::calcArrowPos(XY moved_node_1, XY moved_node_2, XY fix_node, XY old_arrow_pos, int move_code)
   226 {
   227   switch(move_code)
   228     {
   229     case 1:
   230       return XY((moved_node_2.x + fix_node.x) / 2.0, (moved_node_2.y + fix_node.y) / 2.0);
   231       break;
   232     case 2:
   233       return old_arrow_pos;
   234       break;
   235     case 3:
   236       {
   237 	//////////////////////////////////////////////////////////////////////////////////////////////////////
   238 	/////////// keeps shape-with scalar multiplication - version 2.
   239 	//////////////////////////////////////////////////////////////////////////////////////////////////////
   240 
   241 	//old vector from one to the other node - a
   242 	XY a_v(moved_node_1.x-fix_node.x,moved_node_1.y-fix_node.y);
   243 	//new vector from one to the other node - b
   244 	XY b_v(moved_node_2.x-fix_node.x,moved_node_2.y-fix_node.y);
   245 
   246 	double absa=sqrt(a_v.normSquare());
   247 	double absb=sqrt(b_v.normSquare());
   248 
   249 	if ((absa == 0.0) || (absb == 0.0))
   250 	  {
   251 	    return old_arrow_pos;
   252 	  }
   253 	else
   254 	  {
   255 	    //old vector from one node to the breakpoint - c
   256 	    XY c_v(old_arrow_pos.x-fix_node.x,old_arrow_pos.y-fix_node.y);
   257 
   258 	    //unit vector with the same direction to a_v
   259 	    XY a_v_u(a_v.x/absa,a_v.y/absa);
   260 
   261 	    //normal vector of unit vector with the same direction to a_v
   262 	    XY a_v_u_n(((-1)*a_v_u.y),a_v_u.x);
   263 
   264 	    //unit vector with the same direction to b_v
   265 	    XY b_v_u(b_v.x/absb,b_v.y/absb);
   266 
   267 	    //normal vector of unit vector with the same direction to b_v
   268 	    XY b_v_u_n(((-1)*b_v_u.y),b_v_u.x);
   269 
   270 	    //vector c in a_v_u and a_v_u_n co-ordinate system
   271 	    XY c_a(c_v*a_v_u,c_v*a_v_u_n);
   272 
   273 	    //new vector from one node to the breakpoint - d - we have to calculate this one
   274 	    XY d_v=absb/absa*(c_a.x*b_v_u+c_a.y*b_v_u_n);
   275 
   276 	    return XY(d_v.x+fix_node.x,d_v.y+fix_node.y);
   277 	  }
   278 	break;
   279       }
   280     default:
   281       break;
   282     }
   283 }
   284 
   285 
   286 bool GraphDisplayerCanvas::createNodeEventHandler(GdkEvent* e)
   287 {
   288   switch(e->type)
   289   {
   290     //move the new node
   291     case GDK_MOTION_NOTIFY:
   292       {
   293         GdkEvent * generated=new GdkEvent();
   294         generated->motion.x=e->motion.x;
   295         generated->motion.y=e->motion.y;
   296         generated->type=GDK_MOTION_NOTIFY;
   297         moveEventHandler(generated);      
   298         break;
   299       }
   300 
   301     case GDK_BUTTON_RELEASE:
   302       (mytab.mapstorage).modified = true;
   303 
   304       is_drawn=true;
   305 
   306       isbutton=1;
   307 
   308       active_node=(mytab.mapstorage).graph.addNode();
   309 
   310       //initiating values corresponding to new node in maps
   311 
   312       window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
   313 
   314       // update coordinates
   315       (mytab.mapstorage).coords.set(active_node, XY(clicked_x, clicked_y));
   316 
   317       // update all other maps
   318       for (std::map<std::string, Graph::NodeMap<double>*>::const_iterator it =
   319           (mytab.mapstorage).nodemap_storage.begin(); it !=
   320           (mytab.mapstorage).nodemap_storage.end(); ++it)
   321       {
   322         if ((it->first != "coordinates_x") &&
   323             (it->first != "coordinates_y"))
   324         {
   325           (*(it->second))[active_node] =
   326             (mytab.mapstorage).nodemap_default[it->first];
   327         }
   328       }
   329       // increment the id map's default value
   330       (mytab.mapstorage).nodemap_default["label"] += 1.0;
   331 
   332       nodesmap[active_node]=new Gnome::Canvas::Ellipse(displayed_graph,
   333           clicked_x-20, clicked_y-20, clicked_x+20, clicked_y+20);
   334       active_item=(Gnome::Canvas::Item *)(nodesmap[active_node]);
   335       *(nodesmap[active_node]) <<
   336         Gnome::Canvas::Properties::fill_color("blue");
   337       *(nodesmap[active_node]) <<
   338         Gnome::Canvas::Properties::outline_color("black");
   339       active_item->raise_to_top();
   340 
   341       (nodesmap[active_node])->show();
   342 
   343       nodetextmap[active_node]=new Gnome::Canvas::Text(displayed_graph,
   344           clicked_x+node_property_defaults[N_RADIUS]+5,
   345           clicked_y+node_property_defaults[N_RADIUS]+5, "");
   346       nodetextmap[active_node]->property_fill_color().set_value("darkblue");
   347       nodetextmap[active_node]->raise_to_top();
   348 
   349 //       mapwin.updateNode(active_node);
   350       propertyUpdate(active_node);
   351 
   352       isbutton=0;
   353       target_item=NULL;
   354       active_item=NULL;
   355       active_node=INVALID;
   356       break;
   357     default:
   358       break;
   359   }
   360   return false;
   361 }
   362 
   363 bool GraphDisplayerCanvas::createEdgeEventHandler(GdkEvent* e)
   364 {
   365   switch(e->type)
   366   {
   367     case GDK_BUTTON_PRESS:
   368       //in edge creation right button has special meaning
   369       if(e->button.button!=3)
   370       {
   371         //there is not yet selected node
   372         if(active_node==INVALID)
   373         {
   374           //we mark the location of the event to be able to calculate parameters of dragging
   375 
   376           window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
   377 
   378           active_item=(get_item_at(clicked_x, clicked_y));
   379           active_node=INVALID;
   380           for (NodeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
   381           {
   382             if(nodesmap[i]==active_item)
   383             {
   384               active_node=i;
   385             }
   386           }
   387           //the clicked item is really a node
   388           if(active_node!=INVALID)
   389           {
   390             *(nodesmap[active_node]) << Gnome::Canvas::Properties::fill_color("red");
   391             isbutton=1;
   392           }
   393           //clicked item was not a node. It could be e.g. edge.
   394           else
   395           {
   396             active_item=NULL;
   397           }
   398         }
   399         //we only have to do sg. if the mouse button
   400         // is pressed already once AND the click was
   401         // on a node that was found in the set of 
   402         //nodes, and now we only search for the second 
   403         //node
   404         else
   405         {
   406           window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
   407           target_item=(get_item_at(clicked_x, clicked_y));
   408           Node target_node=INVALID;
   409           for (NodeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
   410           {
   411             if(nodesmap[i]==target_item)
   412             {
   413               target_node=i;
   414             }
   415           }
   416           //the clicked item is a node, the edge can be drawn
   417           if(target_node!=INVALID)
   418           {
   419             (mytab.mapstorage).modified = true;
   420 
   421             *(nodesmap[target_node]) <<
   422               Gnome::Canvas::Properties::fill_color("red");
   423 
   424             //creating new edge
   425             active_edge=(mytab.mapstorage).graph.addEdge(active_node,
   426                 target_node);
   427 
   428             // update maps
   429             for (std::map<std::string,
   430                 Graph::EdgeMap<double>*>::const_iterator it =
   431                 (mytab.mapstorage).edgemap_storage.begin(); it !=
   432                 (mytab.mapstorage).edgemap_storage.end(); ++it)
   433             {
   434               (*(it->second))[active_edge] =
   435                 (mytab.mapstorage).edgemap_default[it->first];
   436             }
   437             // increment the id map's default value
   438             (mytab.mapstorage).edgemap_default["label"] += 1.0;
   439 
   440             if(target_node!=active_node)		
   441             {
   442               // set the coordinates of the arrow on the new edge
   443               MapStorage& ms = mytab.mapstorage;
   444               ms.arrow_pos.set(active_edge,
   445                   (ms.coords[ms.graph.source(active_edge)] +
   446                    ms.coords[ms.graph.target(active_edge)])/ 2.0);
   447 
   448               //drawing new edge
   449               edgesmap[active_edge]=new BrokenEdge(displayed_graph, active_edge,
   450                   *this);
   451             }
   452             else
   453             {
   454               // set the coordinates of the arrow on the new edge
   455               MapStorage& ms = mytab.mapstorage;
   456               ms.arrow_pos.set(active_edge,
   457                   (ms.coords[ms.graph.source(active_edge)] +
   458                    XY(0.0, 80.0)));
   459 
   460               //drawing new edge
   461               edgesmap[active_edge]=new LoopEdge(displayed_graph, active_edge,
   462                   *this);
   463             }
   464 
   465             //initializing edge-text as well, to empty string
   466             XY text_pos=mytab.mapstorage.arrow_pos[active_edge];
   467             text_pos+=(XY(10,10));
   468 
   469             edgetextmap[active_edge]=new Gnome::Canvas::Text(displayed_graph,
   470                 text_pos.x, text_pos.y, "");
   471             edgetextmap[active_edge]->property_fill_color().set_value(
   472                 "darkgreen");
   473             edgetextmap[active_edge]->raise_to_top();
   474 
   475             propertyUpdate(active_edge);
   476           }
   477           //clicked item was not a node. it could be an e.g. edge. we do not
   478           //deal with it furthermore.
   479           else
   480           {
   481             target_item=NULL;
   482           }
   483         }
   484       }
   485       break;
   486     case GDK_BUTTON_RELEASE:
   487       isbutton=0;
   488       //we clear settings in two cases
   489       //1: the edge is ready (target_item has valid value)
   490       //2: the edge creation is cancelled with right button
   491       if((target_item)||(e->button.button==3))
   492       {
   493         if(active_item)
   494         {
   495 	  propertyUpdate(active_node,N_COLOR);
   496           active_item=NULL;
   497         }
   498         if(target_item)
   499         {
   500 	  propertyUpdate((mytab.mapstorage).graph.target(active_edge),N_COLOR);
   501           target_item=NULL;
   502         }
   503         active_node=INVALID;
   504         active_edge=INVALID;
   505       }
   506       break;
   507     default:
   508       break;
   509   }
   510   return false;
   511 }
   512 
   513 bool GraphDisplayerCanvas::eraserEventHandler(GdkEvent* e)
   514 {
   515   switch(e->type)
   516     {
   517     case GDK_BUTTON_PRESS:
   518       //finding the clicked items
   519       window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
   520       active_item=(get_item_at(clicked_x, clicked_y));
   521       active_node=INVALID;
   522       active_edge=INVALID;
   523       //was it a node?
   524       for (NodeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
   525 	{
   526 	  if(nodesmap[i]==active_item)
   527 	    {
   528 	      active_node=i;
   529 	    }
   530 	}
   531       //or was it an edge?
   532       if(active_node==INVALID)
   533 	{
   534 	  for (EdgeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
   535 	    {
   536 	      if(edgesmap[i]->getLine()==active_item)
   537 		{
   538 		  active_edge=i;
   539 		}
   540 	    }
   541 	}
   542 
   543       // return if the clicked object is neither an edge nor a node
   544       if (active_edge == INVALID) return false;
   545       
   546       //recolor activated item
   547       if(active_item)
   548 	{
   549 	  *active_item << Gnome::Canvas::Properties::fill_color("red");
   550 	}
   551       break;
   552 
   553     case GDK_BUTTON_RELEASE:
   554       window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
   555       if(active_item)
   556 	{
   557 	  //the cursor was not moved since pressing it
   558 	  if( active_item == ( get_item_at (clicked_x, clicked_y) ) )
   559 	    {
   560 	      //a node was found
   561 	      if(active_node!=INVALID)
   562 		{
   563                   (mytab.mapstorage).modified = true;
   564 
   565 		  std::set<Graph::Edge> edges_to_delete;
   566 
   567 		  for(OutEdgeIt e((mytab.mapstorage).graph,active_node);e!=INVALID;++e)
   568 		    {
   569 		      edges_to_delete.insert(e);
   570 		    }
   571 		  
   572 		  for(InEdgeIt e((mytab.mapstorage).graph,active_node);e!=INVALID;++e)
   573 		    {
   574 		      edges_to_delete.insert(e);
   575 		    }
   576 		  
   577 		  //deleting collected edges
   578 		  for(std::set<Graph::Edge>::iterator
   579 			edge_set_it=edges_to_delete.begin();
   580 		      edge_set_it!=edges_to_delete.end();
   581 		      ++edge_set_it)
   582 		    {
   583 		      deleteItem(*edge_set_it);
   584 		    }
   585 		  deleteItem(active_node);
   586 		}
   587 	      //a simple edge was chosen
   588 	      else if (active_edge != INVALID)
   589 		{
   590 		  deleteItem(active_edge);
   591 		}
   592 	    }
   593 	  //pointer was moved, deletion is cancelled
   594 	  else
   595 	    {
   596 	      if(active_node!=INVALID)
   597 		{
   598 		  *active_item << Gnome::Canvas::Properties::fill_color("blue");
   599 		}
   600 	      else if (active_edge != INVALID)
   601 		{
   602 		  *active_item << Gnome::Canvas::Properties::fill_color("green");
   603 		}
   604 	    }
   605 	}
   606       //reseting datas
   607       active_item=NULL;
   608       active_edge=INVALID;
   609       active_node=INVALID;
   610       break;
   611 
   612     case GDK_MOTION_NOTIFY:
   613       break;
   614 
   615     default:
   616       break;
   617     }
   618   return false;
   619 }
   620 
   621 bool GraphDisplayerCanvas::mapEditEventHandler(GdkEvent* e)
   622 {
   623   if(actual_tool==MAP_EDIT)
   624     {
   625       switch(e->type)
   626 	{
   627 	case GDK_BUTTON_PRESS:
   628 	  {
   629 	    //for determine, whether it was an edge
   630 	    Edge clicked_edge=INVALID;
   631 	    //for determine, whether it was a node
   632 	    Node clicked_node=INVALID;
   633 
   634 	    window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
   635 	    active_item=(get_item_at(clicked_x, clicked_y));
   636 
   637 	    //find the activated item between text of nodes
   638 	    for (NodeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
   639 	      {
   640 		//at the same time only one can be active
   641 		if(nodetextmap[i]==active_item)
   642 		  {
   643 		    clicked_node=i;
   644 		  }
   645 	      }
   646 
   647 	    //if there was not, search for it between nodes
   648 	    if(clicked_node==INVALID)
   649 	      {
   650 		for (NodeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
   651 		  {
   652 		    //at the same time only one can be active
   653 		    if(nodesmap[i]==active_item)
   654 		      {
   655 			clicked_node=i;
   656 		      }
   657 		  }
   658 	      }
   659 
   660 	    if(clicked_node==INVALID)
   661 	      {
   662 		//find the activated item between texts
   663 		for (EdgeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
   664 		  {
   665 		    //at the same time only one can be active
   666 		    if(edgetextmap[i]==active_item)
   667 		      {
   668 			clicked_edge=i;
   669 		      }
   670 		  }
   671 
   672 		//if it was not between texts, search for it between edges
   673 		if(clicked_edge==INVALID)
   674 		  {
   675 		    for (EdgeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
   676 		      {
   677 			//at the same time only one can be active
   678 			if((edgesmap[i]->getLine())==active_item)
   679 			  {
   680 			    clicked_edge=i;
   681 			  }
   682 		      }
   683 		  }
   684 	      }
   685 
   686 	    //if it was really a node...
   687 	    if(clicked_node!=INVALID)
   688 	      {
   689 		// the id map is not editable
   690 		if (nodemap_to_edit == "label") return 0;
   691 
   692 		//and there is activated map
   693 		if(nodetextmap[clicked_node]->property_text().get_value()!="")
   694 		  {
   695 		    //activate the general variable for it
   696 		    active_node=clicked_node;
   697 
   698 		    //create a dialog
   699 		    Gtk::Dialog dialog("Edit value", true);
   700 		    dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
   701 		    dialog.add_button(Gtk::Stock::OK, Gtk::RESPONSE_ACCEPT);
   702 		    Gtk::VBox* vbox = dialog.get_vbox();
   703 		    Gtk::SpinButton spin(0.0, 4);
   704 		    spin.set_increments(1.0, 10.0);
   705 		    spin.set_range(-1000000.0, 1000000.0);
   706 		    spin.set_numeric(true);
   707 		    spin.set_value(atof(nodetextmap[active_node]->property_text().get_value().c_str()));
   708 		    vbox->add(spin);
   709 		    spin.show();
   710 		    switch (dialog.run())
   711 		      {
   712 		      case Gtk::RESPONSE_NONE:
   713 		      case Gtk::RESPONSE_CANCEL:
   714 			break;
   715 		      case Gtk::RESPONSE_ACCEPT:
   716 			double new_value = spin.get_value();
   717 			(*(mytab.mapstorage).nodemap_storage[nodemap_to_edit])[active_node] =
   718 			  new_value;
   719 			std::ostringstream ostr;
   720 			ostr << new_value;
   721 			nodetextmap[active_node]->property_text().set_value(ostr.str());
   722 			//mapwin.updateNode(active_node);
   723 			//mapwin.updateNode(Node(INVALID));
   724 			propertyUpdate(Node(INVALID));
   725 		      }
   726 		  }
   727 	      }
   728 	    else
   729 	      //if it was really an edge...
   730 	      if(clicked_edge!=INVALID)
   731 		{
   732 		  // the id map is not editable
   733 		  if (edgemap_to_edit == "label") return 0;
   734 
   735 		  //and there is activated map
   736 		  if(edgetextmap[clicked_edge]->property_text().get_value()!="")
   737 		    {
   738 		      //activate the general variable for it
   739 		      active_edge=clicked_edge;
   740 
   741 		      //create a dialog
   742 		      Gtk::Dialog dialog("Edit value", true);
   743 		      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
   744 		      dialog.add_button(Gtk::Stock::OK, Gtk::RESPONSE_ACCEPT);
   745 		      Gtk::VBox* vbox = dialog.get_vbox();
   746 		      Gtk::SpinButton spin(0.0, 4);
   747 		      spin.set_increments(1.0, 10.0);
   748 		      spin.set_range(-1000000.0, 1000000.0);
   749 		      spin.set_numeric(true);
   750 		      spin.set_value(atof(edgetextmap[active_edge]->property_text().get_value().c_str()));
   751 		      vbox->add(spin);
   752 		      spin.show();
   753 		      switch (dialog.run())
   754 			{
   755 			case Gtk::RESPONSE_NONE:
   756 			case Gtk::RESPONSE_CANCEL:
   757 			  break;
   758 			case Gtk::RESPONSE_ACCEPT:
   759 			  double new_value = spin.get_value();
   760 			  (*(mytab.mapstorage).edgemap_storage[edgemap_to_edit])[active_edge] =
   761 			    new_value;
   762 			  std::ostringstream ostr;
   763 			  ostr << new_value;
   764 			  edgetextmap[active_edge]->property_text().set_value(
   765 									      ostr.str());
   766 			  //mapwin.updateEdge(active_edge);
   767 			  //                   mapwin.updateEdge(Edge(INVALID));
   768 			  propertyUpdate(Edge(INVALID));
   769 			}
   770 		    }
   771 		}
   772 	    break;
   773 	  }
   774 	default:
   775 	  break;
   776 	}
   777     }
   778   return false;  
   779 }
   780 
   781 void GraphDisplayerCanvas::deleteItem(Node node_to_delete)
   782 {
   783   delete(nodetextmap[node_to_delete]);
   784   delete(nodesmap[node_to_delete]);
   785   (mytab.mapstorage).graph.erase(node_to_delete);
   786 }
   787 
   788 void GraphDisplayerCanvas::deleteItem(Edge edge_to_delete)
   789 {
   790   delete(edgetextmap[edge_to_delete]);
   791   delete(edgesmap[edge_to_delete]);
   792   (mytab.mapstorage).graph.erase(edge_to_delete);
   793 }
   794 
   795 void GraphDisplayerCanvas::textReposition(XY new_place)
   796 {
   797   new_place+=(XY(10,10));
   798   edgetextmap[forming_edge]->property_x().set_value(new_place.x);
   799   edgetextmap[forming_edge]->property_y().set_value(new_place.y);
   800 }
   801 
   802 void GraphDisplayerCanvas::toggleEdgeActivity(EdgeBase* active_bre, bool on)
   803 {
   804   if(on)
   805   {
   806     if(forming_edge!=INVALID)
   807     {
   808       std::cerr << "ERROR!!!! Valid edge found!" << std::endl;
   809     }
   810     else
   811     {
   812       for (EdgeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
   813       {
   814         if(edgesmap[i]==active_bre)
   815         {
   816           forming_edge=i;
   817         }
   818       }
   819     }
   820   }
   821   else
   822     {
   823       if(forming_edge!=INVALID)
   824 	{
   825 	  forming_edge=INVALID;
   826 	}
   827       else
   828 	{
   829 	  std::cerr << "ERROR!!!! Invalid edge found!" << std::endl;
   830 	}
   831     }
   832 }
   833 
   834 void GraphDisplayerCanvas::moveNode(double dx, double dy, Gnome::Canvas::Item * item, Node node)
   835 {
   836   Gnome::Canvas::Item * moved_item=item;
   837   Node moved_node=node;
   838 
   839   if(item==NULL && node==INVALID)
   840     {
   841       moved_item=active_item;
   842       moved_node=active_node;
   843     }
   844   else
   845     {
   846       isbutton=1;
   847     }
   848 
   849   //repositioning node and its text
   850   moved_item->move(dx, dy);
   851   nodetextmap[moved_node]->move(dx, dy);
   852 
   853   // the new coordinates of the centre of the node 
   854   double coord_x = dx + (mytab.mapstorage).coords[moved_node].x;
   855   double coord_y = dy + (mytab.mapstorage).coords[moved_node].y;
   856 
   857   // write back the new coordinates to the coords map
   858   (mytab.mapstorage).coords.set(moved_node, XY(coord_x, coord_y));
   859 
   860   //all the edges connected to the moved point has to be redrawn
   861   for(OutEdgeIt ei((mytab.mapstorage).graph,moved_node);ei!=INVALID;++ei)
   862     {
   863       XY arrow_pos;
   864 
   865       if (mytab.mapstorage.graph.source(ei) == mytab.mapstorage.graph.target(ei))
   866 	{
   867 	  arrow_pos = mytab.mapstorage.arrow_pos[ei] + XY(dx, dy);
   868 	}
   869       else
   870 	{
   871 	  XY moved_node_1(coord_x - dx, coord_y - dy);
   872 	  XY moved_node_2(coord_x, coord_y);
   873 	  Node target = mytab.mapstorage.graph.target(ei);
   874 	  XY fix_node(mytab.mapstorage.coords[target].x,
   875 		      mytab.mapstorage.coords[target].y);
   876 	  XY old_arrow_pos(mytab.mapstorage.arrow_pos[ei]);
   877 
   878 	  arrow_pos = calcArrowPos(moved_node_1, moved_node_2, fix_node, old_arrow_pos, isbutton);
   879 	}
   880 
   881       mytab.mapstorage.arrow_pos.set(ei, arrow_pos);
   882       edgesmap[ei]->draw();
   883 
   884       //reposition of edgetext
   885       XY text_pos=mytab.mapstorage.arrow_pos[ei];
   886       text_pos+=(XY(10,10));
   887       edgetextmap[ei]->property_x().set_value(text_pos.x);
   888       edgetextmap[ei]->property_y().set_value(text_pos.y);
   889     }
   890 
   891   for(InEdgeIt ei((mytab.mapstorage).graph,moved_node);ei!=INVALID;++ei)
   892     {
   893       if (mytab.mapstorage.graph.source(ei) != mytab.mapstorage.graph.target(ei))
   894 	{
   895 	  XY moved_node_1(coord_x - dx, coord_y - dy);
   896 	  XY moved_node_2(coord_x, coord_y);
   897 	  Node source = mytab.mapstorage.graph.source(ei);
   898 	  XY fix_node(mytab.mapstorage.coords[source].x,
   899 		      mytab.mapstorage.coords[source].y);
   900 	  XY old_arrow_pos(mytab.mapstorage.arrow_pos[ei]);
   901 
   902 	  XY arrow_pos;
   903 	  arrow_pos = calcArrowPos(moved_node_1, moved_node_2, fix_node, old_arrow_pos, isbutton);
   904 
   905 	  mytab.mapstorage.arrow_pos.set(ei, arrow_pos);
   906 	  edgesmap[ei]->draw();
   907 
   908 	  //reposition of edgetext
   909 	  XY text_pos=mytab.mapstorage.arrow_pos[ei];
   910 	  text_pos+=(XY(10,10));
   911 	  edgetextmap[ei]->property_x().set_value(text_pos.x);
   912 	  edgetextmap[ei]->property_y().set_value(text_pos.y);
   913 	}
   914     }
   915 }
   916 
   917 Gdk::Color GraphDisplayerCanvas::rainbowColorCounter(double min, double max, double w)
   918 {
   919   Gdk::Color color;
   920 
   921   double pos=(w-min)/(max-min);
   922   int phase=0;
   923 
   924   //rainbow transitions contain 6 phase
   925   //in each phase only one color is changed
   926   //first we determine the phase, in which
   927   //the actual value belongs to
   928   for (int i=0;i<=5;i++)
   929     {
   930       if(((double)i/6<pos)&&(pos<=(double(i+1)/6)))
   931 	{
   932 	  phase=i;
   933 	}
   934     }
   935   if(phase<6)
   936     {
   937       //within its 1/6 long phase the relativ position
   938       //determines the power of the color changed in
   939       //that phase
   940       //we normalize that to one, to be able to give percentage
   941       //value for the function
   942       double rel_pos=(pos-(phase/6))*6;
   943 
   944       switch(phase)
   945 	{
   946 	case 0:
   947 	  color.set_rgb_p (1, 0, 1-rel_pos);
   948 	  break;
   949 	case 1:
   950 	  color.set_rgb_p (1, rel_pos, 0);
   951 	  break;
   952 	case 2:
   953 	  color.set_rgb_p (1-rel_pos, 1, 0);
   954 	  break;
   955 	case 3:
   956 	  color.set_rgb_p (0, 1, rel_pos);
   957 	  break;
   958 	case 4:
   959 	  color.set_rgb_p (0, 1-rel_pos, 1);
   960 	  break;
   961 	case 5:
   962 	  color.set_rgb_p ((rel_pos/3), 0, 1);
   963 	  break;
   964 	default:
   965 	  std::cout << "Wrong phase: " << phase << " " << pos << std::endl;
   966 	}
   967     }
   968   else
   969     {
   970       std::cout << "Wrong phase: " << phase << " " << pos << std::endl;
   971     }
   972   return color;
   973 }