Several changes. \n If new map is added to mapstorage it emits signal with the name of the new map. This was important, because from now on not only tha mapwin should be updated. \n Furthermore algobox gets a pointer to mapstorage instead of only the mapnames from it. This is important because without it it would be complicated to pass all of the required maps to algobox.
1 #include "graph_displayer_canvas.h"
5 bool GraphDisplayerCanvas::on_expose_event(GdkEventExpose *event)
7 Gnome::Canvas::CanvasAA::on_expose_event(event);
13 void GraphDisplayerCanvas::changeEditorialTool(int newtool)
15 if(actual_tool!=newtool)
18 actual_handler.disconnect();
24 GdkEvent * generated=new GdkEvent();
25 generated->type=GDK_BUTTON_RELEASE;
26 generated->button.button=3;
27 createEdgeEventHandler(generated);
31 //has to do the same thing as in the case of NODE_MAP_EDIT
51 actual_handler=signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::moveEventHandler), false);
55 actual_handler=signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::createNodeEventHandler), false);
59 actual_handler=signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::createEdgeEventHandler), false);
63 actual_handler=signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::eraserEventHandler), false);
68 actual_handler=signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::edgeMapEditEventHandler), false);
72 actual_handler=signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::nodeMapEditEventHandler), false);
81 int GraphDisplayerCanvas::getActualTool()
86 bool GraphDisplayerCanvas::moveEventHandler(GdkEvent* e)
88 static Gnome::Canvas::Text *coord_text = 0;
91 case GDK_BUTTON_PRESS:
92 //we mark the location of the event to be able to calculate parameters of dragging
93 window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
95 active_item=(get_item_at(clicked_x, clicked_y));
97 for (NodeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
99 if(nodesmap[i]==active_item)
104 switch(e->button.button)
114 case GDK_BUTTON_RELEASE:
124 case GDK_MOTION_NOTIFY:
125 //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
126 if(active_node!=INVALID)
128 (mytab.mapstorage).modified = true;
130 //new coordinates will be the old values,
131 //because the item will be moved to the
132 //new coordinate therefore the new movement
133 //has to be calculated from here
137 window_to_world (e->motion.x, e->motion.y, new_x, new_y);
139 double dx=new_x-clicked_x;
140 double dy=new_y-clicked_y;
142 //repositioning node and its text
143 active_item->move(dx, dy);
144 nodetextmap[active_node]->move(dx, dy);
146 // the new coordinates of the centre of the node
147 double coord_x = new_x - (clicked_x - (mytab.mapstorage).coords[active_node].x);
148 double coord_y = new_y - (clicked_y - (mytab.mapstorage).coords[active_node].y);
150 // write back the new coordinates to the coords map
151 (mytab.mapstorage).coords.set(active_node, xy<double>(coord_x, coord_y));
156 // reposition the coordinates text
157 std::ostringstream ostr;
159 (mytab.mapstorage).coords[active_node].x << ", " <<
160 (mytab.mapstorage).coords[active_node].y << ")";
162 (nodesmap[active_node]->property_x2().get_value() -
163 nodesmap[active_node]->property_x1().get_value()) / 2.0;
166 coord_text->property_text().set_value(ostr.str());
167 coord_text->property_x().set_value((mytab.mapstorage).coords[active_node].x +
169 coord_text->property_y().set_value((mytab.mapstorage).coords[active_node].y -
174 coord_text = new Gnome::Canvas::Text(
176 (mytab.mapstorage).coords[active_node].x + radius,
177 (mytab.mapstorage).coords[active_node].y - radius,
179 coord_text->property_fill_color().set_value("black");
180 coord_text->property_anchor().set_value(Gtk::ANCHOR_SOUTH_WEST);
183 //all the edges connected to the moved point has to be redrawn
184 for(OutEdgeIt ei((mytab.mapstorage).graph,active_node);ei!=INVALID;++ei)
186 XY moved_node_1(coord_x - dx, coord_y - dy);
187 XY moved_node_2(coord_x, coord_y);
188 Node target = mytab.mapstorage.graph.target(ei);
189 XY fix_node(mytab.mapstorage.coords[target].x,
190 mytab.mapstorage.coords[target].y);
191 XY old_arrow_pos(mytab.mapstorage.arrow_pos[ei]);
195 arrow_pos = calcArrowPos(moved_node_1, moved_node_2, fix_node, old_arrow_pos, false);
197 arrow_pos = calcArrowPos(moved_node_1, moved_node_2, fix_node, old_arrow_pos, true);
199 mytab.mapstorage.arrow_pos.set(ei, arrow_pos);
200 edgesmap[ei]->draw();
202 //reposition of edgetext
203 XY text_pos=mytab.mapstorage.arrow_pos[ei];
204 text_pos+=(XY(10,10));
205 edgetextmap[ei]->property_x().set_value(text_pos.x);
206 edgetextmap[ei]->property_y().set_value(text_pos.y);
209 for(InEdgeIt ei((mytab.mapstorage).graph,active_node);ei!=INVALID;++ei)
211 XY moved_node_1(coord_x - dx, coord_y - dy);
212 XY moved_node_2(coord_x, coord_y);
213 Node source = mytab.mapstorage.graph.source(ei);
214 XY fix_node(mytab.mapstorage.coords[source].x,
215 mytab.mapstorage.coords[source].y);
216 XY old_arrow_pos(mytab.mapstorage.arrow_pos[ei]);
220 arrow_pos = calcArrowPos(moved_node_1, moved_node_2, fix_node, old_arrow_pos, false);
222 arrow_pos = calcArrowPos(moved_node_1, moved_node_2, fix_node, old_arrow_pos, true);
224 mytab.mapstorage.arrow_pos.set(ei, arrow_pos);
225 edgesmap[ei]->draw();
227 //reposition of edgetext
228 XY text_pos=mytab.mapstorage.arrow_pos[ei];
229 text_pos+=(XY(10,10));
230 edgetextmap[ei]->property_x().set_value(text_pos.x);
231 edgetextmap[ei]->property_y().set_value(text_pos.y);
240 XY GraphDisplayerCanvas::calcArrowPos(XY moved_node_1, XY moved_node_2, XY fix_node, XY old_arrow_pos, bool move)
244 return XY((moved_node_2.x + fix_node.x) / 2.0, (moved_node_2.y + fix_node.y) / 2.0);
248 //////////////////////////////////////////////////////////////////////////////////////////////////////
249 /////////// keeps shape-with scalar multiplication - version 2.
250 //////////////////////////////////////////////////////////////////////////////////////////////////////
252 //old vector from one to the other node - a
253 xy<double> a_v(moved_node_1.x-fix_node.x,moved_node_1.y-fix_node.y);
254 //new vector from one to the other node - b
255 xy<double> b_v(moved_node_2.x-fix_node.x,moved_node_2.y-fix_node.y);
257 double absa=sqrt(a_v.normSquare());
258 double absb=sqrt(b_v.normSquare());
260 if ((absa == 0.0) || (absb == 0.0))
262 return old_arrow_pos;
266 //old vector from one node to the breakpoint - c
267 xy<double> c_v(old_arrow_pos.x-fix_node.x,old_arrow_pos.y-fix_node.y);
269 //unit vector with the same direction to a_v
270 xy<double> a_v_u(a_v.x/absa,a_v.y/absa);
272 //normal vector of unit vector with the same direction to a_v
273 xy<double> a_v_u_n(((-1)*a_v_u.y),a_v_u.x);
275 //unit vector with the same direction to b_v
276 xy<double> b_v_u(b_v.x/absb,b_v.y/absb);
278 //normal vector of unit vector with the same direction to b_v
279 xy<double> b_v_u_n(((-1)*b_v_u.y),b_v_u.x);
281 //vector c in a_v_u and a_v_u_n co-ordinate system
282 xy<double> c_a(c_v*a_v_u,c_v*a_v_u_n);
284 //new vector from one node to the breakpoint - d - we have to calculate this one
285 xy<double> d_v=absb/absa*(c_a.x*b_v_u+c_a.y*b_v_u_n);
287 return XY(d_v.x+fix_node.x,d_v.y+fix_node.y);
292 bool GraphDisplayerCanvas::createNodeEventHandler(GdkEvent* e)
297 case GDK_MOTION_NOTIFY:
299 GdkEvent * generated=new GdkEvent();
300 generated->motion.x=e->motion.x;
301 generated->motion.y=e->motion.y;
302 generated->type=GDK_MOTION_NOTIFY;
303 moveEventHandler(generated);
307 case GDK_BUTTON_RELEASE:
308 (mytab.mapstorage).modified = true;
312 active_node=(mytab.mapstorage).graph.addNode();
314 //initiating values corresponding to new node in maps
316 window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
318 // update coordinates
319 (mytab.mapstorage).coords.set(active_node, xy<double>(clicked_x, clicked_y));
321 // update all other maps
322 for (std::map<std::string, Graph::NodeMap<double>*>::const_iterator it =
323 (mytab.mapstorage).nodemap_storage.begin(); it !=
324 (mytab.mapstorage).nodemap_storage.end(); ++it)
326 if ((it->first != "coordinates_x") &&
327 (it->first != "coordinates_y"))
329 (*(it->second))[active_node] =
330 (mytab.mapstorage).nodemap_default[it->first];
333 // increment the id map's default value
334 (mytab.mapstorage).nodemap_default["id"] += 1.0;
336 nodesmap[active_node]=new Gnome::Canvas::Ellipse(displayed_graph,
337 clicked_x-20, clicked_y-20, clicked_x+20, clicked_y+20);
338 active_item=(Gnome::Canvas::Item *)(nodesmap[active_node]);
339 *(nodesmap[active_node]) <<
340 Gnome::Canvas::Properties::fill_color("blue");
341 *(nodesmap[active_node]) <<
342 Gnome::Canvas::Properties::outline_color("black");
343 active_item->raise_to_top();
345 (nodesmap[active_node])->show();
347 nodetextmap[active_node]=new Gnome::Canvas::Text(displayed_graph,
348 clicked_x+node_property_defaults[N_RADIUS]+5,
349 clicked_y+node_property_defaults[N_RADIUS]+5, "");
350 nodetextmap[active_node]->property_fill_color().set_value("darkblue");
351 nodetextmap[active_node]->raise_to_top();
353 // mapwin.updateNode(active_node);
354 propertyUpdate(active_node);
367 bool GraphDisplayerCanvas::createEdgeEventHandler(GdkEvent* e)
371 case GDK_BUTTON_PRESS:
372 //in edge creation right button has special meaning
373 if(e->button.button!=3)
375 //there is not yet selected node
376 if(active_node==INVALID)
378 //we mark the location of the event to be able to calculate parameters of dragging
380 window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
382 active_item=(get_item_at(clicked_x, clicked_y));
384 for (NodeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
386 if(nodesmap[i]==active_item)
391 //the clicked item is really a node
392 if(active_node!=INVALID)
394 *(nodesmap[active_node]) << Gnome::Canvas::Properties::fill_color("red");
397 //clicked item was not a node. It could be e.g. edge.
403 //we only have to do sg. if the mouse button
404 // is pressed already once AND the click was
405 // on a node that was found in the set of
406 //nodes, and now we only search for the second
410 window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
411 target_item=(get_item_at(clicked_x, clicked_y));
412 Node target_node=INVALID;
413 for (NodeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
415 if(nodesmap[i]==target_item)
420 //the clicked item is a node, the edge can be drawn
421 if(target_node!=INVALID)
423 if(target_node!=active_node)
425 (mytab.mapstorage).modified = true;
427 *(nodesmap[target_node]) <<
428 Gnome::Canvas::Properties::fill_color("red");
431 active_edge=(mytab.mapstorage).graph.addEdge(active_node,
435 for (std::map<std::string,
436 Graph::EdgeMap<double>*>::const_iterator it =
437 (mytab.mapstorage).edgemap_storage.begin(); it !=
438 (mytab.mapstorage).edgemap_storage.end(); ++it)
440 (*(it->second))[active_edge] =
441 (mytab.mapstorage).edgemap_default[it->first];
443 // increment the id map's default value
444 (mytab.mapstorage).edgemap_default["id"] += 1.0;
446 //calculating coordinates of new edge
447 Gnome::Canvas::Points coos;
448 double x1, x2, y1, y2;
450 active_item->get_bounds(x1, y1, x2, y2);
451 coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
453 target_item->get_bounds(x1, y1, x2, y2);
454 coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
457 edgesmap[active_edge]=new BrokenEdge(displayed_graph, active_edge,
459 *(edgesmap[active_edge]) <<
460 Gnome::Canvas::Properties::fill_color("green");
461 edgesmap[active_edge]->property_width_pixels().set_value(10);
463 edgesmap[active_edge]->lower_to_bottom();
465 //initializing edge-text as well, to empty string
466 XY text_pos=mytab.mapstorage.arrow_pos[active_edge];
467 text_pos+=(XY(10,10));
469 edgetextmap[active_edge]=new Gnome::Canvas::Text(displayed_graph,
470 text_pos.x, text_pos.y, "");
471 edgetextmap[active_edge]->property_fill_color().set_value(
473 edgetextmap[active_edge]->raise_to_top();
475 //updating its properties
476 // mapwin.updateEdge(active_edge);
477 propertyUpdate(active_edge);
482 std::cerr << "Loop edge is not yet implemented!" << std::endl;
485 //clicked item was not a node. it could be an e.g. edge. we do not
486 //deal with it furthermore.
494 case GDK_BUTTON_RELEASE:
496 //we clear settings in two cases
497 //1: the edge is ready (target_item has valid value)
498 //2: the edge creation is cancelled with right button
499 if((target_item)||(e->button.button==3))
503 *active_item << Gnome::Canvas::Properties::fill_color("blue");
508 *target_item << Gnome::Canvas::Properties::fill_color("blue");
521 bool GraphDisplayerCanvas::eraserEventHandler(GdkEvent* e)
525 case GDK_BUTTON_PRESS:
526 //finding the clicked items
527 window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
528 active_item=(get_item_at(clicked_x, clicked_y));
532 for (NodeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
534 if(nodesmap[i]==active_item)
540 if(active_node==INVALID)
542 for (EdgeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
544 if(edgesmap[i]==active_item)
551 //recolor activated item
554 *active_item << Gnome::Canvas::Properties::fill_color("red");
558 case GDK_BUTTON_RELEASE:
559 window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
562 //the cursor was not moved since pressing it
563 if( active_item == ( get_item_at (clicked_x, clicked_y) ) )
566 if(active_node!=INVALID)
568 (mytab.mapstorage).modified = true;
570 std::set<Graph::Edge> edges_to_delete;
572 for(OutEdgeIt e((mytab.mapstorage).graph,active_node);e!=INVALID;++e)
574 edges_to_delete.insert(e);
577 for(InEdgeIt e((mytab.mapstorage).graph,active_node);e!=INVALID;++e)
579 edges_to_delete.insert(e);
582 //deleting collected edges
583 for(std::set<Graph::Edge>::iterator
584 edge_set_it=edges_to_delete.begin();
585 edge_set_it!=edges_to_delete.end();
588 deleteItem(*edge_set_it);
590 deleteItem(active_node);
592 //a simple edge was chosen
595 deleteItem(active_edge);
598 //pointer was moved, deletion is cancelled
601 if(active_node!=INVALID)
603 *active_item << Gnome::Canvas::Properties::fill_color("blue");
607 *active_item << Gnome::Canvas::Properties::fill_color("green");
617 case GDK_MOTION_NOTIFY:
626 bool GraphDisplayerCanvas::edgeMapEditEventHandler(GdkEvent* e)
628 if(actual_tool==EDGE_MAP_EDIT)
632 case GDK_BUTTON_PRESS:
634 //for determine, whether it was an edge
635 Edge clicked_edge=INVALID;
637 window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
638 active_item=(get_item_at(clicked_x, clicked_y));
640 //find the activated item between texts
641 for (EdgeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
643 //at the same time only one can be active
644 if(edgetextmap[i]==active_item)
650 //if it was not between texts, search for it between edges
651 if(clicked_edge==INVALID)
653 for (EdgeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
655 //at the same time only one can be active
656 if((edgesmap[i]==active_item)||(edgetextmap[i]==active_item))
663 //if it was really an edge...
664 if(clicked_edge!=INVALID)
666 // the id map is not editable
667 if (edgemap_to_edit == "id") return 0;
669 //and there is activated map
670 if(edgetextmap[clicked_edge]->property_text().get_value()!="")
672 //activate the general variable for it
673 active_edge=clicked_edge;
676 Gtk::Dialog dialog("Edit value", true);
677 dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
678 dialog.add_button(Gtk::Stock::OK, Gtk::RESPONSE_ACCEPT);
679 Gtk::VBox* vbox = dialog.get_vbox();
680 Gtk::SpinButton spin(0.0, 4);
681 spin.set_increments(1.0, 10.0);
682 spin.set_range(-1000000.0, 1000000.0);
683 spin.set_numeric(true);
686 switch (dialog.run())
688 case Gtk::RESPONSE_NONE:
689 case Gtk::RESPONSE_CANCEL:
691 case Gtk::RESPONSE_ACCEPT:
692 double new_value = spin.get_value();
693 (*(mytab.mapstorage).edgemap_storage[edgemap_to_edit])[active_edge] =
695 std::ostringstream ostr;
697 edgetextmap[active_edge]->property_text().set_value(
699 //mapwin.updateEdge(active_edge);
700 // mapwin.updateEdge(Edge(INVALID));
701 propertyUpdate(Edge(INVALID));
714 bool GraphDisplayerCanvas::nodeMapEditEventHandler(GdkEvent* e)
716 if(actual_tool==NODE_MAP_EDIT)
720 case GDK_BUTTON_PRESS:
722 //for determine, whether it was a node
723 Node clicked_node=INVALID;
725 window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
726 active_item=(get_item_at(clicked_x, clicked_y));
728 //find the activated item between texts
729 for (NodeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
731 //at the same time only one can be active
732 if(nodetextmap[i]==active_item)
738 //if there was not, search for it between nodes
739 if(clicked_node==INVALID)
741 for (NodeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
743 //at the same time only one can be active
744 if(nodesmap[i]==active_item)
751 //if it was really a node...
752 if(clicked_node!=INVALID)
754 // the id map is not editable
755 if (nodemap_to_edit == "id") return 0;
757 //and there is activated map
758 if(nodetextmap[clicked_node]->property_text().get_value()!="")
760 //activate the general variable for it
761 active_node=clicked_node;
764 Gtk::Dialog dialog("Edit value", true);
765 dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
766 dialog.add_button(Gtk::Stock::OK, Gtk::RESPONSE_ACCEPT);
767 Gtk::VBox* vbox = dialog.get_vbox();
768 Gtk::SpinButton spin(0.0, 4);
769 spin.set_increments(1.0, 10.0);
770 spin.set_range(-1000000.0, 1000000.0);
771 spin.set_numeric(true);
774 switch (dialog.run())
776 case Gtk::RESPONSE_NONE:
777 case Gtk::RESPONSE_CANCEL:
779 case Gtk::RESPONSE_ACCEPT:
780 double new_value = spin.get_value();
781 (*(mytab.mapstorage).nodemap_storage[nodemap_to_edit])[active_node] =
783 std::ostringstream ostr;
785 nodetextmap[active_node]->property_text().set_value(
787 //mapwin.updateNode(active_node);
788 // mapwin.updateNode(Node(INVALID));
789 propertyUpdate(Node(INVALID));
802 void GraphDisplayerCanvas::deleteItem(Node node_to_delete)
804 delete(nodetextmap[node_to_delete]);
805 delete(nodesmap[node_to_delete]);
806 (mytab.mapstorage).graph.erase(node_to_delete);
809 void GraphDisplayerCanvas::deleteItem(Edge edge_to_delete)
811 delete(edgetextmap[edge_to_delete]);
812 delete(edgesmap[edge_to_delete]);
813 (mytab.mapstorage).graph.erase(edge_to_delete);
816 void GraphDisplayerCanvas::textReposition(xy<double> new_place)
818 new_place+=(xy<double>(10,10));
819 edgetextmap[forming_edge]->property_x().set_value(new_place.x);
820 edgetextmap[forming_edge]->property_y().set_value(new_place.y);
823 void GraphDisplayerCanvas::toggleEdgeActivity(BrokenEdge* active_bre, bool on)
827 if(forming_edge!=INVALID)
829 std::cerr << "ERROR!!!! Valid edge found!" << std::endl;
833 for (EdgeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
835 if(edgesmap[i]==active_bre)
844 if(forming_edge!=INVALID)
846 forming_edge=INVALID;
850 std::cerr << "ERROR!!!! Invalid edge found!" << std::endl;
856 int GraphDisplayerCanvas::addNewEdgeMap(double default_value, std::string mapname)
859 Graph::EdgeMap<double> * emptr=new Graph::EdgeMap<double> ((mytab.mapstorage).graph, default_value);
861 //if addition was not successful addEdgeMap returns one.
862 //cause can be that there is already a map named like the new one
863 if((mytab.mapstorage).addEdgeMap(mapname,emptr, default_value))
869 //add it to the list of the displayable maps
870 mytab.registerNewEdgeMap(mapname);
873 changeEdgeText(mapname);
878 int GraphDisplayerCanvas::addNewNodeMap(double default_value, std::string mapname)
881 Graph::NodeMap<double> * emptr=new Graph::NodeMap<double> ((mytab.mapstorage).graph,default_value);
883 //if addition was not successful addNodeMap returns one.
884 //cause can be that there is already a map named like the new one
885 if((mytab.mapstorage).addNodeMap(mapname,emptr, default_value))
890 //add it to the list of the displayable maps
891 mytab.registerNewNodeMap(mapname);
894 changeNodeText(mapname);