updated required automake/autoconf versions (autoconf 2.57 is surely not enough; couldn't test with 2.58)
1 #include <graph_displayer_canvas.h>
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)
7 actual_handler=displayed_graph.signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::create_edge_event_handler), false);
12 //set_center_scroll_region(true);
14 //first edges are drawn, to hide joining with nodes later
16 for (EdgeIt i(g); i!=INVALID; ++i)
19 //drawing green lines, coordinates are from cm
21 Gnome::Canvas::Points coos;
22 coos.push_back(Gnome::Art::Point(cm[g.source(i)].x,cm[g.source(i)].y));
23 coos.push_back(Gnome::Art::Point(cm[g.target(i)].x,cm[g.target(i)].y));
25 edgesmap[i]=new Gnome::Canvas::Line(displayed_graph, coos);
26 *(edgesmap[i]) << Gnome::Canvas::Properties::fill_color("green");
27 edgesmap[i]->property_width_pixels().set_value(10);
29 //initializing edge-text as well, to empty string
31 double x1, x2, y1, y2;
32 edgesmap[i]->get_bounds(x1, y1, x2, y2);
34 edgetextmap[i]=new Gnome::Canvas::Text(displayed_graph,(x1+x2)/2, (y1+y2)/2, "");
35 edgetextmap[i]->property_fill_color().set_value("black");
38 //afterwards nodes come to be drawn
41 int maxx=0, maxy=0, minx=(int)cm[i].x, miny=(int)cm[i].y;
43 for (; i!=INVALID; ++i)
45 //minimum and maximum is gathered to be able to zoom to the graph correctly (whole figure should be seen)
47 if(cm[i].x>maxx)maxx=(int)cm[i].x;
48 if(cm[i].y>maxy)maxy=(int)cm[i].y;
49 if(cm[i].x<minx)minx=(int)cm[i].x;
50 if(cm[i].y<miny)miny=(int)cm[i].y;
52 //drawing bule nodes, with black line around them
54 nodesmap[i]=new Gnome::Canvas::Ellipse(displayed_graph, cm[i].x-20, cm[i].y-20, cm[i].x+20, cm[i].y+20);
55 *(nodesmap[i]) << Gnome::Canvas::Properties::fill_color("blue");
56 *(nodesmap[i]) << Gnome::Canvas::Properties::outline_color("black");
57 //!!!!!!! (nodesmap[i])->signal_event().connect(sigc::bind(sigc::mem_fun(*this, &GraphDisplayerCanvas::event_handler),i));
63 GraphDisplayerCanvas::~GraphDisplayerCanvas()
66 //writing out the end state of the graph
67 //\todo all the maps has to be write out!
69 Graph::NodeMap <int> id(g);
70 Graph::NodeMap <double> xc(g);
71 Graph::NodeMap <double> yc(g);
75 for (NodeIt i(g); i!=INVALID; ++i)
78 nodesmap[i]->get_bounds(x1, y1, x2, y2);
85 GraphWriter<Graph> writer(std::cout,g);
87 writer.writeNodeMap("id", id);
88 writer.writeNodeMap("coordinates_x", xc);
89 writer.writeNodeMap("coordinates_y", yc);
93 int GraphDisplayerCanvas::changeLineWidth (std::string mapname)
95 for (EdgeIt i(g); i!=INVALID; ++i)
97 int w=(int)(*(mapstorage.edgemap_storage)[mapname])[i];
98 edgesmap[i]->property_width_pixels().set_value(w);
103 int GraphDisplayerCanvas::changeColor (std::string mapname)
106 //function maps the range of the maximum and
107 //the minimum of the nodemap to the range of
110 for (EdgeIt i(g); i!=INVALID; ++i)
112 double w=(*(mapstorage.edgemap_storage)[mapname])[i];
113 double max=mapstorage.maxOfEdgeMap(mapname);
114 double min=mapstorage.minOfEdgeMap(mapname);
116 //std::cout<<w<<" "<<max<<" "<<min<<" "<<100*(w-min)/(max-min)<<std::endl;
120 color.set_rgb_p (0, 100*(w-min)/(max-min), 0);
124 color.set_rgb_p (0, 100, 0);
127 edgesmap[i]->property_fill_color_gdk().set_value(color);
132 int GraphDisplayerCanvas::changeText (std::string mapname)
135 //the number in the map will be written on the edge
136 //EXCEPT when the name of the map is Text, because
137 //in that case empty string will be written, because
138 //that is the deleter map
139 //\todo isn't it a bit woodcutter?
141 for (EdgeIt i(g); i!=INVALID; ++i)
145 double number=(*(mapstorage.edgemap_storage)[mapname])[i];
146 int length=(int)(floor(log(number)/log(10)))+1;
147 int maxpos=(int)(pow(10,length-1));
148 int strl=length+1+RANGE;
149 char * str=new char[strl];
153 for(int j=0;j<strl;j++)
157 int digit=(int)(number/maxpos);
159 number-=digit*maxpos;
164 edgetextmap[i]->property_text().set_value(str);
168 edgetextmap[i]->property_text().set_value("");
174 bool GraphDisplayerCanvas::event_handler(GdkEvent* e, Node n)
178 case GDK_BUTTON_PRESS:
179 //we mark the location of the event to be able to calculate parameters of dragging
180 clicked_x=e->button.x;
181 clicked_y=e->button.y;
182 active_item=(get_item_at(e->button.x, e->button.y));
185 case GDK_BUTTON_RELEASE:
188 updateScrollRegion();
190 case GDK_MOTION_NOTIFY:
191 //we only have to do sg. if the mouse button is pressed
194 //new coordinates will be the old values,
195 //because the item will be moved to the
196 //new coordinate therefore the new movement
197 //has to be calculated from here
199 double dx=e->motion.x-clicked_x;
200 double dy=e->motion.y-clicked_y;
201 active_item->move(dx, dy);
202 clicked_x=e->motion.x;
203 clicked_y=e->motion.y;
205 //all the edges connected to the moved point has to be redrawn
209 for(;e!=INVALID;g.nextOut(e))
211 Gnome::Canvas::Points coos;
212 double x1, x2, y1, y2;
214 nodesmap[g.source(e)]->get_bounds(x1, y1, x2, y2);
215 coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
217 nodesmap[g.target(e)]->get_bounds(x1, y1, x2, y2);
218 coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
220 edgesmap[e]->property_points().set_value(coos);
222 edgesmap[e]->get_bounds(x1, y1, x2, y2);
224 edgetextmap[e]->property_x().set_value((x1+x2)/2);
225 edgetextmap[e]->property_y().set_value((y1+y2)/2);
229 for(;e!=INVALID;g.nextIn(e))
231 Gnome::Canvas::Points coos;
232 double x1, x2, y1, y2;
234 nodesmap[g.source(e)]->get_bounds(x1, y1, x2, y2);
235 coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
237 nodesmap[g.target(e)]->get_bounds(x1, y1, x2, y2);
238 coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
240 edgesmap[e]->property_points().set_value(coos);
242 edgesmap[e]->get_bounds(x1, y1, x2, y2);
244 edgetextmap[e]->property_x().set_value((x1+x2)/2);
245 edgetextmap[e]->property_y().set_value((y1+y2)/2);
253 bool GraphDisplayerCanvas::on_expose_event(GdkEventExpose *event)
255 Gnome::Canvas::CanvasAA::on_expose_event(event);
261 void GraphDisplayerCanvas::zoomIn()
264 (1.0 + (double) zoom_step / 100.0) * get_pixels_per_unit());
267 void GraphDisplayerCanvas::zoomOut()
270 (1.0 - (double) zoom_step / 100.0) * get_pixels_per_unit());
273 void GraphDisplayerCanvas::zoomFit()
275 // get the height and width of the canvas
276 Gtk::Allocation a = get_allocation();
277 int aw = a.get_width();
278 int ah = a.get_height();
280 aw -= 5; if (aw < 0) aw = 0;
281 ah -= 5; if (ah < 0) ah = 0;
283 // get the bounding box of the graph
284 double wx1, wy1, wx2, wy2;
285 Gnome::Canvas::Item* pCanvasItem = root();
286 pCanvasItem->get_bounds(wx1, wy1, wx2, wy2);
288 // fit the graph to the window
289 double ppu1 = (double) aw / fabs(wx2 - wx1);
290 double ppu2 = (double) ah / fabs(wy2 - wy1);
291 set_pixels_per_unit((ppu1 < ppu2) ? ppu1 : ppu2);
294 void GraphDisplayerCanvas::zoom100()
296 set_pixels_per_unit(1.0);
299 void GraphDisplayerCanvas::updateScrollRegion()
301 double wx1, wy1, wx2, wy2;
302 Gnome::Canvas::Item* pCanvasItem = root();
303 pCanvasItem->get_bounds(wx1, wy1, wx2, wy2);
304 set_scroll_region(wx1, wy1, wx2, wy2);
307 void GraphDisplayerCanvas::changeEditorialTool(int newtool)
309 actual_handler.disconnect();
314 actual_handler=displayed_graph.signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::move_event_handler), false);
317 //it has to assigned to canvas, because all the canvas has to be monitored, not only the elements of the already drawn group
319 actual_handler=signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::create_node_event_handler), false);
323 actual_handler=displayed_graph.signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::create_edge_event_handler), false);
330 bool GraphDisplayerCanvas::move_event_handler(GdkEvent* e)
334 case GDK_BUTTON_PRESS:
335 //we mark the location of the event to be able to calculate parameters of dragging
336 clicked_x=e->button.x;
337 clicked_y=e->button.y;
338 active_item=(get_item_at(e->button.x, e->button.y));
340 for (NodeIt i(g); i!=INVALID; ++i)
342 if(nodesmap[i]==active_item)
349 case GDK_BUTTON_RELEASE:
353 updateScrollRegion();
355 case GDK_MOTION_NOTIFY:
356 //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
357 if(active_node!=INVALID)
359 //new coordinates will be the old values,
360 //because the item will be moved to the
361 //new coordinate therefore the new movement
362 //has to be calculated from here
364 double dx=e->motion.x-clicked_x;
365 double dy=e->motion.y-clicked_y;
367 active_item->move(dx, dy);
369 clicked_x=e->motion.x;
370 clicked_y=e->motion.y;
372 //all the edges connected to the moved point has to be redrawn
375 g.firstOut(e,active_node);
377 for(;e!=INVALID;g.nextOut(e))
379 Gnome::Canvas::Points coos;
380 double x1, x2, y1, y2;
382 nodesmap[g.source(e)]->get_bounds(x1, y1, x2, y2);
383 coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
385 nodesmap[g.target(e)]->get_bounds(x1, y1, x2, y2);
386 coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
388 edgesmap[e]->property_points().set_value(coos);
390 edgesmap[e]->get_bounds(x1, y1, x2, y2);
392 edgetextmap[e]->property_x().set_value((x1+x2)/2);
393 edgetextmap[e]->property_y().set_value((y1+y2)/2);
396 g.firstIn(e,active_node);
397 for(;e!=INVALID;g.nextIn(e))
399 Gnome::Canvas::Points coos;
400 double x1, x2, y1, y2;
402 nodesmap[g.source(e)]->get_bounds(x1, y1, x2, y2);
403 coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
405 nodesmap[g.target(e)]->get_bounds(x1, y1, x2, y2);
406 coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
408 edgesmap[e]->property_points().set_value(coos);
410 edgesmap[e]->get_bounds(x1, y1, x2, y2);
412 edgetextmap[e]->property_x().set_value((x1+x2)/2);
413 edgetextmap[e]->property_y().set_value((y1+y2)/2);
422 bool GraphDisplayerCanvas::create_node_event_handler(GdkEvent* e)
427 //draw the new node in red at the clicked place
428 case GDK_BUTTON_PRESS:
431 active_node=NodeIt(g,g.addNode());
433 window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
435 nodesmap[active_node]=new Gnome::Canvas::Ellipse(displayed_graph, clicked_x-20, clicked_y-20, clicked_x+20, clicked_y+20);
436 active_item=(Gnome::Canvas::Item *)(nodesmap[active_node]);
437 *(nodesmap[active_node]) << Gnome::Canvas::Properties::fill_color("red");
438 *(nodesmap[active_node]) << Gnome::Canvas::Properties::outline_color("black");
439 (nodesmap[active_node])->show();
443 case GDK_MOTION_NOTIFY:
445 double world_motion_x, world_motion_y;
446 GdkEvent * generated=new GdkEvent();
447 window_to_world (e->motion.x, e->motion.y, world_motion_x, world_motion_y);
448 generated->motion.x=world_motion_x;
449 generated->motion.y=world_motion_y;
450 generated->type=GDK_MOTION_NOTIFY;
451 move_event_handler(generated);
455 //finalize the new node
456 case GDK_BUTTON_RELEASE:
458 *active_item << Gnome::Canvas::Properties::fill_color("blue");
461 updateScrollRegion();
469 bool GraphDisplayerCanvas::create_edge_event_handler(GdkEvent* e)
473 case GDK_BUTTON_PRESS:
474 //in edge creatino right button has special meaning
475 if(e->button.button!=3)
477 //there is not yet selected node
478 if(active_node==INVALID)
480 //we mark the location of the event to be able to calculate parameters of dragging
481 clicked_x=e->button.x;
482 clicked_y=e->button.y;
483 active_item=(get_item_at(e->button.x, e->button.y));
485 for (NodeIt i(g); i!=INVALID; ++i)
487 if(nodesmap[i]==active_item)
492 //the clicked item is really a node
493 if(active_node!=INVALID)
495 *(nodesmap[active_node]) << Gnome::Canvas::Properties::fill_color("red");
498 //clicked item was not a node. It could be e.g. edge.
504 //we only have to do sg. if the mouse button
505 // is pressed already once AND the click was
506 // on a node that was found in the set of
507 //nodes, and now we only search for the second
511 target_item=(get_item_at(e->button.x, e->button.y));
512 Graph::NodeIt target_node=INVALID;
513 for (NodeIt i(g); i!=INVALID; ++i)
515 if(nodesmap[i]==target_item)
520 //the clicked item is a node, the edge can be drawn
521 if(target_node!=INVALID)
523 *(nodesmap[target_node]) << Gnome::Canvas::Properties::fill_color("red");
526 active_edge=EdgeIt(g,g.addEdge(active_node, target_node));
528 //calculating coordinates of new edge
529 Gnome::Canvas::Points coos;
530 double x1, x2, y1, y2;
532 active_item->get_bounds(x1, y1, x2, y2);
533 coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
535 target_item->get_bounds(x1, y1, x2, y2);
536 coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
539 edgesmap[active_edge]=new Gnome::Canvas::Line(displayed_graph, coos);
540 *(edgesmap[active_edge]) << Gnome::Canvas::Properties::fill_color("green");
541 edgesmap[active_edge]->property_width_pixels().set_value(10);
543 //redraw nodes to blank terminations of the new edge
544 target_item->raise_to_top();
545 active_item->raise_to_top();
547 //initializing edge-text as well, to empty string
548 edgesmap[active_edge]->get_bounds(x1, y1, x2, y2);
549 edgetextmap[active_edge]=new Gnome::Canvas::Text(displayed_graph,(x1+x2)/2, (y1+y2)/2, "");
550 edgetextmap[active_edge]->property_fill_color().set_value("black");
552 //clicked item was not a node. it could be an e.g. edge. we do not deal with it furthermore.
560 case GDK_BUTTON_RELEASE:
562 //we clear settings in two cases
563 //1: the edge is ready (target_item has valid value)
564 //2: the edge creation is cancelled with right button
565 if((target_item)||(e->button.button==3))
569 *active_item << Gnome::Canvas::Properties::fill_color("blue");
574 *target_item << Gnome::Canvas::Properties::fill_color("blue");