Use libintl.h instead of locale.h.
3 * This file is a part of LEMON, a generic C++ optimization library
5 * Copyright (C) 2003-2006
6 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7 * (Egervary Research Group on Combinatorial Optimization, EGRES).
9 * Permission to use, modify and distribute this software is granted
10 * provided that this copyright notice appears in all copies. For
11 * precise terms see the accompanying LICENSE file.
13 * This software is provided "AS IS" with no warranty of any kind,
14 * express or implied, and with no claim as to its suitability for any
19 #include <graph_displayer_canvas.h>
20 #include <mapstorage.h>
25 bool DigraphDisplayerCanvas::on_expose_event(GdkEventExpose *event)
27 Gnome::Canvas::CanvasAA::on_expose_event(event);
33 void DigraphDisplayerCanvas::changeEditorialTool(int newtool)
35 if(actual_tool!=newtool)
38 actual_handler.disconnect();
44 GdkEvent * generated=new GdkEvent();
45 generated->type=GDK_BUTTON_RELEASE;
46 generated->button.button=3;
47 createArcEventHandler(generated);
69 actual_handler=signal_event().connect(sigc::mem_fun(*this, &DigraphDisplayerCanvas::moveEventHandler), false);
73 actual_handler=signal_event().connect(sigc::mem_fun(*this, &DigraphDisplayerCanvas::createNodeEventHandler), false);
77 actual_handler=signal_event().connect(sigc::mem_fun(*this, &DigraphDisplayerCanvas::createArcEventHandler), false);
81 actual_handler=signal_event().connect(sigc::mem_fun(*this, &DigraphDisplayerCanvas::eraserEventHandler), false);
86 actual_handler=signal_event().connect(sigc::mem_fun(*this, &DigraphDisplayerCanvas::mapEditEventHandler), false);
95 int DigraphDisplayerCanvas::getActualTool()
100 bool DigraphDisplayerCanvas::scrollEventHandler(GdkEvent* e)
103 if(e->type==GDK_SCROLL)
106 //pointer shows this win point before zoom
107 XY win_coord(((GdkEventScroll*)e)->x, ((GdkEventScroll*)e)->y);
109 //the original scroll settings
110 int scroll_offset_x, scroll_offset_y;
111 get_scroll_offsets(scroll_offset_x, scroll_offset_y);
113 //pointer shows this canvas point before zoom
115 window_to_world(win_coord.x, win_coord.y, canvas_coord.x, canvas_coord.y);
117 if(((GdkEventScroll*)e)->direction) //IN
126 //pointer shows this window point after zoom
128 world_to_window(canvas_coord.x, canvas_coord.y, post_win_coord.x, post_win_coord.y);
130 //we have to add the difference between new and old window point to original scroll offset
131 scroll_to(scroll_offset_x+(int)(post_win_coord.x-win_coord.x),scroll_offset_y+(int)(post_win_coord.y-win_coord.y));
133 //no other eventhandler is needed
139 bool DigraphDisplayerCanvas::moveEventHandler(GdkEvent* e)
141 MapStorage& ms = *mytab.mapstorage;
143 static Gnome::Canvas::Text *coord_text = 0;
146 case GDK_BUTTON_PRESS:
147 //we mark the location of the event to be able to calculate parameters of dragging
148 window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
150 active_item=(get_item_at(clicked_x, clicked_y));
152 for (NodeIt i(ms.digraph); i!=INVALID; ++i)
154 if(nodesmap[i]==active_item)
159 isbutton=e->button.button;
161 case GDK_BUTTON_RELEASE:
171 case GDK_MOTION_NOTIFY:
172 //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
173 if(active_node!=INVALID)
177 //new coordinates will be the old values,
178 //because the item will be moved to the
179 //new coordinate therefore the new movement
180 //has to be calculated from here
184 window_to_world (e->motion.x, e->motion.y, new_x, new_y);
186 double dx=new_x-clicked_x;
187 double dy=new_y-clicked_y;
194 // reposition the coordinates text
195 std::ostringstream ostr;
197 ms.getNodeCoords(active_node).x << ", " <<
198 ms.getNodeCoords(active_node).y << ")";
200 (nodesmap[active_node]->property_x2().get_value() -
201 nodesmap[active_node]->property_x1().get_value()) / 2.0;
204 coord_text->property_text().set_value(ostr.str());
205 coord_text->property_x().set_value(
206 ms.getNodeCoords(active_node).x + radius);
207 coord_text->property_y().set_value(
208 ms.getNodeCoords(active_node).y - radius);
212 coord_text = new Gnome::Canvas::Text(
214 ms.getNodeCoords(active_node).x + radius,
215 ms.getNodeCoords(active_node).y - radius,
217 coord_text->property_fill_color().set_value("black");
218 coord_text->property_anchor().set_value(Gtk::ANCHOR_SOUTH_WEST);
229 XY DigraphDisplayerCanvas::calcArrowPos(XY moved_node_1, XY moved_node_2, XY fix_node, XY old_arrow_pos, int move_code)
234 return XY((moved_node_2.x + fix_node.x) / 2.0, (moved_node_2.y + fix_node.y) / 2.0);
237 return old_arrow_pos;
241 //////////////////////////////////////////////////////////////////////////////////////////////////////
242 /////////// keeps shape-with scalar multiplication - version 2.
243 //////////////////////////////////////////////////////////////////////////////////////////////////////
245 //old vector from one to the other node - a
246 XY a_v(moved_node_1.x-fix_node.x,moved_node_1.y-fix_node.y);
247 //new vector from one to the other node - b
248 XY b_v(moved_node_2.x-fix_node.x,moved_node_2.y-fix_node.y);
250 double absa=sqrt(a_v.normSquare());
251 double absb=sqrt(b_v.normSquare());
253 if ((absa == 0.0) || (absb == 0.0))
255 return old_arrow_pos;
259 //old vector from one node to the breakpoint - c
260 XY c_v(old_arrow_pos.x-fix_node.x,old_arrow_pos.y-fix_node.y);
262 //unit vector with the same direction to a_v
263 XY a_v_u(a_v.x/absa,a_v.y/absa);
265 //normal vector of unit vector with the same direction to a_v
266 XY a_v_u_n(((-1)*a_v_u.y),a_v_u.x);
268 //unit vector with the same direction to b_v
269 XY b_v_u(b_v.x/absb,b_v.y/absb);
271 //normal vector of unit vector with the same direction to b_v
272 XY b_v_u_n(((-1)*b_v_u.y),b_v_u.x);
274 //vector c in a_v_u and a_v_u_n co-ordinate system
275 XY c_a(c_v*a_v_u,c_v*a_v_u_n);
277 //new vector from one node to the breakpoint - d - we have to calculate this one
278 XY d_v=absb/absa*(c_a.x*b_v_u+c_a.y*b_v_u_n);
280 return XY(d_v.x+fix_node.x,d_v.y+fix_node.y);
290 bool DigraphDisplayerCanvas::createNodeEventHandler(GdkEvent* e)
292 MapStorage& ms = *mytab.mapstorage;
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:
314 window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
316 active_node = ms.addNode(XY(clicked_x, clicked_y));
318 nodesmap[active_node]=new Gnome::Canvas::Ellipse(displayed_graph,
319 clicked_x-20, clicked_y-20, clicked_x+20, clicked_y+20);
320 active_item=(Gnome::Canvas::Item *)(nodesmap[active_node]);
321 *(nodesmap[active_node]) <<
322 Gnome::Canvas::Properties::fill_color("blue");
323 *(nodesmap[active_node]) <<
324 Gnome::Canvas::Properties::outline_color("black");
325 active_item->raise_to_top();
327 (nodesmap[active_node])->show();
329 nodetextmap[active_node]=new Gnome::Canvas::Text(displayed_graph,
330 clicked_x+node_property_defaults[N_RADIUS]+5,
331 clicked_y+node_property_defaults[N_RADIUS]+5, "");
332 nodetextmap[active_node]->property_fill_color().set_value("darkblue");
333 nodetextmap[active_node]->raise_to_top();
335 // mapwin.updateNode(active_node);
336 propertyUpdate(active_node);
349 bool DigraphDisplayerCanvas::createArcEventHandler(GdkEvent* e)
351 MapStorage& ms = *mytab.mapstorage;
355 case GDK_BUTTON_PRESS:
356 //in arc creation right button has special meaning
357 if(e->button.button!=3)
359 //there is not yet selected node
360 if(active_node==INVALID)
362 //we mark the location of the event to be able to calculate parameters of dragging
364 window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
366 active_item=(get_item_at(clicked_x, clicked_y));
368 for (NodeIt i(ms.digraph); i!=INVALID; ++i)
370 if(nodesmap[i]==active_item)
375 //the clicked item is really a node
376 if(active_node!=INVALID)
378 *(nodesmap[active_node]) << Gnome::Canvas::Properties::fill_color("red");
381 //clicked item was not a node. It could be e.g. arc.
387 //we only have to do sg. if the mouse button
388 // is pressed already once AND the click was
389 // on a node that was found in the set of
390 //nodes, and now we only search for the second
394 window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
395 target_item=(get_item_at(clicked_x, clicked_y));
396 Node target_node=INVALID;
397 for (NodeIt i(ms.digraph); i!=INVALID; ++i)
399 if(nodesmap[i]==target_item)
404 //the clicked item is a node, the arc can be drawn
405 if(target_node!=INVALID)
409 *(nodesmap[target_node]) <<
410 Gnome::Canvas::Properties::fill_color("red");
412 active_arc = ms.addArc(active_node, target_node);
414 if(target_node!=active_node)
416 arcsmap[active_arc]=new BrokenArc(displayed_graph, active_arc, *this);
420 arcsmap[active_arc]=new LoopArc(displayed_graph, active_arc, *this);
423 //initializing arc-text as well, to empty string
424 XY text_pos=ms.getArrowCoords(active_arc);
425 text_pos+=(XY(10,10));
427 arctextmap[active_arc]=new Gnome::Canvas::Text(displayed_graph,
428 text_pos.x, text_pos.y, "");
429 arctextmap[active_arc]->property_fill_color().set_value(
431 arctextmap[active_arc]->raise_to_top();
433 propertyUpdate(active_arc);
435 //clicked item was not a node. it could be an e.g. arc. we do not
436 //deal with it furthermore.
444 case GDK_BUTTON_RELEASE:
446 //we clear settings in two cases
447 //1: the arc is ready (target_item has valid value)
448 //2: the arc creation is cancelled with right button
449 if((target_item)||(e->button.button==3))
453 propertyUpdate(active_node,N_COLOR);
458 propertyUpdate(ms.digraph.target(active_arc),N_COLOR);
471 bool DigraphDisplayerCanvas::eraserEventHandler(GdkEvent* e)
473 MapStorage& ms = *mytab.mapstorage;
477 case GDK_BUTTON_PRESS:
478 //finding the clicked items
479 window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
480 active_item=(get_item_at(clicked_x, clicked_y));
484 for (NodeIt i(ms.digraph); i!=INVALID; ++i)
486 if(nodesmap[i]==active_item)
492 if(active_node==INVALID)
494 for (ArcIt i(ms.digraph); i!=INVALID; ++i)
496 if(arcsmap[i]->getLine()==active_item)
503 // return if the clicked object is neither an arc nor a node
504 if (active_arc == INVALID) return false;
506 //recolor activated item
509 *active_item << Gnome::Canvas::Properties::fill_color("red");
513 case GDK_BUTTON_RELEASE:
514 window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
517 //the cursor was not moved since pressing it
518 if( active_item == ( get_item_at (clicked_x, clicked_y) ) )
521 if(active_node!=INVALID)
525 std::set<Digraph::Arc> arcs_to_delete;
527 for(OutArcIt e(ms.digraph,active_node);e!=INVALID;++e)
529 arcs_to_delete.insert(e);
532 for(InArcIt e(ms.digraph,active_node);e!=INVALID;++e)
534 arcs_to_delete.insert(e);
537 //deleting collected arcs
538 for(std::set<Digraph::Arc>::iterator
539 arc_set_it=arcs_to_delete.begin();
540 arc_set_it!=arcs_to_delete.end();
543 deleteItem(*arc_set_it);
545 deleteItem(active_node);
547 //a simple arc was chosen
548 else if (active_arc != INVALID)
550 deleteItem(active_arc);
553 //pointer was moved, deletion is cancelled
556 if(active_node!=INVALID)
558 *active_item << Gnome::Canvas::Properties::fill_color("blue");
560 else if (active_arc != INVALID)
562 *active_item << Gnome::Canvas::Properties::fill_color("green");
572 case GDK_MOTION_NOTIFY:
581 bool DigraphDisplayerCanvas::mapEditEventHandler(GdkEvent* e)
583 MapStorage& ms = *mytab.mapstorage;
585 if(actual_tool==MAP_EDIT)
589 case GDK_BUTTON_PRESS:
591 //for determine, whether it was an arc
592 Arc clicked_arc=INVALID;
593 //for determine, whether it was a node
594 Node clicked_node=INVALID;
596 window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
597 active_item=(get_item_at(clicked_x, clicked_y));
599 //find the activated item between text of nodes
600 for (NodeIt i(ms.digraph); i!=INVALID; ++i)
602 //at the same time only one can be active
603 if(nodetextmap[i]==active_item)
609 //if there was not, search for it between nodes
610 if(clicked_node==INVALID)
612 for (NodeIt i(ms.digraph); i!=INVALID; ++i)
614 //at the same time only one can be active
615 if(nodesmap[i]==active_item)
622 if(clicked_node==INVALID)
624 //find the activated item between texts
625 for (ArcIt i(ms.digraph); i!=INVALID; ++i)
627 //at the same time only one can be active
628 if(arctextmap[i]==active_item)
634 //if it was not between texts, search for it between arcs
635 if(clicked_arc==INVALID)
637 for (ArcIt i(ms.digraph); i!=INVALID; ++i)
639 //at the same time only one can be active
640 if((arcsmap[i]->getLine())==active_item)
648 //if it was really a node...
649 if(clicked_node!=INVALID)
651 // the id map is not editable
652 if (nodemap_to_edit == "label") return 0;
654 //and there is activated map
655 if(nodetextmap[clicked_node]->property_text().get_value()!="")
657 //activate the general variable for it
658 active_node=clicked_node;
661 Gtk::Dialog dialog("Edit value", true);
662 dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
663 dialog.add_button(Gtk::Stock::OK, Gtk::RESPONSE_ACCEPT);
664 Gtk::VBox* vbox = dialog.get_vbox();
667 Gtk::SpinButton spin(0.0, 4);
668 spin.set_increments(1.0, 10.0);
669 spin.set_range(-1000000.0, 1000000.0);
670 spin.set_numeric(true);
671 spin.set_value(atof(nodetextmap[active_node]->property_text().get_value().c_str()));
676 entry.set_text(nodetextmap[active_node]->property_text().get_value());
680 switch (dialog.run())
682 case Gtk::RESPONSE_NONE:
683 case Gtk::RESPONSE_CANCEL:
685 case Gtk::RESPONSE_ACCEPT:
686 switch (ms.getNodeMapElementType(nodemap_to_edit))
688 case MapValue::NUMERIC:
689 ms.set(nodemap_to_edit, active_node,
690 atof(entry.get_text().c_str()));
692 case MapValue::STRING:
693 ms.set(nodemap_to_edit, active_node,
694 static_cast<std::string>(entry.get_text()));
697 nodetextmap[active_node]->property_text().set_value(
698 static_cast<std::string>(ms.get(nodemap_to_edit, active_node)));
700 //mapwin.updateNode(active_node);
701 //mapwin.updateNode(Node(INVALID));
702 propertyUpdate(Node(INVALID));
707 //if it was really an arc...
708 if(clicked_arc!=INVALID)
710 // the id map is not editable
711 if (arcmap_to_edit == "label") return 0;
713 //and there is activated map
714 if(arctextmap[clicked_arc]->property_text().get_value()!="")
716 //activate the general variable for it
717 active_arc=clicked_arc;
720 Gtk::Dialog dialog("Edit value", true);
721 dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
722 dialog.add_button(Gtk::Stock::OK, Gtk::RESPONSE_ACCEPT);
723 Gtk::VBox* vbox = dialog.get_vbox();
726 Gtk::SpinButton spin(0.0, 4);
727 spin.set_increments(1.0, 10.0);
728 spin.set_range(-1000000.0, 1000000.0);
729 spin.set_numeric(true);
730 spin.set_value(atof(arctextmap[active_arc]->property_text().get_value().c_str()));
735 entry.set_text(arctextmap[active_arc]->property_text().get_value());
739 std::cout << arcmap_to_edit << std::endl;
740 switch (dialog.run())
742 case Gtk::RESPONSE_NONE:
743 case Gtk::RESPONSE_CANCEL:
745 case Gtk::RESPONSE_ACCEPT:
746 switch (ms.getArcMapElementType(arcmap_to_edit))
748 case MapValue::NUMERIC:
749 ms.set(arcmap_to_edit, active_arc,
750 atof(entry.get_text().c_str()));
752 case MapValue::STRING:
753 ms.set(arcmap_to_edit, active_arc,
754 static_cast<std::string>(entry.get_text()));
757 arctextmap[active_arc]->property_text().set_value(
758 static_cast<std::string>(ms.get(arcmap_to_edit, active_arc)));
760 //mapwin.updateArc(active_arc);
761 // mapwin.updateArc(Arc(INVALID));
762 propertyUpdate(Arc(INVALID));
775 void DigraphDisplayerCanvas::deleteItem(Node node_to_delete)
777 delete(nodetextmap[node_to_delete]);
778 delete(nodesmap[node_to_delete]);
779 mytab.mapstorage->digraph.erase(node_to_delete);
782 void DigraphDisplayerCanvas::deleteItem(Arc arc_to_delete)
784 delete(arctextmap[arc_to_delete]);
785 delete(arcsmap[arc_to_delete]);
786 mytab.mapstorage->digraph.erase(arc_to_delete);
789 void DigraphDisplayerCanvas::textReposition(XY new_place)
791 new_place+=(XY(10,10));
792 arctextmap[forming_arc]->property_x().set_value(new_place.x);
793 arctextmap[forming_arc]->property_y().set_value(new_place.y);
796 void DigraphDisplayerCanvas::toggleArcActivity(ArcBase* active_bre, bool on)
800 if(forming_arc!=INVALID)
802 std::cerr << "ERROR!!!! Valid arc found!" << std::endl;
806 for (ArcIt i(mytab.mapstorage->digraph); i!=INVALID; ++i)
808 if(arcsmap[i]==active_bre)
817 if(forming_arc!=INVALID)
823 std::cerr << "ERROR!!!! Invalid arc found!" << std::endl;
828 void DigraphDisplayerCanvas::moveNode(double dx, double dy, Gnome::Canvas::Item * item, Node node)
830 MapStorage& ms = *mytab.mapstorage;
832 Gnome::Canvas::Item * moved_item=item;
833 Node moved_node=node;
835 if(item==NULL && node==INVALID)
837 moved_item=active_item;
838 moved_node=active_node;
845 //repositioning node and its text
846 moved_item->move(dx, dy);
847 nodetextmap[moved_node]->move(dx, dy);
849 // the new coordinates of the centre of the node
850 double coord_x = dx + ms.getNodeCoords(moved_node).x;
851 double coord_y = dy + ms.getNodeCoords(moved_node).y;
853 // write back the new coordinates to the coords map
854 ms.setNodeCoords(moved_node, XY(coord_x, coord_y));
856 //all the arcs connected to the moved point has to be redrawn
857 for(OutArcIt ei(ms.digraph,moved_node);ei!=INVALID;++ei)
861 if (ms.digraph.source(ei) == ms.digraph.target(ei))
863 arrow_pos = ms.getArrowCoords(ei) + XY(dx, dy);
867 XY moved_node_1(coord_x - dx, coord_y - dy);
868 XY moved_node_2(coord_x, coord_y);
869 Node target = ms.digraph.target(ei);
870 XY fix_node = ms.getNodeCoords(target);
871 XY old_arrow_pos(ms.getArrowCoords(ei));
873 arrow_pos = calcArrowPos(moved_node_1, moved_node_2, fix_node, old_arrow_pos, isbutton);
876 ms.setArrowCoords(ei, arrow_pos);
879 //reposition of arctext
880 XY text_pos=ms.getArrowCoords(ei);
881 text_pos+=(XY(10,10));
882 arctextmap[ei]->property_x().set_value(text_pos.x);
883 arctextmap[ei]->property_y().set_value(text_pos.y);
886 for(InArcIt ei(ms.digraph,moved_node);ei!=INVALID;++ei)
888 if (ms.digraph.source(ei) != ms.digraph.target(ei))
890 XY moved_node_1(coord_x - dx, coord_y - dy);
891 XY moved_node_2(coord_x, coord_y);
892 Node source = ms.digraph.source(ei);
893 XY fix_node = ms.getNodeCoords(source);
894 XY old_arrow_pos(ms.getArrowCoords(ei));
897 arrow_pos = calcArrowPos(moved_node_1, moved_node_2, fix_node, old_arrow_pos, isbutton);
899 ms.setArrowCoords(ei, arrow_pos);
902 //reposition of arctext
903 XY text_pos=ms.getArrowCoords(ei);
904 text_pos+=(XY(10,10));
905 arctextmap[ei]->property_x().set_value(text_pos.x);
906 arctextmap[ei]->property_y().set_value(text_pos.y);
911 Gdk::Color DigraphDisplayerCanvas::rainbowColorCounter(double min, double max, double w)
915 double pos=(w-min)/(max-min);
918 //rainbow transitions contain 6 phase
919 //in each phase only one color is changed
920 //first we determine the phase, in which
921 //the actual value belongs to
922 for (int i=0;i<=5;i++)
924 if(((double)i/6<pos)&&(pos<=(double(i+1)/6)))
931 //within its 1/6 long phase the relativ position
932 //determines the power of the color changed in
934 //we normalize that to one, to be able to give percentage
935 //value for the function
936 double rel_pos=(pos-(phase/6.0))*6.0;
941 color.set_rgb_p (1, 0, 1-rel_pos);
944 color.set_rgb_p (1, rel_pos, 0);
947 color.set_rgb_p (1-rel_pos, 1, 0);
950 color.set_rgb_p (0, 1, rel_pos);
953 color.set_rgb_p (0, 1-rel_pos, 1);
956 color.set_rgb_p ((rel_pos/3.0), 0, 1);
959 std::cout << "Wrong phase: " << phase << " " << pos << std::endl;
964 std::cout << "Wrong phase: " << phase << " " << pos << std::endl;