COIN-OR::LEMON - Graph Library

source: glemon-0.x/graph_displayer_canvas.cc @ 11:09b2a893fc9d

gui
Last change on this file since 11:09b2a893fc9d was 11:09b2a893fc9d, checked in by Hegyi Péter, 14 years ago

Edge creation is available.

  • Property exe set to *
File size: 14.8 KB
Line 
1#include <graph_displayer_canvas.h>
2#include <math.h>
3
4GraphDisplayerCanvas::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
60GraphDisplayerCanvas::~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
90int 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
100int 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
129int 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
171bool 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
250bool 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
258void GraphDisplayerCanvas::zoomIn()
259{
260  set_pixels_per_unit(
261      (1.0 + (double) zoom_step / 100.0) * get_pixels_per_unit());
262}
263
264void GraphDisplayerCanvas::zoomOut()
265{
266  set_pixels_per_unit(
267      (1.0 - (double) zoom_step / 100.0) * get_pixels_per_unit());
268}
269
270void 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
291void GraphDisplayerCanvas::zoom100()
292{
293  set_pixels_per_unit(1.0);
294}
295
296void 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
304void 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
324bool 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
415bool 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
455bool 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
Note: See TracBrowser for help on using the repository browser.