gui/graph_displayer_canvas.cc
author hegyi
Mon, 13 Jun 2005 10:30:08 +0000
changeset 1474 75c6d2eb187a
parent 1468 d0ccb2fdeeff
child 1478 bc7ae573d77d
permissions -rwxr-xr-x
Edge creation is available.
     1 #include <graph_displayer_canvas.h>
     2 #include <math.h>
     3 
     4 GraphDisplayerCanvas::GraphDisplayerCanvas(Graph & gr, CoordinatesMap & cm, MapStorage & ms):g(gr),nodesmap(g),edgesmap(g),edgetextmap(g),displayed_graph(*(root()), 0, 0),mapstorage(ms),isbutton(false),active_item(NULL),target_item(NULL)
     5 {
     6   
     7   actual_handler=displayed_graph.signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::create_edge_event_handler), false);
     8 
     9   //set_center_scroll_region(true);
    10 
    11   //first edges are drawn, to hide joining with nodes later
    12 
    13   for (EdgeIt i(g); i!=INVALID; ++i)
    14   {
    15 
    16     //drawing green lines, coordinates are from cm
    17 
    18     Gnome::Canvas::Points coos;
    19     coos.push_back(Gnome::Art::Point(cm[g.source(i)].x,cm[g.source(i)].y));
    20     coos.push_back(Gnome::Art::Point(cm[g.target(i)].x,cm[g.target(i)].y));
    21     
    22     edgesmap[i]=new Gnome::Canvas::Line(displayed_graph, coos);
    23     *(edgesmap[i]) << Gnome::Canvas::Properties::fill_color("green");
    24     edgesmap[i]->property_width_pixels().set_value(10);    
    25     
    26     //initializing edge-text as well, to empty string
    27 
    28     double x1, x2, y1, y2;
    29     edgesmap[i]->get_bounds(x1, y1, x2, y2);
    30     
    31     edgetextmap[i]=new Gnome::Canvas::Text(displayed_graph,(x1+x2)/2, (y1+y2)/2, "");
    32     edgetextmap[i]->property_fill_color().set_value("black");
    33   }
    34 
    35   //afterwards nodes come to be drawn
    36 
    37   NodeIt i(g);
    38   int maxx=0, maxy=0, minx=(int)cm[i].x, miny=(int)cm[i].y;
    39 
    40   for (; i!=INVALID; ++i)
    41   {
    42     //minimum and maximum is gathered to be able to zoom to the graph correctly (whole figure should be seen)
    43 
    44     if(cm[i].x>maxx)maxx=(int)cm[i].x;
    45     if(cm[i].y>maxy)maxy=(int)cm[i].y;
    46     if(cm[i].x<minx)minx=(int)cm[i].x;
    47     if(cm[i].y<miny)miny=(int)cm[i].y;
    48 
    49     //drawing bule nodes, with black line around them
    50 
    51     nodesmap[i]=new Gnome::Canvas::Ellipse(displayed_graph, cm[i].x-20, cm[i].y-20, cm[i].x+20, cm[i].y+20);
    52     *(nodesmap[i]) << Gnome::Canvas::Properties::fill_color("blue");
    53     *(nodesmap[i]) << Gnome::Canvas::Properties::outline_color("black");
    54     //!!!!!!! (nodesmap[i])->signal_event().connect(sigc::bind(sigc::mem_fun(*this, &GraphDisplayerCanvas::event_handler),i));
    55   }
    56 
    57   updateScrollRegion();
    58 }
    59 
    60 GraphDisplayerCanvas::~GraphDisplayerCanvas()
    61 {
    62 
    63   //writing out the end state of the graph
    64   //\todo all the maps has to be write out!
    65 
    66   Graph::NodeMap <int> id(g);
    67   Graph::NodeMap <double> xc(g);
    68   Graph::NodeMap <double> yc(g);
    69   
    70   int j=1;
    71   
    72   for (NodeIt i(g); i!=INVALID; ++i)
    73   {
    74     double x1,y1,x2,y2;
    75     nodesmap[i]->get_bounds(x1, y1, x2, y2);
    76     
    77     id[i]=j++;
    78     xc[i]=(x1+x2)/2;
    79     yc[i]=(y1+y2)/2;
    80   }
    81 
    82   GraphWriter<Graph> writer(std::cout,g);
    83   
    84   writer.writeNodeMap("id", id);
    85   writer.writeNodeMap("coordinates_x", xc);
    86   writer.writeNodeMap("coordinates_y", yc);
    87   writer.run();
    88 }
    89 
    90 int GraphDisplayerCanvas::changeLineWidth (std::string mapname)
    91 {
    92   for (EdgeIt i(g); i!=INVALID; ++i)
    93   {
    94     int w=(int)(*(mapstorage.edgemap_storage)[mapname])[i];
    95     edgesmap[i]->property_width_pixels().set_value(w);
    96   }
    97   return 0;
    98 };
    99 
   100 int GraphDisplayerCanvas::changeColor (std::string mapname)
   101 {  
   102 
   103   //function maps the range of the maximum and
   104   //the minimum of the nodemap to the range of
   105   //green in RGB
   106 
   107   for (EdgeIt i(g); i!=INVALID; ++i)
   108   {
   109     double w=(*(mapstorage.edgemap_storage)[mapname])[i];
   110     double max=mapstorage.maxOfEdgeMap(mapname);
   111     double min=mapstorage.minOfEdgeMap(mapname);
   112       
   113     //std::cout<<w<<" "<<max<<" "<<min<<" "<<100*(w-min)/(max-min)<<std::endl;
   114     Gdk::Color color;
   115     if(max!=min)
   116     {
   117       color.set_rgb_p (0, 100*(w-min)/(max-min), 0);
   118     }
   119     else
   120     {
   121       color.set_rgb_p (0, 100, 0);
   122     }
   123 
   124     edgesmap[i]->property_fill_color_gdk().set_value(color);
   125   }
   126   return 0;
   127 };
   128 
   129 int GraphDisplayerCanvas::changeText (std::string mapname)
   130 {
   131 
   132   //the number in the map will be written on the edge
   133   //EXCEPT when the name of the map is Text, because
   134   //in that case empty string will be written, because
   135   //that is the deleter map
   136   //\todo isn't it a bit woodcutter?
   137 
   138   for (EdgeIt i(g); i!=INVALID; ++i)
   139   {
   140     if(mapname!="Text")
   141     {
   142       double number=(*(mapstorage.edgemap_storage)[mapname])[i];
   143       int length=(int)(floor(log(number)/log(10)))+1;
   144       int maxpos=(int)(pow(10,length-1));
   145       int strl=length+1+RANGE;
   146       char * str=new char[strl];
   147       str[length]='.';
   148       str[strl]='\0';
   149       
   150       for(int j=0;j<strl;j++)
   151       {
   152 	if(j!=length)
   153         {
   154 	  int digit=(int)(number/maxpos);
   155 	  str[j]=(digit+'0');
   156 	  number-=digit*maxpos;
   157 	  number*=10;
   158         }
   159       }
   160       
   161       edgetextmap[i]->property_text().set_value(str);
   162     }
   163     else
   164     {
   165       edgetextmap[i]->property_text().set_value("");
   166     }
   167   }
   168   return 0;
   169 };
   170 
   171 bool GraphDisplayerCanvas::event_handler(GdkEvent* e, Node n)
   172 {
   173   switch(e->type)
   174   {
   175     case GDK_BUTTON_PRESS:
   176       //we mark the location of the event to be able to calculate parameters of dragging
   177       clicked_x=e->button.x;
   178       clicked_y=e->button.y;
   179       active_item=(get_item_at(e->button.x, e->button.y));
   180       isbutton=true;
   181       break;
   182     case GDK_BUTTON_RELEASE:
   183       isbutton=false;
   184       active_item=NULL;
   185       updateScrollRegion();
   186       break;
   187     case GDK_MOTION_NOTIFY:
   188       //we only have to do sg. if the mouse button is pressed
   189       if(isbutton)
   190       {
   191 	//new coordinates will be the old values,
   192 	//because the item will be moved to the
   193 	//new coordinate therefore the new movement
   194 	//has to be calculated from here
   195 
   196         double dx=e->motion.x-clicked_x;
   197         double dy=e->motion.y-clicked_y;
   198         active_item->move(dx, dy);
   199         clicked_x=e->motion.x;
   200         clicked_y=e->motion.y;
   201 
   202 	//all the edges connected to the moved point has to be redrawn
   203 
   204         EdgeIt e;
   205         g.firstOut(e,n);
   206         for(;e!=INVALID;g.nextOut(e))
   207         {
   208             Gnome::Canvas::Points coos;
   209             double x1, x2, y1, y2;
   210 
   211             nodesmap[g.source(e)]->get_bounds(x1, y1, x2, y2);
   212             coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
   213 
   214             nodesmap[g.target(e)]->get_bounds(x1, y1, x2, y2);
   215             coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
   216 
   217             edgesmap[e]->property_points().set_value(coos);
   218 
   219 	    edgesmap[e]->get_bounds(x1, y1, x2, y2);
   220 
   221 	    edgetextmap[e]->property_x().set_value((x1+x2)/2);
   222 	    edgetextmap[e]->property_y().set_value((y1+y2)/2);
   223         }
   224 
   225         g.firstIn(e,n);
   226         for(;e!=INVALID;g.nextIn(e))
   227         {
   228             Gnome::Canvas::Points coos;
   229             double x1, x2, y1, y2;
   230 
   231             nodesmap[g.source(e)]->get_bounds(x1, y1, x2, y2);
   232             coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
   233 
   234             nodesmap[g.target(e)]->get_bounds(x1, y1, x2, y2);
   235             coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
   236 
   237             edgesmap[e]->property_points().set_value(coos);
   238 
   239 	    edgesmap[e]->get_bounds(x1, y1, x2, y2);
   240 
   241 	    edgetextmap[e]->property_x().set_value((x1+x2)/2);
   242 	    edgetextmap[e]->property_y().set_value((y1+y2)/2);
   243         }
   244       }
   245     default: break;
   246   }
   247   return true;
   248 }
   249 
   250 bool GraphDisplayerCanvas::on_expose_event(GdkEventExpose *event)
   251 {
   252   Gnome::Canvas::CanvasAA::on_expose_event(event);
   253   //usleep(10000);
   254   //rezoom();
   255   return true;
   256 }
   257 
   258 void GraphDisplayerCanvas::zoomIn()
   259 {
   260   set_pixels_per_unit(
   261       (1.0 + (double) zoom_step / 100.0) * get_pixels_per_unit());
   262 }
   263 
   264 void GraphDisplayerCanvas::zoomOut()
   265 {
   266   set_pixels_per_unit(
   267       (1.0 - (double) zoom_step / 100.0) * get_pixels_per_unit());
   268 }
   269 
   270 void GraphDisplayerCanvas::zoomFit()
   271 {
   272   // get the height and width of the canvas
   273   Gtk::Allocation a = get_allocation();
   274   int aw = a.get_width();
   275   int ah = a.get_height();
   276   // add some space
   277   aw -= 5; if (aw < 0) aw = 0;
   278   ah -= 5; if (ah < 0) ah = 0;
   279 
   280   // get the bounding box of the graph
   281   double wx1, wy1, wx2, wy2;
   282   Gnome::Canvas::Item* pCanvasItem = root();
   283   pCanvasItem->get_bounds(wx1, wy1, wx2, wy2);
   284 
   285   // fit the graph to the window
   286   double ppu1 = (double) aw / fabs(wx2 - wx1);
   287   double ppu2 = (double) ah / fabs(wy2 - wy1);
   288   set_pixels_per_unit((ppu1 < ppu2) ? ppu1 : ppu2);
   289 }
   290 
   291 void GraphDisplayerCanvas::zoom100()
   292 {
   293   set_pixels_per_unit(1.0);
   294 }
   295 
   296 void GraphDisplayerCanvas::updateScrollRegion()
   297 {
   298   double wx1, wy1, wx2, wy2;
   299   Gnome::Canvas::Item* pCanvasItem = root();
   300   pCanvasItem->get_bounds(wx1, wy1, wx2, wy2);
   301   set_scroll_region(wx1, wy1, wx2, wy2);
   302 }
   303 
   304 void GraphDisplayerCanvas::changeEditorialTool(int newtool)
   305 {
   306   actual_handler.disconnect();
   307 
   308   switch(newtool)
   309     {
   310     case MOVE:
   311       actual_handler=displayed_graph.signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::move_event_handler), false);
   312       break;
   313     case CREATE_NODE:
   314       actual_handler=signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::create_node_event_handler), false);
   315       break;
   316     case CREATE_EDGE:
   317       actual_handler=displayed_graph.signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::create_edge_event_handler), false);
   318       break;
   319     default:
   320       break;
   321     }
   322 }
   323 
   324 bool GraphDisplayerCanvas::move_event_handler(GdkEvent* e)
   325 {
   326   switch(e->type)
   327   {
   328     case GDK_BUTTON_PRESS:
   329       //we mark the location of the event to be able to calculate parameters of dragging
   330       clicked_x=e->button.x;
   331       clicked_y=e->button.y;
   332       active_item=(get_item_at(e->button.x, e->button.y));
   333       active_node=INVALID;
   334       for (NodeIt i(g); i!=INVALID; ++i)
   335 	{
   336 	  if(nodesmap[i]==active_item)
   337 	    {
   338 	      active_node=i;
   339 	    }
   340 	}
   341       isbutton=true;
   342       break;
   343     case GDK_BUTTON_RELEASE:
   344       isbutton=false;
   345       active_item=NULL;
   346       updateScrollRegion();
   347       break;
   348     case GDK_MOTION_NOTIFY:
   349       //we only have to do sg. if the mouse button is pressed
   350       if(isbutton)
   351       {
   352 	//new coordinates will be the old values,
   353 	//because the item will be moved to the
   354 	//new coordinate therefore the new movement
   355 	//has to be calculated from here
   356 
   357         double dx=e->motion.x-clicked_x;
   358         double dy=e->motion.y-clicked_y;
   359 
   360         active_item->move(dx, dy);
   361 
   362         clicked_x=e->motion.x;
   363         clicked_y=e->motion.y;
   364 
   365 	//all the edges connected to the moved point has to be redrawn
   366         EdgeIt e;
   367 
   368         g.firstOut(e,active_node);
   369 
   370         for(;e!=INVALID;g.nextOut(e))
   371         {
   372             Gnome::Canvas::Points coos;
   373             double x1, x2, y1, y2;
   374 
   375             nodesmap[g.source(e)]->get_bounds(x1, y1, x2, y2);
   376             coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
   377 
   378             nodesmap[g.target(e)]->get_bounds(x1, y1, x2, y2);
   379             coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
   380 
   381             edgesmap[e]->property_points().set_value(coos);
   382 
   383 	    edgesmap[e]->get_bounds(x1, y1, x2, y2);
   384 
   385 	    edgetextmap[e]->property_x().set_value((x1+x2)/2);
   386 	    edgetextmap[e]->property_y().set_value((y1+y2)/2);
   387         }
   388 
   389         g.firstIn(e,active_node);
   390         for(;e!=INVALID;g.nextIn(e))
   391         {
   392             Gnome::Canvas::Points coos;
   393             double x1, x2, y1, y2;
   394 
   395             nodesmap[g.source(e)]->get_bounds(x1, y1, x2, y2);
   396             coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
   397 
   398             nodesmap[g.target(e)]->get_bounds(x1, y1, x2, y2);
   399             coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
   400 
   401             edgesmap[e]->property_points().set_value(coos);
   402 
   403 	    edgesmap[e]->get_bounds(x1, y1, x2, y2);
   404 
   405 	    edgetextmap[e]->property_x().set_value((x1+x2)/2);
   406 	    edgetextmap[e]->property_y().set_value((y1+y2)/2);
   407         }
   408       }
   409     default: break;
   410   }
   411 
   412   return true;
   413 }
   414 
   415 bool GraphDisplayerCanvas::create_node_event_handler(GdkEvent* e)
   416 {
   417   switch(e->type)
   418     {
   419     case GDK_BUTTON_PRESS:
   420       isbutton=true;
   421 
   422       active_node=NodeIt(g,g.addNode());
   423 
   424       window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
   425 
   426       nodesmap[active_node]=new Gnome::Canvas::Ellipse(displayed_graph, clicked_x-20, clicked_y-20, clicked_x+20, clicked_y+20);
   427       active_item=(Gnome::Canvas::Item *)(nodesmap[active_node]);
   428       *(nodesmap[active_node]) << Gnome::Canvas::Properties::fill_color("red");
   429       *(nodesmap[active_node]) << Gnome::Canvas::Properties::outline_color("black");
   430       (nodesmap[active_node])->show();
   431       break;
   432     case GDK_MOTION_NOTIFY:
   433       {
   434 	double world_motion_x, world_motion_y;
   435 	GdkEvent * generated=new GdkEvent();
   436 	window_to_world (e->motion.x, e->motion.y, world_motion_x, world_motion_y);
   437 	generated->motion.x=world_motion_x;
   438 	generated->motion.y=world_motion_y;
   439 	generated->type=GDK_MOTION_NOTIFY;
   440 	move_event_handler(generated);      
   441 	break;
   442       }
   443     case GDK_BUTTON_RELEASE:
   444       isbutton=false;
   445       *active_item << Gnome::Canvas::Properties::fill_color("blue");
   446       active_item=NULL;
   447       updateScrollRegion();
   448       break;
   449     default:
   450       break;
   451     }
   452   return false;
   453 }
   454 
   455 bool GraphDisplayerCanvas::create_edge_event_handler(GdkEvent* e)
   456 {
   457   switch(e->type)
   458     {
   459     case GDK_BUTTON_PRESS:
   460       if(!active_item)
   461 	{
   462 	  //we mark the location of the event to be able to calculate parameters of dragging
   463 	  clicked_x=e->button.x;
   464 	  clicked_y=e->button.y;
   465 	  active_item=(get_item_at(e->button.x, e->button.y));
   466 	  active_node=INVALID;
   467 	  for (NodeIt i(g); i!=INVALID; ++i)
   468 	    {
   469 	      if(nodesmap[i]==active_item)
   470 		{
   471 		  active_node=i;
   472 		}
   473 	    }
   474 	  *(nodesmap[active_node]) << Gnome::Canvas::Properties::fill_color("red");
   475 	  isbutton=true;
   476 	}
   477       else
   478 	{
   479 	  target_item=(get_item_at(e->button.x, e->button.y));
   480 	  Graph::NodeIt target_node=INVALID;
   481 	  for (NodeIt i(g); i!=INVALID; ++i)
   482 	    {
   483 	      if(nodesmap[i]==target_item)
   484 		{
   485 		  target_node=i;
   486 		}
   487 	    }
   488 	  *(nodesmap[target_node]) << Gnome::Canvas::Properties::fill_color("red");
   489 
   490 	  //creating new edge
   491 	  //	  Graph::Edge new_edge=g.addEdge(active_node, target_node);
   492 	  active_edge=EdgeIt(g,g.addEdge(active_node, target_node));
   493 	  
   494 	  //calculating coordinates of new edge
   495 	  Gnome::Canvas::Points coos;
   496 	  double x1, x2, y1, y2;
   497 	  
   498 	  active_item->get_bounds(x1, y1, x2, y2);
   499 	  coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
   500 
   501 	  target_item->get_bounds(x1, y1, x2, y2);
   502 	  coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
   503 
   504 	  //drawing new edge
   505 	  edgesmap[active_edge]=new Gnome::Canvas::Line(displayed_graph, coos);
   506 	  *(edgesmap[active_edge]) << Gnome::Canvas::Properties::fill_color("green");
   507 	  edgesmap[active_edge]->property_width_pixels().set_value(10);
   508 
   509 	  //redraw nodes to blank terminations of the new edge
   510 	  target_item->raise_to_top();
   511 	  active_item->raise_to_top();
   512 
   513 	  //initializing edge-text as well, to empty string
   514 	  edgesmap[active_edge]->get_bounds(x1, y1, x2, y2);
   515 	  edgetextmap[active_edge]=new Gnome::Canvas::Text(displayed_graph,(x1+x2)/2, (y1+y2)/2, "");
   516 	  edgetextmap[active_edge]->property_fill_color().set_value("black");
   517 	}
   518       break;
   519     case GDK_BUTTON_RELEASE:
   520       isbutton=false;
   521       if(target_item)
   522 	{
   523 	  *active_item << Gnome::Canvas::Properties::fill_color("blue");
   524 	  *target_item << Gnome::Canvas::Properties::fill_color("blue");
   525 	  active_item=NULL;
   526 	  target_item=NULL;
   527 	}
   528       break;
   529     default:
   530       break;
   531     }
   532   return false;
   533 }
   534