A bug, explored by Alpar is corrected, but with value-checking, and not with correct values. (There is some problem with map values of new items! Maybe refreshemnt is the responsible thing?)
1 #include <graph_displayer_canvas.h>
2 #include <broken_edge.h>
5 GraphDisplayerCanvas::GraphDisplayerCanvas(Graph & gr, CoordinatesMap & cm, MapStorage & ms):g(gr),nodesmap(g),edgesmap(g),edgetextmap(g),displayed_graph(*(root()), 0, 0),mapstorage(ms),isbutton(0),active_item(NULL),target_item(NULL)
8 actual_handler=signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::create_node_event_handler), false);
9 actual_tool=CREATE_NODE;
14 //set_center_scroll_region(true);
16 //first edges are drawn, to hide joining with nodes later
18 for (EdgeIt i(g); i!=INVALID; ++i)
21 //drawing green lines, coordinates are from cm
23 Gnome::Canvas::Points coos;
24 coos.push_back(Gnome::Art::Point(cm[g.source(i)].x,cm[g.source(i)].y));
25 coos.push_back(Gnome::Art::Point(cm[g.target(i)].x,cm[g.target(i)].y));
27 edgesmap[i]=new BrokenEdge(displayed_graph, coos, *this);
28 *(edgesmap[i]) << Gnome::Canvas::Properties::fill_color("green");
29 edgesmap[i]->property_width_pixels().set_value(10);
31 //initializing edge-text as well, to empty string
33 xy<double> text_pos=edgesmap[i]->get_arrow_pos();
34 text_pos+=(xy<double>(10,10));
36 edgetextmap[i]=new Gnome::Canvas::Text(displayed_graph, text_pos.x, text_pos.y, "");
37 edgetextmap[i]->property_fill_color().set_value("black");
40 //afterwards nodes come to be drawn
43 int maxx=0, maxy=0, minx=(int)cm[i].x, miny=(int)cm[i].y;
45 for (; i!=INVALID; ++i)
47 //minimum and maximum is gathered to be able to zoom to the graph correctly (whole figure should be seen)
49 if(cm[i].x>maxx)maxx=(int)cm[i].x;
50 if(cm[i].y>maxy)maxy=(int)cm[i].y;
51 if(cm[i].x<minx)minx=(int)cm[i].x;
52 if(cm[i].y<miny)miny=(int)cm[i].y;
54 //drawing bule nodes, with black line around them
56 nodesmap[i]=new Gnome::Canvas::Ellipse(displayed_graph, cm[i].x-20, cm[i].y-20, cm[i].x+20, cm[i].y+20);
57 *(nodesmap[i]) << Gnome::Canvas::Properties::fill_color("blue");
58 *(nodesmap[i]) << Gnome::Canvas::Properties::outline_color("black");
59 //!!!!!!! (nodesmap[i])->signal_event().connect(sigc::bind(sigc::mem_fun(*this, &GraphDisplayerCanvas::event_handler),i));
65 GraphDisplayerCanvas::~GraphDisplayerCanvas()
68 //writing out the end state of the graph
69 //\todo all the maps has to be write out!
71 Graph::NodeMap <int> id(g);
72 Graph::NodeMap <double> xc(g);
73 Graph::NodeMap <double> yc(g);
77 for (NodeIt i(g); i!=INVALID; ++i)
80 nodesmap[i]->get_bounds(x1, y1, x2, y2);
87 GraphWriter<Graph> writer(std::cout,g);
89 writer.writeNodeMap("id", id);
90 writer.writeNodeMap("coordinates_x", xc);
91 writer.writeNodeMap("coordinates_y", yc);
95 int GraphDisplayerCanvas::changeLineWidth (std::string mapname)
97 for (EdgeIt i(g); i!=INVALID; ++i)
99 int w=(int)(*(mapstorage.edgemap_storage)[mapname])[i];
102 edgesmap[i]->property_width_pixels().set_value(w);
108 int GraphDisplayerCanvas::changeColor (std::string mapname)
111 //function maps the range of the maximum and
112 //the minimum of the nodemap to the range of
115 for (EdgeIt i(g); i!=INVALID; ++i)
117 double w=(*(mapstorage.edgemap_storage)[mapname])[i];
118 double max=mapstorage.maxOfEdgeMap(mapname);
119 double min=mapstorage.minOfEdgeMap(mapname);
121 //std::cout<<w<<" "<<max<<" "<<min<<" "<<100*(w-min)/(max-min)<<std::endl;
125 color.set_rgb_p (0, 100*(w-min)/(max-min), 0);
129 color.set_rgb_p (0, 100, 0);
132 edgesmap[i]->property_fill_color_gdk().set_value(color);
137 int GraphDisplayerCanvas::changeText (std::string mapname)
140 //the number in the map will be written on the edge
141 //EXCEPT when the name of the map is Text, because
142 //in that case empty string will be written, because
143 //that is the deleter map
144 //\todo isn't it a bit woodcutter?
146 for (EdgeIt i(g); i!=INVALID; ++i)
150 double number=(*(mapstorage.edgemap_storage)[mapname])[i];
152 //if number is smaller than one, length would be negative, or invalid
155 length=(int)(floor(log(number)/log(10)))+1;
157 int maxpos=(int)(pow(10,length-1));
158 int strl=length+1+RANGE;
159 char * str=new char[strl];
163 for(int j=0;j<strl;j++)
167 int digit=(int)(number/maxpos);
169 number-=digit*maxpos;
174 edgetextmap[i]->property_text().set_value(str);
178 edgetextmap[i]->property_text().set_value("");
185 bool GraphDisplayerCanvas::event_handler(GdkEvent* e, Node n)
189 case GDK_BUTTON_PRESS:
190 //we mark the location of the event to be able to calculate parameters of dragging
191 clicked_x=e->button.x;
192 clicked_y=e->button.y;
193 active_item=(get_item_at(e->button.x, e->button.y));
196 case GDK_BUTTON_RELEASE:
199 updateScrollRegion();
201 case GDK_MOTION_NOTIFY:
202 //we only have to do sg. if the mouse button is pressed
205 //new coordinates will be the old values,
206 //because the item will be moved to the
207 //new coordinate therefore the new movement
208 //has to be calculated from here
210 double dx=e->motion.x-clicked_x;
211 double dy=e->motion.y-clicked_y;
212 active_item->move(dx, dy);
213 clicked_x=e->motion.x;
214 clicked_y=e->motion.y;
216 //all the edges connected to the moved point has to be redrawn
220 for(;e!=INVALID;g.nextOut(e))
222 Gnome::Canvas::Points coos;
223 double x1, x2, y1, y2;
225 nodesmap[g.source(e)]->get_bounds(x1, y1, x2, y2);
226 coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
228 nodesmap[g.target(e)]->get_bounds(x1, y1, x2, y2);
229 coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
231 edgesmap[e]->property_points().set_value(coos);
233 edgesmap[e]->get_bounds(x1, y1, x2, y2);
235 edgetextmap[e]->property_x().set_value((x1+x2)/2);
236 edgetextmap[e]->property_y().set_value((y1+y2)/2);
240 for(;e!=INVALID;g.nextIn(e))
242 Gnome::Canvas::Points coos;
243 double x1, x2, y1, y2;
245 nodesmap[g.source(e)]->get_bounds(x1, y1, x2, y2);
246 coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
248 nodesmap[g.target(e)]->get_bounds(x1, y1, x2, y2);
249 coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
251 edgesmap[e]->property_points().set_value(coos);
253 edgesmap[e]->get_bounds(x1, y1, x2, y2);
255 edgetextmap[e]->property_x().set_value((x1+x2)/2);
256 edgetextmap[e]->property_y().set_value((y1+y2)/2);
264 bool GraphDisplayerCanvas::on_expose_event(GdkEventExpose *event)
266 Gnome::Canvas::CanvasAA::on_expose_event(event);
272 void GraphDisplayerCanvas::zoomIn()
275 (1.0 + (double) zoom_step / 100.0) * get_pixels_per_unit());
278 void GraphDisplayerCanvas::zoomOut()
281 (1.0 - (double) zoom_step / 100.0) * get_pixels_per_unit());
284 void GraphDisplayerCanvas::zoomFit()
286 // get the height and width of the canvas
287 Gtk::Allocation a = get_allocation();
288 int aw = a.get_width();
289 int ah = a.get_height();
291 aw -= 5; if (aw < 0) aw = 0;
292 ah -= 5; if (ah < 0) ah = 0;
294 // get the bounding box of the graph
295 double wx1, wy1, wx2, wy2;
296 Gnome::Canvas::Item* pCanvasItem = root();
297 pCanvasItem->get_bounds(wx1, wy1, wx2, wy2);
299 // fit the graph to the window
300 double ppu1 = (double) aw / fabs(wx2 - wx1);
301 double ppu2 = (double) ah / fabs(wy2 - wy1);
302 set_pixels_per_unit((ppu1 < ppu2) ? ppu1 : ppu2);
305 void GraphDisplayerCanvas::zoom100()
307 set_pixels_per_unit(1.0);
310 void GraphDisplayerCanvas::updateScrollRegion()
312 double wx1, wy1, wx2, wy2;
313 Gnome::Canvas::Item* pCanvasItem = root();
314 pCanvasItem->get_bounds(wx1, wy1, wx2, wy2);
315 set_scroll_region(wx1, wy1, wx2, wy2);
318 void GraphDisplayerCanvas::changeEditorialTool(int newtool)
320 actual_handler.disconnect();
322 if(actual_tool==CREATE_EDGE)
324 GdkEvent * generated=new GdkEvent();
325 generated->type=GDK_BUTTON_RELEASE;
326 generated->button.button=3;
327 create_edge_event_handler(generated);
335 actual_handler=displayed_graph.signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::move_event_handler), false);
338 //it has to assigned to canvas, because all the canvas has to be monitored, not only the elements of the already drawn group
340 actual_handler=signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::create_node_event_handler), false);
344 actual_handler=displayed_graph.signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::create_edge_event_handler), false);
348 actual_handler=displayed_graph.signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::eraser_event_handler), false);
356 int GraphDisplayerCanvas::get_actual_tool()
361 bool GraphDisplayerCanvas::move_event_handler(GdkEvent* e)
365 case GDK_BUTTON_PRESS:
366 //we mark the location of the event to be able to calculate parameters of dragging
367 clicked_x=e->button.x;
368 clicked_y=e->button.y;
369 active_item=(get_item_at(e->button.x, e->button.y));
371 for (NodeIt i(g); i!=INVALID; ++i)
373 if(nodesmap[i]==active_item)
378 switch(e->button.button)
388 case GDK_BUTTON_RELEASE:
392 updateScrollRegion();
394 case GDK_MOTION_NOTIFY:
395 //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
396 if(active_node!=INVALID)
398 //new coordinates will be the old values,
399 //because the item will be moved to the
400 //new coordinate therefore the new movement
401 //has to be calculated from here
403 double dx=e->motion.x-clicked_x;
404 double dy=e->motion.y-clicked_y;
406 active_item->move(dx, dy);
408 clicked_x=e->motion.x;
409 clicked_y=e->motion.y;
411 //all the edges connected to the moved point has to be redrawn
414 g.firstOut(ei,active_node);
416 for(;ei!=INVALID;g.nextOut(ei))
418 Gnome::Canvas::Points coos;
419 double x1, x2, y1, y2;
421 nodesmap[g.source(ei)]->get_bounds(x1, y1, x2, y2);
422 coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
424 nodesmap[g.target(ei)]->get_bounds(x1, y1, x2, y2);
425 coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
429 edgesmap[ei]->set_points(coos);
433 edgesmap[ei]->set_points(coos,true);
436 xy<double> text_pos=edgesmap[ei]->get_arrow_pos();
437 text_pos+=(xy<double>(10,10));
438 edgetextmap[ei]->property_x().set_value(text_pos.x);
439 edgetextmap[ei]->property_y().set_value(text_pos.y);
442 g.firstIn(ei,active_node);
443 for(;ei!=INVALID;g.nextIn(ei))
445 Gnome::Canvas::Points coos;
446 double x1, x2, y1, y2;
448 nodesmap[g.source(ei)]->get_bounds(x1, y1, x2, y2);
449 coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
451 nodesmap[g.target(ei)]->get_bounds(x1, y1, x2, y2);
452 coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
456 edgesmap[ei]->set_points(coos);
460 edgesmap[ei]->set_points(coos,true);
463 xy<double> text_pos=edgesmap[ei]->get_arrow_pos();
464 text_pos+=(xy<double>(10,10));
465 edgetextmap[ei]->property_x().set_value(text_pos.x);
466 edgetextmap[ei]->property_y().set_value(text_pos.y);
475 bool GraphDisplayerCanvas::create_node_event_handler(GdkEvent* e)
480 //draw the new node in red at the clicked place
481 case GDK_BUTTON_PRESS:
484 active_node=NodeIt(g,g.addNode());
486 //initiating values corresponding to new node in maps
489 window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
491 nodesmap[active_node]=new Gnome::Canvas::Ellipse(displayed_graph, clicked_x-20, clicked_y-20, clicked_x+20, clicked_y+20);
492 active_item=(Gnome::Canvas::Item *)(nodesmap[active_node]);
493 *(nodesmap[active_node]) << Gnome::Canvas::Properties::fill_color("red");
494 *(nodesmap[active_node]) << Gnome::Canvas::Properties::outline_color("black");
495 (nodesmap[active_node])->show();
499 case GDK_MOTION_NOTIFY:
501 double world_motion_x, world_motion_y;
502 GdkEvent * generated=new GdkEvent();
503 window_to_world (e->motion.x, e->motion.y, world_motion_x, world_motion_y);
504 generated->motion.x=world_motion_x;
505 generated->motion.y=world_motion_y;
506 generated->type=GDK_MOTION_NOTIFY;
507 move_event_handler(generated);
511 //finalize the new node
512 case GDK_BUTTON_RELEASE:
514 *active_item << Gnome::Canvas::Properties::fill_color("blue");
517 updateScrollRegion();
525 bool GraphDisplayerCanvas::create_edge_event_handler(GdkEvent* e)
529 case GDK_BUTTON_PRESS:
530 //in edge creation right button has special meaning
531 if(e->button.button!=3)
533 //there is not yet selected node
534 if(active_node==INVALID)
536 //we mark the location of the event to be able to calculate parameters of dragging
537 clicked_x=e->button.x;
538 clicked_y=e->button.y;
539 active_item=(get_item_at(e->button.x, e->button.y));
541 for (NodeIt i(g); i!=INVALID; ++i)
543 if(nodesmap[i]==active_item)
548 //the clicked item is really a node
549 if(active_node!=INVALID)
551 *(nodesmap[active_node]) << Gnome::Canvas::Properties::fill_color("red");
554 //clicked item was not a node. It could be e.g. edge.
560 //we only have to do sg. if the mouse button
561 // is pressed already once AND the click was
562 // on a node that was found in the set of
563 //nodes, and now we only search for the second
567 target_item=(get_item_at(e->button.x, e->button.y));
568 Graph::NodeIt target_node=INVALID;
569 for (NodeIt i(g); i!=INVALID; ++i)
571 if(nodesmap[i]==target_item)
576 //the clicked item is a node, the edge can be drawn
577 if(target_node!=INVALID)
579 *(nodesmap[target_node]) << Gnome::Canvas::Properties::fill_color("red");
582 active_edge=EdgeIt(g,g.addEdge(active_node, target_node));
584 //initiating values corresponding to new edge in maps
585 mapstorage.init_maps_for_edge(active_edge);
587 //calculating coordinates of new edge
588 Gnome::Canvas::Points coos;
589 double x1, x2, y1, y2;
591 active_item->get_bounds(x1, y1, x2, y2);
592 coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
594 target_item->get_bounds(x1, y1, x2, y2);
595 coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
598 edgesmap[active_edge]=new BrokenEdge(displayed_graph, coos, *this);
599 *(edgesmap[active_edge]) << Gnome::Canvas::Properties::fill_color("green");
600 edgesmap[active_edge]->property_width_pixels().set_value(10);
602 //redraw nodes to blank terminations of the new edge
603 target_item->raise_to_top();
604 active_item->raise_to_top();
606 //initializing edge-text as well, to empty string
607 xy<double> text_pos=edgesmap[active_edge]->get_arrow_pos();
608 text_pos+=(xy<double>(10,10));
610 edgetextmap[active_edge]=new Gnome::Canvas::Text(displayed_graph, text_pos.x, text_pos.y, "");
611 edgetextmap[active_edge]->property_fill_color().set_value("black");
613 //clicked item was not a node. it could be an e.g. edge. we do not deal with it furthermore.
621 case GDK_BUTTON_RELEASE:
623 //we clear settings in two cases
624 //1: the edge is ready (target_item has valid value)
625 //2: the edge creation is cancelled with right button
626 if((target_item)||(e->button.button==3))
630 *active_item << Gnome::Canvas::Properties::fill_color("blue");
635 *target_item << Gnome::Canvas::Properties::fill_color("blue");
648 bool GraphDisplayerCanvas::eraser_event_handler(GdkEvent* e)
652 case GDK_BUTTON_PRESS:
653 active_item=(get_item_at(e->button.x, e->button.y));
656 for (NodeIt i(g); i!=INVALID; ++i)
658 if(nodesmap[i]==active_item)
663 if(active_node==INVALID)
665 for (EdgeIt i(g); i!=INVALID; ++i)
667 if(edgesmap[i]==active_item)
673 *active_item << Gnome::Canvas::Properties::fill_color("red");
676 case GDK_BUTTON_RELEASE:
677 if(active_item==(get_item_at(e->button.x, e->button.y)))
679 if(active_node!=INVALID)
682 //collecting edges to delete
684 std::set<Graph::Edge> edges_to_delete;
686 g.firstOut(e,active_node);
687 for(;e!=INVALID;g.nextOut(e))
689 edges_to_delete.insert(e);
692 g.firstIn(e,active_node);
693 for(;e!=INVALID;g.nextIn(e))
695 edges_to_delete.insert(e);
698 //deleting collected edges
699 for(std::set<Graph::Edge>::iterator edge_set_it=edges_to_delete.begin();edge_set_it!=edges_to_delete.end();edge_set_it++)
701 delete_item(*edge_set_it);
703 delete_item(active_node);
705 //a simple edge was chosen
708 delete_item(active_edge);
713 //pointer was moved, deletion is cancelled
716 if(active_node!=INVALID)
718 *active_item << Gnome::Canvas::Properties::fill_color("blue");
722 *active_item << Gnome::Canvas::Properties::fill_color("green");
731 case GDK_MOTION_NOTIFY:
740 void GraphDisplayerCanvas::delete_item(NodeIt node_to_delete)
742 delete(nodesmap[node_to_delete]);
743 g.erase(node_to_delete);
746 void GraphDisplayerCanvas::delete_item(EdgeIt edge_to_delete)
748 delete(edgesmap[edge_to_delete]);
749 g.erase(edge_to_delete);
752 void GraphDisplayerCanvas::delete_item(Graph::Edge edge_to_delete)
754 delete(edgesmap[edge_to_delete]);
755 g.erase(edge_to_delete);
758 void GraphDisplayerCanvas::text_reposition(xy<double> new_place)
760 new_place+=(xy<double>(10,10));
761 edgetextmap[active_edge]->property_x().set_value(new_place.x);
762 edgetextmap[active_edge]->property_y().set_value(new_place.y);
765 void GraphDisplayerCanvas::toggle_edge_activity(BrokenEdge* active_bre, bool on)
769 if(active_edge!=INVALID)
771 std::cout << "ERROR!!!! Valid edge found!" << std::endl;
775 for (EdgeIt i(g); i!=INVALID; ++i)
777 if(edgesmap[i]==active_bre)
786 if(active_edge!=INVALID)
792 std::cout << "ERROR!!!! Invalid edge found!" << std::endl;