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