gui/graph_displayer_canvas-event.cc
author athos
Fri, 01 Jul 2005 16:10:46 +0000
changeset 1528 1aa71600000c
parent 1524 587a823bcdd0
child 1550 4dcbb4ab1d7a
permissions -rwxr-xr-x
Graph input-output demo, some documentation.
     1 #include <graph_displayer_canvas.h>
     2 #include <broken_edge.h>
     3 #include <math.h>
     4 
     5 
     6 bool GraphDisplayerCanvas::on_expose_event(GdkEventExpose *event)
     7 {
     8   Gnome::Canvas::CanvasAA::on_expose_event(event);
     9   //usleep(10000);
    10   //rezoom();
    11   return true;
    12 }
    13 
    14 void GraphDisplayerCanvas::changeEditorialTool(int newtool)
    15 {
    16   actual_handler.disconnect();
    17 
    18   if(actual_tool==CREATE_EDGE)
    19     {
    20 	GdkEvent * generated=new GdkEvent();
    21 	generated->type=GDK_BUTTON_RELEASE;
    22 	generated->button.button=3;
    23 	createEdgeEventHandler(generated);      
    24     }
    25 
    26   actual_tool=newtool;
    27 
    28   switch(newtool)
    29     {
    30     case MOVE:
    31       actual_handler=signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::moveEventHandler), false);
    32       break;
    33 
    34     case CREATE_NODE:
    35       actual_handler=signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::createNodeEventHandler), false);
    36       break;
    37 
    38     case CREATE_EDGE:
    39       actual_handler=signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::createEdgeEventHandler), false);
    40       break;
    41 
    42     case ERASER:
    43       actual_handler=signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::eraserEventHandler), false);
    44       break;
    45 
    46     default:
    47       break;
    48     }
    49 }
    50 
    51 int GraphDisplayerCanvas::getActualTool()
    52 {
    53   return actual_tool;
    54 }
    55 
    56 bool GraphDisplayerCanvas::moveEventHandler(GdkEvent* e)
    57 {
    58   switch(e->type)
    59   {
    60     case GDK_BUTTON_PRESS:
    61       //we mark the location of the event to be able to calculate parameters of dragging
    62       window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
    63 
    64       active_item=(get_item_at(clicked_x, clicked_y));
    65       active_node=INVALID;
    66       for (NodeIt i(g); i!=INVALID; ++i)
    67 	{
    68 	  if(nodesmap[i]==active_item)
    69 	    {
    70 	      active_node=i;
    71 	    }
    72 	}
    73       switch(e->button.button)
    74 	{
    75 	case 3:      
    76 	  isbutton=3;
    77 	  break;
    78 	default:
    79 	  isbutton=1;
    80 	  break;
    81 	}
    82       break;
    83     case GDK_BUTTON_RELEASE:
    84       isbutton=0;
    85       active_item=NULL;
    86       active_node=INVALID;
    87       break;
    88     case GDK_MOTION_NOTIFY:
    89       //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
    90       if(active_node!=INVALID)
    91       {
    92 	//new coordinates will be the old values,
    93 	//because the item will be moved to the
    94 	//new coordinate therefore the new movement
    95 	//has to be calculated from here
    96 
    97 	double new_x, new_y;
    98 
    99 	window_to_world (e->motion.x, e->motion.y, new_x, new_y);
   100 
   101         double dx=new_x-clicked_x;
   102         double dy=new_y-clicked_y;
   103 
   104 	//repositioning node and its text
   105         active_item->move(dx, dy);
   106 	nodetextmap[active_node]->move(dx, dy);
   107 
   108         clicked_x=new_x;
   109         clicked_y=new_y;
   110 
   111 	//all the edges connected to the moved point has to be redrawn
   112         EdgeIt ei;
   113 
   114         g.firstOut(ei,active_node);
   115 
   116         for(;ei!=INVALID;g.nextOut(ei))
   117         {
   118             Gnome::Canvas::Points coos;
   119             double x1, x2, y1, y2;
   120 
   121             nodesmap[g.source(ei)]->get_bounds(x1, y1, x2, y2);
   122             coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
   123 
   124             nodesmap[g.target(ei)]->get_bounds(x1, y1, x2, y2);
   125             coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
   126 
   127 	    if(isbutton==3)
   128 	      {
   129 		edgesmap[ei]->setPoints(coos);
   130 	      }
   131 	    else
   132 	      {
   133 		edgesmap[ei]->setPoints(coos,true);
   134 	      }
   135 
   136 	    //reposition of edgetext
   137 	    xy<double> text_pos=edgesmap[ei]->getArrowPos();
   138 	    text_pos+=(xy<double>(10,10));
   139 	    edgetextmap[ei]->property_x().set_value(text_pos.x);
   140 	    edgetextmap[ei]->property_y().set_value(text_pos.y);
   141         }
   142 
   143         g.firstIn(ei,active_node);
   144         for(;ei!=INVALID;g.nextIn(ei))
   145         {
   146             Gnome::Canvas::Points coos;
   147             double x1, x2, y1, y2;
   148 
   149             nodesmap[g.source(ei)]->get_bounds(x1, y1, x2, y2);
   150             coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
   151 
   152             nodesmap[g.target(ei)]->get_bounds(x1, y1, x2, y2);
   153             coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
   154 
   155 	    if(isbutton==3)
   156 	      {
   157 		edgesmap[ei]->setPoints(coos);
   158 	      }
   159 	    else
   160 	      {
   161 		edgesmap[ei]->setPoints(coos,true);
   162 	      }
   163 
   164 	    xy<double> text_pos=edgesmap[ei]->getArrowPos();
   165 	    text_pos+=(xy<double>(10,10));
   166 	    edgetextmap[ei]->property_x().set_value(text_pos.x);
   167 	    edgetextmap[ei]->property_y().set_value(text_pos.y);
   168         }
   169       }
   170     default: break;
   171   }
   172 
   173   return false;
   174 }
   175 
   176 bool GraphDisplayerCanvas::createNodeEventHandler(GdkEvent* e)
   177 {
   178   switch(e->type)
   179     {
   180 
   181       //draw the new node in red at the clicked place
   182     case GDK_2BUTTON_PRESS:
   183       std::cout << "double click" << std::endl;
   184       break;
   185     case GDK_BUTTON_PRESS:
   186       isbutton=1;
   187 
   188       active_node=NodeIt(g,g.addNode());
   189 
   190       //initiating values corresponding to new node in maps
   191 
   192       window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
   193 
   194       target_item=NULL;
   195       target_item=get_item_at(clicked_x, clicked_y);
   196 
   197       nodesmap[active_node]=new Gnome::Canvas::Ellipse(displayed_graph, clicked_x-20, clicked_y-20, clicked_x+20, clicked_y+20);
   198       active_item=(Gnome::Canvas::Item *)(nodesmap[active_node]);
   199       *(nodesmap[active_node]) << Gnome::Canvas::Properties::fill_color("red");
   200       *(nodesmap[active_node]) << Gnome::Canvas::Properties::outline_color("black");
   201       (nodesmap[active_node])->show();
   202 
   203       nodetextmap[active_node]=new Gnome::Canvas::Text(displayed_graph, clicked_x+node_property_defaults[N_RADIUS]+5, clicked_y+node_property_defaults[N_RADIUS]+5, "");
   204       nodetextmap[active_node]->property_fill_color().set_value("darkblue");
   205 
   206       mapwin->updateNode(active_node);
   207 
   208       break;
   209 
   210       //move the new node
   211     case GDK_MOTION_NOTIFY:
   212       {
   213 	double world_motion_x, world_motion_y;
   214 	GdkEvent * generated=new GdkEvent();
   215 	generated->motion.x=e->motion.x;
   216 	generated->motion.y=e->motion.y;
   217 	generated->type=GDK_MOTION_NOTIFY;
   218 	moveEventHandler(generated);      
   219 	break;
   220       }
   221 
   222       //finalize the new node
   223     case GDK_BUTTON_RELEASE:
   224       isbutton=0;
   225       if(!target_item)
   226 	{
   227 	  //Its appropriate color is given by update.
   228 	  //*active_item << Gnome::Canvas::Properties::fill_color("blue");
   229 	}
   230       else
   231 	{
   232 	  //In this case the given color has to be overwritten, because the noe covers an other item.
   233 	  *active_item << Gnome::Canvas::Properties::fill_color("lightblue");
   234 	}
   235       target_item=NULL;
   236       active_item=NULL;
   237       active_node=INVALID;
   238       break;
   239     default:
   240       break;
   241     }
   242   return false;
   243 }
   244 
   245 bool GraphDisplayerCanvas::createEdgeEventHandler(GdkEvent* e)
   246 {
   247   switch(e->type)
   248     {
   249     case GDK_BUTTON_PRESS:
   250       //in edge creation right button has special meaning
   251       if(e->button.button!=3)
   252 	{
   253 	  //there is not yet selected node
   254 	  if(active_node==INVALID)
   255 	    {
   256 	      //we mark the location of the event to be able to calculate parameters of dragging
   257 
   258 	      window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
   259 
   260 	      active_item=(get_item_at(clicked_x, clicked_y));
   261 	      active_node=INVALID;
   262 	      for (NodeIt i(g); i!=INVALID; ++i)
   263 		{
   264 		  if(nodesmap[i]==active_item)
   265 		    {
   266 		      active_node=i;
   267 		    }
   268 		}
   269 	      //the clicked item is really a node
   270 	      if(active_node!=INVALID)
   271 		{
   272 		  *(nodesmap[active_node]) << Gnome::Canvas::Properties::fill_color("red");
   273 		  isbutton=1;
   274 		}
   275 	      //clicked item was not a node. It could be e.g. edge.
   276 	      else
   277 		{
   278 		  active_item=NULL;
   279 		}
   280 	    }
   281 	  //we only have to do sg. if the mouse button
   282 	  // is pressed already once AND the click was
   283 	  // on a node that was found in the set of 
   284 	  //nodes, and now we only search for the second 
   285 	  //node
   286 	  else
   287 	    {
   288 	      window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
   289 	      target_item=(get_item_at(clicked_x, clicked_y));
   290 	      Graph::NodeIt target_node=INVALID;
   291 	      for (NodeIt i(g); i!=INVALID; ++i)
   292 		{
   293 		  if(nodesmap[i]==target_item)
   294 		    {
   295 		      target_node=i;
   296 		    }
   297 		}
   298 	      //the clicked item is a node, the edge can be drawn
   299 	      if(target_node!=INVALID)
   300 		{
   301 		  if(target_node!=active_node)		
   302 		    {
   303 		      *(nodesmap[target_node]) << Gnome::Canvas::Properties::fill_color("red");
   304 
   305 		      //creating new edge
   306 		      active_edge=EdgeIt(g,g.addEdge(active_node, target_node));
   307 
   308 		      //initiating values corresponding to new edge in maps
   309 		      mapstorage.initMapsForEdge(active_edge);
   310 	  
   311 		      //calculating coordinates of new edge
   312 		      Gnome::Canvas::Points coos;
   313 		      double x1, x2, y1, y2;
   314 	  
   315 		      active_item->get_bounds(x1, y1, x2, y2);
   316 		      coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
   317 
   318 		      target_item->get_bounds(x1, y1, x2, y2);
   319 		      coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
   320 
   321 		      //drawing new edge
   322 		      edgesmap[active_edge]=new BrokenEdge(displayed_graph, coos, *this);
   323 		      *(edgesmap[active_edge]) << Gnome::Canvas::Properties::fill_color("green");
   324 		      edgesmap[active_edge]->property_width_pixels().set_value(10);
   325 
   326 		      //redraw nodes to blank terminations of the new edge
   327 		      target_item->raise_to_top();
   328 		      active_item->raise_to_top();
   329 
   330 		      //initializing edge-text as well, to empty string
   331 		      xy<double> text_pos=edgesmap[active_edge]->getArrowPos();
   332 		      text_pos+=(xy<double>(10,10));
   333 
   334 		      edgetextmap[active_edge]=new Gnome::Canvas::Text(displayed_graph, text_pos.x, text_pos.y, "");
   335 		      edgetextmap[active_edge]->property_fill_color().set_value("darkgreen");
   336 
   337 		      //updating its properties
   338 		      mapwin->updateEdge(active_edge);
   339 		    }
   340 		  else
   341 		    {
   342 		      target_node=INVALID;
   343 		      std::cout << "Loop edge is not yet implemented!" << std::endl;
   344 		    }
   345 		}
   346 	      //clicked item was not a node. it could be an e.g. edge. we do not deal with it furthermore.
   347 	      else
   348 		{
   349 		  target_item=NULL;
   350 		}
   351 	    }
   352 	}
   353       break;
   354     case GDK_BUTTON_RELEASE:
   355       isbutton=0;
   356       //we clear settings in two cases
   357       //1: the edge is ready (target_item has valid value)
   358       //2: the edge creation is cancelled with right button
   359       if((target_item)||(e->button.button==3))
   360 	{
   361 	  if(active_item)
   362 	    {
   363 	      *active_item << Gnome::Canvas::Properties::fill_color("blue");
   364 	      active_item=NULL;
   365 	    }
   366 	  if(target_item)
   367 	    {
   368 	      *target_item << Gnome::Canvas::Properties::fill_color("blue");
   369 	      target_item=NULL;
   370 	    }
   371 	  active_node=INVALID;
   372 	  active_edge=INVALID;
   373 	}
   374       break;
   375     default:
   376       break;
   377     }
   378   return false;
   379 }
   380 
   381 bool GraphDisplayerCanvas::eraserEventHandler(GdkEvent* e)
   382 {
   383   switch(e->type)
   384     {
   385     case GDK_BUTTON_PRESS:
   386       window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
   387       active_item=(get_item_at(clicked_x, clicked_y));
   388       active_node=INVALID;
   389       active_edge=INVALID;
   390       for (NodeIt i(g); i!=INVALID; ++i)
   391 	{
   392 	  if(nodesmap[i]==active_item)
   393 	    {
   394 	      active_node=i;
   395 	    }
   396 	}
   397       if(active_node==INVALID)
   398 	{
   399 	  for (EdgeIt i(g); i!=INVALID; ++i)
   400 	    {
   401 	      if(edgesmap[i]==active_item)
   402 		{
   403 		  active_edge=i;
   404 		}
   405 	    }
   406 	}
   407       if(active_item)
   408 	{
   409 	  *active_item << Gnome::Canvas::Properties::fill_color("red");
   410 	}
   411       break;
   412 
   413     case GDK_BUTTON_RELEASE:
   414       window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
   415       if(active_item)
   416 	{
   417 	  if( active_item == ( get_item_at (clicked_x, clicked_y) ) )
   418 	    {
   419 	      if(active_node!=INVALID)
   420 		{
   421 
   422 		  //collecting edges to delete
   423 		  EdgeIt e;
   424 		  std::set<Graph::Edge> edges_to_delete;
   425 
   426 		  g.firstOut(e,active_node);
   427 		  for(;e!=INVALID;g.nextOut(e))
   428 		    {
   429 		      edges_to_delete.insert(e);
   430 		    }
   431 
   432 		  g.firstIn(e,active_node);
   433 		  for(;e!=INVALID;g.nextIn(e))
   434 		    {
   435 		      edges_to_delete.insert(e);
   436 		    }
   437 
   438 		  //deleting collected edges
   439 		  for(std::set<Graph::Edge>::iterator edge_set_it=edges_to_delete.begin();edge_set_it!=edges_to_delete.end();edge_set_it++)
   440 		    {
   441 		      deleteItem(*edge_set_it);
   442 		    }
   443 		  deleteItem(active_node);
   444 		}
   445 	      //a simple edge was chosen
   446 	      else
   447 		{
   448 		  deleteItem(active_edge);
   449 		}
   450 	    }
   451 	  //pointer was moved, deletion is cancelled
   452 	  else
   453 	    {
   454 	      if(active_node!=INVALID)
   455 		{
   456 		  *active_item << Gnome::Canvas::Properties::fill_color("blue");
   457 		}
   458 	      else
   459 		{
   460 		  *active_item << Gnome::Canvas::Properties::fill_color("green");
   461 		}
   462 	    }
   463 	}
   464       //reseting datas
   465       active_item=NULL;
   466       active_edge=INVALID;
   467       active_node=INVALID;
   468       break;
   469 
   470     case GDK_MOTION_NOTIFY:
   471       break;
   472 
   473     default:
   474       break;
   475     }
   476   return false;
   477 }
   478 
   479 void GraphDisplayerCanvas::deleteItem(NodeIt node_to_delete)
   480 {
   481   delete(nodetextmap[node_to_delete]);
   482   delete(nodesmap[node_to_delete]);
   483   g.erase(node_to_delete);
   484 }
   485 
   486 void GraphDisplayerCanvas::deleteItem(EdgeIt edge_to_delete)
   487 {
   488   delete(edgetextmap[edge_to_delete]);
   489   delete(edgesmap[edge_to_delete]);
   490   g.erase(edge_to_delete);
   491 }
   492 
   493 void GraphDisplayerCanvas::deleteItem(Graph::Edge edge_to_delete)
   494 {
   495   delete(edgetextmap[edge_to_delete]);
   496   delete(edgesmap[edge_to_delete]);
   497   g.erase(edge_to_delete);
   498 }
   499 
   500 void GraphDisplayerCanvas::textReposition(xy<double> new_place)
   501 {
   502   new_place+=(xy<double>(10,10));
   503   edgetextmap[active_edge]->property_x().set_value(new_place.x);
   504   edgetextmap[active_edge]->property_y().set_value(new_place.y);
   505 }
   506 
   507 void GraphDisplayerCanvas::toggleEdgeActivity(BrokenEdge* active_bre, bool on)
   508 {
   509   if(on)
   510     {
   511       if(active_edge!=INVALID)
   512 	{
   513 	  std::cout << "ERROR!!!! Valid edge found!" << std::endl;
   514 	}
   515       else
   516 	{
   517 	  for (EdgeIt i(g); i!=INVALID; ++i)
   518 	    {
   519 	      if(edgesmap[i]==active_bre)
   520 		{
   521 		  active_edge=i;
   522 		}
   523 	    }
   524 	}
   525     }
   526   else
   527     {
   528       if(active_edge!=INVALID)
   529 	{
   530 	  active_edge=INVALID;
   531 	}
   532       else
   533 	{
   534 	  std::cout << "ERROR!!!! Invalid edge found!" << std::endl;
   535 	}
   536     }
   537 
   538 }