# HG changeset patch # User hegyi # Date 1160653169 0 # Node ID 14a76109b5612c1b94f30df09b58ac1808c47922 # Parent 7ea73c90a7f0367b3329b67d9ca343c0bc57ca9d Node antigravity and edge elasticity based graph layout redesigner. diff -r 7ea73c90a7f0 -r 14a76109b561 Makefile.am --- a/Makefile.am Mon Oct 09 08:06:31 2006 +0000 +++ b/Makefile.am Thu Oct 12 11:39:29 2006 +0000 @@ -42,7 +42,9 @@ xml.h \ guipixbufs.h \ i18n.h \ - gettext.h + gettext.h \ + design_win.h \ + design_win.cc glemon_CXXFLAGS = $(GTK_CFLAGS) $(LEMON_CFLAGS) glemon_LDFLAGS = $(GTK_LIBS) $(LEMON_LIBS) diff -r 7ea73c90a7f0 -r 14a76109b561 graph_displayer_canvas-event.cc --- a/graph_displayer_canvas-event.cc Mon Oct 09 08:06:31 2006 +0000 +++ b/graph_displayer_canvas-event.cc Thu Oct 12 11:39:29 2006 +0000 @@ -81,11 +81,11 @@ { static Gnome::Canvas::Text *coord_text = 0; switch(e->type) - { + { case GDK_BUTTON_PRESS: //we mark the location of the event to be able to calculate parameters of dragging window_to_world (e->button.x, e->button.y, clicked_x, clicked_y); - + active_item=(get_item_at(clicked_x, clicked_y)); active_node=INVALID; for (NodeIt i((mytab.mapstorage).graph); i!=INVALID; ++i) @@ -99,10 +99,10 @@ break; case GDK_BUTTON_RELEASE: if (coord_text) - { - delete coord_text; - coord_text = 0; - } + { + delete coord_text; + coord_text = 0; + } isbutton=0; active_item=NULL; active_node=INVALID; @@ -110,122 +110,59 @@ case GDK_MOTION_NOTIFY: //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 if(active_node!=INVALID) - { - (mytab.mapstorage).modified = true; + { + (mytab.mapstorage).modified = true; + + //new coordinates will be the old values, + //because the item will be moved to the + //new coordinate therefore the new movement + //has to be calculated from here + + double new_x, new_y; + + window_to_world (e->motion.x, e->motion.y, new_x, new_y); + + double dx=new_x-clicked_x; + double dy=new_y-clicked_y; + + moveNode(dx, dy); - //new coordinates will be the old values, - //because the item will be moved to the - //new coordinate therefore the new movement - //has to be calculated from here + clicked_x=new_x; + clicked_y=new_y; - double new_x, new_y; + // reposition the coordinates text + std::ostringstream ostr; + ostr << "(" << + (mytab.mapstorage).coords[active_node].x << ", " << + (mytab.mapstorage).coords[active_node].y << ")"; + double radius = + (nodesmap[active_node]->property_x2().get_value() - + nodesmap[active_node]->property_x1().get_value()) / 2.0; + if (coord_text) + { + coord_text->property_text().set_value(ostr.str()); + coord_text->property_x().set_value((mytab.mapstorage).coords[active_node].x + + radius); + coord_text->property_y().set_value((mytab.mapstorage).coords[active_node].y - + radius); + } + else + { + coord_text = new Gnome::Canvas::Text( + displayed_graph, + (mytab.mapstorage).coords[active_node].x + radius, + (mytab.mapstorage).coords[active_node].y - radius, + ostr.str()); + coord_text->property_fill_color().set_value("black"); + coord_text->property_anchor().set_value(Gtk::ANCHOR_SOUTH_WEST); + } - window_to_world (e->motion.x, e->motion.y, new_x, new_y); - double dx=new_x-clicked_x; - double dy=new_y-clicked_y; + } + default: break; + } - //repositioning node and its text - active_item->move(dx, dy); - nodetextmap[active_node]->move(dx, dy); - - // the new coordinates of the centre of the node - double coord_x = new_x - (clicked_x - (mytab.mapstorage).coords[active_node].x); - double coord_y = new_y - (clicked_y - (mytab.mapstorage).coords[active_node].y); - - // write back the new coordinates to the coords map - (mytab.mapstorage).coords.set(active_node, XY(coord_x, coord_y)); - - clicked_x=new_x; - clicked_y=new_y; - - // reposition the coordinates text - std::ostringstream ostr; - ostr << "(" << - (mytab.mapstorage).coords[active_node].x << ", " << - (mytab.mapstorage).coords[active_node].y << ")"; - double radius = - (nodesmap[active_node]->property_x2().get_value() - - nodesmap[active_node]->property_x1().get_value()) / 2.0; - if (coord_text) - { - coord_text->property_text().set_value(ostr.str()); - coord_text->property_x().set_value((mytab.mapstorage).coords[active_node].x + - radius); - coord_text->property_y().set_value((mytab.mapstorage).coords[active_node].y - - radius); - } - else - { - coord_text = new Gnome::Canvas::Text( - displayed_graph, - (mytab.mapstorage).coords[active_node].x + radius, - (mytab.mapstorage).coords[active_node].y - radius, - ostr.str()); - coord_text->property_fill_color().set_value("black"); - coord_text->property_anchor().set_value(Gtk::ANCHOR_SOUTH_WEST); - } - - //all the edges connected to the moved point has to be redrawn - for(OutEdgeIt ei((mytab.mapstorage).graph,active_node);ei!=INVALID;++ei) - { - XY arrow_pos; - - if (mytab.mapstorage.graph.source(ei) == mytab.mapstorage.graph.target(ei)) - { - arrow_pos = mytab.mapstorage.arrow_pos[ei] + XY(dx, dy); - } - else - { - XY moved_node_1(coord_x - dx, coord_y - dy); - XY moved_node_2(coord_x, coord_y); - Node target = mytab.mapstorage.graph.target(ei); - XY fix_node(mytab.mapstorage.coords[target].x, - mytab.mapstorage.coords[target].y); - XY old_arrow_pos(mytab.mapstorage.arrow_pos[ei]); - - arrow_pos = calcArrowPos(moved_node_1, moved_node_2, fix_node, old_arrow_pos, isbutton); - } - - mytab.mapstorage.arrow_pos.set(ei, arrow_pos); - edgesmap[ei]->draw(); - - //reposition of edgetext - XY text_pos=mytab.mapstorage.arrow_pos[ei]; - text_pos+=(XY(10,10)); - edgetextmap[ei]->property_x().set_value(text_pos.x); - edgetextmap[ei]->property_y().set_value(text_pos.y); - } - - for(InEdgeIt ei((mytab.mapstorage).graph,active_node);ei!=INVALID;++ei) - { - if (mytab.mapstorage.graph.source(ei) != mytab.mapstorage.graph.target(ei)) - { - XY moved_node_1(coord_x - dx, coord_y - dy); - XY moved_node_2(coord_x, coord_y); - Node source = mytab.mapstorage.graph.source(ei); - XY fix_node(mytab.mapstorage.coords[source].x, - mytab.mapstorage.coords[source].y); - XY old_arrow_pos(mytab.mapstorage.arrow_pos[ei]); - - XY arrow_pos; - arrow_pos = calcArrowPos(moved_node_1, moved_node_2, fix_node, old_arrow_pos, isbutton); - - mytab.mapstorage.arrow_pos.set(ei, arrow_pos); - edgesmap[ei]->draw(); - - //reposition of edgetext - XY text_pos=mytab.mapstorage.arrow_pos[ei]; - text_pos+=(XY(10,10)); - edgetextmap[ei]->property_x().set_value(text_pos.x); - edgetextmap[ei]->property_y().set_value(text_pos.y); - } - } - } - default: break; - } - - return false; +return false; } XY GraphDisplayerCanvas::calcArrowPos(XY moved_node_1, XY moved_node_2, XY fix_node, XY old_arrow_pos, int move_code) @@ -823,14 +760,97 @@ } } else - { - if(forming_edge!=INVALID) { - forming_edge=INVALID; + if(forming_edge!=INVALID) + { + forming_edge=INVALID; + } + else + { + std::cerr << "ERROR!!!! Invalid edge found!" << std::endl; + } } - else +} + +void GraphDisplayerCanvas::moveNode(double dx, double dy, Gnome::Canvas::Item * item, Node node) +{ + Gnome::Canvas::Item * moved_item=item; + Node moved_node=node; + + if(item==NULL && node==INVALID) { - std::cerr << "ERROR!!!! Invalid edge found!" << std::endl; + moved_item=active_item; + moved_node=active_node; } - } + else + { + isbutton=1; + } + + //repositioning node and its text + moved_item->move(dx, dy); + nodetextmap[moved_node]->move(dx, dy); + + // the new coordinates of the centre of the node + double coord_x = dx + (mytab.mapstorage).coords[moved_node].x; + double coord_y = dy + (mytab.mapstorage).coords[moved_node].y; + + // write back the new coordinates to the coords map + (mytab.mapstorage).coords.set(moved_node, XY(coord_x, coord_y)); + + //all the edges connected to the moved point has to be redrawn + for(OutEdgeIt ei((mytab.mapstorage).graph,moved_node);ei!=INVALID;++ei) + { + XY arrow_pos; + + if (mytab.mapstorage.graph.source(ei) == mytab.mapstorage.graph.target(ei)) + { + arrow_pos = mytab.mapstorage.arrow_pos[ei] + XY(dx, dy); + } + else + { + XY moved_node_1(coord_x - dx, coord_y - dy); + XY moved_node_2(coord_x, coord_y); + Node target = mytab.mapstorage.graph.target(ei); + XY fix_node(mytab.mapstorage.coords[target].x, + mytab.mapstorage.coords[target].y); + XY old_arrow_pos(mytab.mapstorage.arrow_pos[ei]); + + arrow_pos = calcArrowPos(moved_node_1, moved_node_2, fix_node, old_arrow_pos, isbutton); + } + + mytab.mapstorage.arrow_pos.set(ei, arrow_pos); + edgesmap[ei]->draw(); + + //reposition of edgetext + XY text_pos=mytab.mapstorage.arrow_pos[ei]; + text_pos+=(XY(10,10)); + edgetextmap[ei]->property_x().set_value(text_pos.x); + edgetextmap[ei]->property_y().set_value(text_pos.y); + } + + for(InEdgeIt ei((mytab.mapstorage).graph,moved_node);ei!=INVALID;++ei) + { + if (mytab.mapstorage.graph.source(ei) != mytab.mapstorage.graph.target(ei)) + { + XY moved_node_1(coord_x - dx, coord_y - dy); + XY moved_node_2(coord_x, coord_y); + Node source = mytab.mapstorage.graph.source(ei); + XY fix_node(mytab.mapstorage.coords[source].x, + mytab.mapstorage.coords[source].y); + XY old_arrow_pos(mytab.mapstorage.arrow_pos[ei]); + + XY arrow_pos; + arrow_pos = calcArrowPos(moved_node_1, moved_node_2, fix_node, old_arrow_pos, isbutton); + + mytab.mapstorage.arrow_pos.set(ei, arrow_pos); + edgesmap[ei]->draw(); + + //reposition of edgetext + XY text_pos=mytab.mapstorage.arrow_pos[ei]; + text_pos+=(XY(10,10)); + edgetextmap[ei]->property_x().set_value(text_pos.x); + edgetextmap[ei]->property_y().set_value(text_pos.y); + } + } } diff -r 7ea73c90a7f0 -r 14a76109b561 graph_displayer_canvas.cc --- a/graph_displayer_canvas.cc Mon Oct 09 08:06:31 2006 +0000 +++ b/graph_displayer_canvas.cc Thu Oct 12 11:39:29 2006 +0000 @@ -5,7 +5,8 @@ nodesmap(mainw.mapstorage.graph), edgesmap(mainw.mapstorage.graph), edgetextmap(mainw.mapstorage.graph), nodetextmap(mainw.mapstorage.graph), displayed_graph(*(root()), 0, 0), isbutton(0), active_item(NULL), target_item(NULL), nodemap_to_edit(""), - edgemap_to_edit(""), autoscale(true), zoomtrack(false), radius_size(20), edge_width(10), mytab(mainw) + edgemap_to_edit(""), autoscale(true), zoomtrack(false), radius_size(20), edge_width(10), + iterations(20), attraction(0.05), propulsation(40000), mytab(mainw) { //base event handler is move tool actual_handler=signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::moveEventHandler), false); @@ -251,3 +252,117 @@ width_p=edge_width; radius_p=radius_size; } + +void GraphDisplayerCanvas::reDesignGraph() +{ + double min_dist=40; + + //iteration counter + for(int l=0;l x(mytab.mapstorage.graph); + Graph::NodeMap y(mytab.mapstorage.graph); + XYMap > actual_forces; + actual_forces.setXMap(x); + actual_forces.setYMap(y); + + lemon::dim2::Point delta; + + //count actual force for each nodes + for (NodeIt i((mytab.mapstorage).graph); i!=INVALID; ++i) + { + //propulsation of nodes + for (NodeIt j((mytab.mapstorage).graph); j!=INVALID; ++j) + { + if(i!=j) + { + delta=((mytab.mapstorage).coords[i]-(mytab.mapstorage).coords[j]); + + double length_sqr=delta.normSquare(); + double length=sqrt(length_sqr); + if(length_sqradd( Gtk::Action::create("ShowMenu", _("_Show")) ); ag->add( Gtk::Action::create("ShowMaps", _("_Maps")), sigc::mem_fun(*this, &MainWin::createMapWin)); + ag->add( Gtk::Action::create("ShowDesign", _("_Design")), + sigc::mem_fun(*this, &MainWin::createDesignWin)); ag->add( Gtk::Action::create("AlgoMenu", _("_Algorithms")) ); ag->add( Gtk::Action::create("AlgoGeneral", _("_General")), @@ -122,6 +124,9 @@ ag->add( Gtk::Action::create("AddMap", Gtk::StockID("gd-newmap")), sigc::mem_fun ( *this , &MainWin::createNewMapWin ) ); + ag->add( Gtk::Action::create("DesignGraph", Gtk::Stock::REFRESH), + sigc::mem_fun ( *this , &MainWin::reDesignGraph ) ); + uim=Gtk::UIManager::create(); uim->insert_action_group(ag); add_accel_group(uim->get_accel_group()); @@ -149,6 +154,7 @@ " " " " " " + " " " " " " " " @@ -173,6 +179,7 @@ " " " " " " + " " " " ""; @@ -448,6 +455,14 @@ } } +void MainWin::createDesignWin() +{ + if(active_tab!=-1) + { + tabs[active_tab]->createDesignWin(tabnames[active_tab]); + } +} + void MainWin::createAlgoWin(int algoid) { AlgoWin * aw=new AlgoWin(algoid, tabnames); @@ -536,3 +551,8 @@ bool autoscale=auto_scale->get_active(); tabs[active_tab]->setView(autoscale, zoomtrack, width, radius); } + +void MainWin::reDesignGraph() +{ + tabs[active_tab]->reDesignGraph(); +} diff -r 7ea73c90a7f0 -r 14a76109b561 main_win.h --- a/main_win.h Mon Oct 09 08:06:31 2006 +0000 +++ b/main_win.h Thu Oct 12 11:39:29 2006 +0000 @@ -145,6 +145,12 @@ ///\ref NoteBookTab virtual void createMapWin(); + ///Callback for Show Design menupoint. + + ///It calls the appropriate function in + ///\ref NoteBookTab + virtual void createDesignWin(); + ///Pops up an Algorithm window. ///It not only creates but registrates the newly created \ref AlgoWin. @@ -237,6 +243,8 @@ virtual void onChangeTab(GtkNotebookPage*, guint); virtual void nodeViewChanged(); + + virtual void reDesignGraph(); }; #endif //MAIN_WIN_H diff -r 7ea73c90a7f0 -r 14a76109b561 nbtab.cc --- a/nbtab.cc Mon Oct 09 08:06:31 2006 +0000 +++ b/nbtab.cc Thu Oct 12 11:39:29 2006 +0000 @@ -1,6 +1,6 @@ #include -NoteBookTab::NoteBookTab():mapwinexists(false) +NoteBookTab::NoteBookTab():mapwinexists(false), designwinexists(false) { Gtk::ScrolledWindow *pScrolledWindow = manage(new Gtk::ScrolledWindow); gd_canvas=new GraphDisplayerCanvas(*this); @@ -207,12 +207,42 @@ } } +void NoteBookTab::createDesignWin(std::string name) +{ + if(!designwinexists) + { + double attraction, propulsation; + int iterations; + gd_canvas->get_design_data(attraction, propulsation, iterations); + designwin=new DesignWin("Design Setup - "+name, attraction, propulsation, iterations); + + designwin->signal_attraction().connect(sigc::mem_fun(*this, &NoteBookTab::attraction_ch)); + designwin->signal_propulsation().connect(sigc::mem_fun(*this, &NoteBookTab::propulsation_ch)); + designwin->signal_iteration().connect(sigc::mem_fun(*gd_canvas, &GraphDisplayerCanvas::set_iteration)); + designwin->close_run().connect(sigc::mem_fun(*gd_canvas, &GraphDisplayerCanvas::reDesignGraph)); + + designwin->signal_delete_event().connect(sigc::mem_fun(*this, &NoteBookTab::closeDesignWin)); + + designwin->show(); + designwinexists=true; + } +} + void NoteBookTab::closeMapWin() { mapwinexists=false; delete mapwin; } +bool NoteBookTab::closeDesignWin(GdkEventAny * e) +{ + if(e->type==GDK_DELETE) + { + designwinexists=false; + delete designwin; + } +} + sigc::signal NoteBookTab::signal_title_ch() { return signal_title; @@ -227,3 +257,24 @@ { gd_canvas->getView(autoscale, zoomtrack, width, radius); } + +void NoteBookTab::reDesignGraph() +{ + gd_canvas->reDesignGraph(); +} + +void NoteBookTab::attraction_ch(double v) +{ + gd_canvas->set_attraction(v); +} + +void NoteBookTab::propulsation_ch(double v) +{ + gd_canvas->set_propulsation(v); +} + +void NoteBookTab::iteration_ch(int v) +{ + gd_canvas->set_iteration(v); +} + diff -r 7ea73c90a7f0 -r 14a76109b561 nbtab.h --- a/nbtab.h Mon Oct 09 08:06:31 2006 +0000 +++ b/nbtab.h Thu Oct 12 11:39:29 2006 +0000 @@ -7,6 +7,7 @@ #include "mapstorage.h" #include "map_win.h" +#include "design_win.h" #include "graph_displayer_canvas.h" #include #include @@ -77,6 +78,9 @@ ///Indicates whether the \ref MapWin is opened or not. See \ref mapwin. bool mapwinexists; + ///Indicates whether the \ref DesignWin is opened or not. See \ref designwin. + bool designwinexists; + ///Address of the only \ref MapWin that the \ref NoteBookTab can open. ///Only one of this window can be opened at the same time (\ref mapwinexists), @@ -85,6 +89,14 @@ ///more complicated to synchronize them. MapWin * mapwin; + ///Address of the only \ref DesignWin that the \ref NoteBookTab can open. + + ///Only one of this window can be opened at the same time (\ref designwinexists), + ///because there is no need for more, one per tab is enough. + ///There won't be benefit of more than one, but it would be + ///more complicated to synchronize them. + DesignWin * designwin; + public: ///Callback for 'FileNew' action. virtual void newFile(); @@ -151,17 +163,33 @@ ///\ref mapwin. void createMapWin(std::string); + ///Pops up and registrates the \ref DesignWin of \ref NoteBookTab. + + ///See also + ///\ref mapwin. + void createDesignWin(std::string); + ///Closes and deregistrates the \ref MapWin of \ref NoteBookTab. ///See also ///\ref mapwin. void closeMapWin(); + bool closeDesignWin(GdkEventAny *); + ///Sets node representation settings void setView(bool, bool, double, double); ///Gets node representation settings void getView(bool &, bool &, double&, double&); + + void reDesignGraph(); + + void attraction_ch(double); + + void propulsation_ch(double); + + void iteration_ch(int); }; #endif //NBTAB_H