Correcting the structure of the graph's and adaptor's map.
The template assign operators and map iterators can be used for adaptors also.
Some bugfix in the adaptors
New class SwapBpUGraphAdaptor which swaps the two nodeset of the graph.
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));
456 // set the coordinates of the arrow on the new edge
457 MapStorage& ms = mytab.mapstorage;
458 ms.arrow_pos.set(active_edge,
459 (ms.coords[ms.graph.source(active_edge)] +
460 ms.coords[ms.graph.target(active_edge)])/ 2.0);
463 edgesmap[active_edge]=new BrokenEdge(displayed_graph, active_edge,
465 *(edgesmap[active_edge]) <<
466 Gnome::Canvas::Properties::fill_color("green");
467 edgesmap[active_edge]->property_width_pixels().set_value(10);
469 edgesmap[active_edge]->lower_to_bottom();
471 //initializing edge-text as well, to empty string
472 XY text_pos=mytab.mapstorage.arrow_pos[active_edge];
473 text_pos+=(XY(10,10));
475 edgetextmap[active_edge]=new Gnome::Canvas::Text(displayed_graph,
476 text_pos.x, text_pos.y, "");
477 edgetextmap[active_edge]->property_fill_color().set_value(
479 edgetextmap[active_edge]->raise_to_top();
481 //updating its properties
482 // mapwin.updateEdge(active_edge);
483 propertyUpdate(active_edge);
488 std::cerr << "Loop edge is not yet implemented!" << std::endl;
491 //clicked item was not a node. it could be an e.g. edge. we do not
492 //deal with it furthermore.
500 case GDK_BUTTON_RELEASE:
502 //we clear settings in two cases
503 //1: the edge is ready (target_item has valid value)
504 //2: the edge creation is cancelled with right button
505 if((target_item)||(e->button.button==3))
509 *active_item << Gnome::Canvas::Properties::fill_color("blue");
514 *target_item << Gnome::Canvas::Properties::fill_color("blue");
527 bool GraphDisplayerCanvas::eraserEventHandler(GdkEvent* e)
531 case GDK_BUTTON_PRESS:
532 //finding the clicked items
533 window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
534 active_item=(get_item_at(clicked_x, clicked_y));
538 for (NodeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
540 if(nodesmap[i]==active_item)
546 if(active_node==INVALID)
548 for (EdgeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
550 if(edgesmap[i]==active_item)
557 // return if the clicked object is neither an edge nor a node
558 if (active_edge == INVALID) return false;
560 //recolor activated item
563 *active_item << Gnome::Canvas::Properties::fill_color("red");
567 case GDK_BUTTON_RELEASE:
568 window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
571 //the cursor was not moved since pressing it
572 if( active_item == ( get_item_at (clicked_x, clicked_y) ) )
575 if(active_node!=INVALID)
577 (mytab.mapstorage).modified = true;
579 std::set<Graph::Edge> edges_to_delete;
581 for(OutEdgeIt e((mytab.mapstorage).graph,active_node);e!=INVALID;++e)
583 edges_to_delete.insert(e);
586 for(InEdgeIt e((mytab.mapstorage).graph,active_node);e!=INVALID;++e)
588 edges_to_delete.insert(e);
591 //deleting collected edges
592 for(std::set<Graph::Edge>::iterator
593 edge_set_it=edges_to_delete.begin();
594 edge_set_it!=edges_to_delete.end();
597 deleteItem(*edge_set_it);
599 deleteItem(active_node);
601 //a simple edge was chosen
602 else if (active_edge != INVALID)
604 deleteItem(active_edge);
607 //pointer was moved, deletion is cancelled
610 if(active_node!=INVALID)
612 *active_item << Gnome::Canvas::Properties::fill_color("blue");
614 else if (active_edge != INVALID)
616 *active_item << Gnome::Canvas::Properties::fill_color("green");
626 case GDK_MOTION_NOTIFY:
635 bool GraphDisplayerCanvas::edgeMapEditEventHandler(GdkEvent* e)
637 if(actual_tool==EDGE_MAP_EDIT)
641 case GDK_BUTTON_PRESS:
643 //for determine, whether it was an edge
644 Edge clicked_edge=INVALID;
646 window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
647 active_item=(get_item_at(clicked_x, clicked_y));
649 //find the activated item between texts
650 for (EdgeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
652 //at the same time only one can be active
653 if(edgetextmap[i]==active_item)
659 //if it was not between texts, search for it between edges
660 if(clicked_edge==INVALID)
662 for (EdgeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
664 //at the same time only one can be active
665 if((edgesmap[i]==active_item)||(edgetextmap[i]==active_item))
672 //if it was really an edge...
673 if(clicked_edge!=INVALID)
675 // the id map is not editable
676 if (edgemap_to_edit == "id") return 0;
678 //and there is activated map
679 if(edgetextmap[clicked_edge]->property_text().get_value()!="")
681 //activate the general variable for it
682 active_edge=clicked_edge;
685 Gtk::Dialog dialog("Edit value", true);
686 dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
687 dialog.add_button(Gtk::Stock::OK, Gtk::RESPONSE_ACCEPT);
688 Gtk::VBox* vbox = dialog.get_vbox();
689 Gtk::SpinButton spin(0.0, 4);
690 spin.set_increments(1.0, 10.0);
691 spin.set_range(-1000000.0, 1000000.0);
692 spin.set_numeric(true);
695 switch (dialog.run())
697 case Gtk::RESPONSE_NONE:
698 case Gtk::RESPONSE_CANCEL:
700 case Gtk::RESPONSE_ACCEPT:
701 double new_value = spin.get_value();
702 (*(mytab.mapstorage).edgemap_storage[edgemap_to_edit])[active_edge] =
704 std::ostringstream ostr;
706 edgetextmap[active_edge]->property_text().set_value(
708 //mapwin.updateEdge(active_edge);
709 // mapwin.updateEdge(Edge(INVALID));
710 propertyUpdate(Edge(INVALID));
723 bool GraphDisplayerCanvas::nodeMapEditEventHandler(GdkEvent* e)
725 if(actual_tool==NODE_MAP_EDIT)
729 case GDK_BUTTON_PRESS:
731 //for determine, whether it was a node
732 Node clicked_node=INVALID;
734 window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
735 active_item=(get_item_at(clicked_x, clicked_y));
737 //find the activated item between texts
738 for (NodeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
740 //at the same time only one can be active
741 if(nodetextmap[i]==active_item)
747 //if there was not, search for it between nodes
748 if(clicked_node==INVALID)
750 for (NodeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
752 //at the same time only one can be active
753 if(nodesmap[i]==active_item)
760 //if it was really a node...
761 if(clicked_node!=INVALID)
763 // the id map is not editable
764 if (nodemap_to_edit == "id") return 0;
766 //and there is activated map
767 if(nodetextmap[clicked_node]->property_text().get_value()!="")
769 //activate the general variable for it
770 active_node=clicked_node;
773 Gtk::Dialog dialog("Edit value", true);
774 dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
775 dialog.add_button(Gtk::Stock::OK, Gtk::RESPONSE_ACCEPT);
776 Gtk::VBox* vbox = dialog.get_vbox();
777 Gtk::SpinButton spin(0.0, 4);
778 spin.set_increments(1.0, 10.0);
779 spin.set_range(-1000000.0, 1000000.0);
780 spin.set_numeric(true);
783 switch (dialog.run())
785 case Gtk::RESPONSE_NONE:
786 case Gtk::RESPONSE_CANCEL:
788 case Gtk::RESPONSE_ACCEPT:
789 double new_value = spin.get_value();
790 (*(mytab.mapstorage).nodemap_storage[nodemap_to_edit])[active_node] =
792 std::ostringstream ostr;
794 nodetextmap[active_node]->property_text().set_value(
796 //mapwin.updateNode(active_node);
797 // mapwin.updateNode(Node(INVALID));
798 propertyUpdate(Node(INVALID));
811 void GraphDisplayerCanvas::deleteItem(Node node_to_delete)
813 delete(nodetextmap[node_to_delete]);
814 delete(nodesmap[node_to_delete]);
815 (mytab.mapstorage).graph.erase(node_to_delete);
818 void GraphDisplayerCanvas::deleteItem(Edge edge_to_delete)
820 delete(edgetextmap[edge_to_delete]);
821 delete(edgesmap[edge_to_delete]);
822 (mytab.mapstorage).graph.erase(edge_to_delete);
825 void GraphDisplayerCanvas::textReposition(xy<double> new_place)
827 new_place+=(xy<double>(10,10));
828 edgetextmap[forming_edge]->property_x().set_value(new_place.x);
829 edgetextmap[forming_edge]->property_y().set_value(new_place.y);
832 void GraphDisplayerCanvas::toggleEdgeActivity(BrokenEdge* active_bre, bool on)
836 if(forming_edge!=INVALID)
838 std::cerr << "ERROR!!!! Valid edge found!" << std::endl;
842 for (EdgeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
844 if(edgesmap[i]==active_bre)
853 if(forming_edge!=INVALID)
855 forming_edge=INVALID;
859 std::cerr << "ERROR!!!! Invalid edge found!" << std::endl;