// This example was started by Guillaume Laurent. // It has become a place to dump code that tests parts of the // gnomemm canvas code. Little thought has been given to the // actual on-screen output. #include #include #include #include #include #include #include #include #include #include #include using namespace lemon; typedef xy Coordinates; typedef ListGraph Graph; typedef Graph::NodeMap CoordinatesMap; typedef Graph::Node Node; typedef Graph::EdgeIt EdgeIt; typedef Graph::NodeIt NodeIt; class GraphDisplayerCanvas : public Gnome::Canvas::CanvasAA { typedef Gnome::Canvas::CanvasAA Parent; public: GraphDisplayerCanvas(Graph &, CoordinatesMap &); virtual ~GraphDisplayerCanvas(); private: ///Event handler function that handles dragging nodes of displayed_graph bool event_handler(GdkEvent* e, Node n); ///The graph, on which we work Graph g; ///Map of nodes of planefigure Graph::NodeMap nodesmap; ///Map of edges of planefigure Graph::EdgeMap edgesmap; ///Group of graphical elements of displayed_graph Gnome::Canvas::Group displayed_graph; ///Indicates whether the button of mouse is pressed or not bool isbutton; ///At this location was the mousebutton pressed. ///It helps to calculate the distance of dragging. double clicked_x, clicked_y; ///Remembers which Gnome::Canvas::Item was pressed. ///this variable is needed, because ///1. we cannot query the item at he cursor as fast as it could not cause a Segmentation Fault ///2. we would like to handle only ony item per movement, therefore quering it is not a working solution Gnome::Canvas::Item * active_item; }; ///This function moves only one node of displayed_graph, ///but recalculate the location of weight point, ///and also redraw the sides of the planefigure. bool GraphDisplayerCanvas::event_handler(GdkEvent* e, Node n) { switch(e->type) { case GDK_BUTTON_PRESS: clicked_x=e->button.x; clicked_y=e->button.y; active_item=(get_item_at(e->button.x, e->button.y)); isbutton=true; break; case GDK_BUTTON_RELEASE: isbutton=false; active_item=NULL; break; case GDK_MOTION_NOTIFY: if(isbutton) { double dx=e->motion.x-clicked_x; double dy=e->motion.y-clicked_y; active_item->move(dx, dy); clicked_x=e->motion.x; clicked_y=e->motion.y; EdgeIt e; g.firstOut(e,n); for(;e!=INVALID;g.nextOut(e)) { Gnome::Canvas::Points coos; double x1, x2, y1, y2; nodesmap[g.source(e)]->get_bounds(x1, y1, x2, y2); coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2)); nodesmap[g.target(e)]->get_bounds(x1, y1, x2, y2); coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2)); edgesmap[e]->property_points().set_value(coos); } g.firstIn(e,n); for(;e!=INVALID;g.nextIn(e)) { Gnome::Canvas::Points coos; double x1, x2, y1, y2; nodesmap[g.source(e)]->get_bounds(x1, y1, x2, y2); coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2)); nodesmap[g.target(e)]->get_bounds(x1, y1, x2, y2); coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2)); edgesmap[e]->property_points().set_value(coos); } } default: break; } return true; } GraphDisplayerCanvas::GraphDisplayerCanvas(Graph & gr, CoordinatesMap & cm):g(gr),nodesmap(g),edgesmap(g),displayed_graph(*(root()), 0, 0),isbutton(false),active_item(NULL) { for (EdgeIt i(g); i!=INVALID; ++i) { Gnome::Canvas::Points coos; coos.push_back(Gnome::Art::Point(cm[g.source(i)].x,cm[g.source(i)].y)); coos.push_back(Gnome::Art::Point(cm[g.target(i)].x,cm[g.target(i)].y)); edgesmap[i]=new Gnome::Canvas::Line(displayed_graph, coos); *(edgesmap[i]) << Gnome::Canvas::Properties::fill_color("green"); edgesmap[i]->property_width_pixels().set_value(10); } for (NodeIt i(g); i!=INVALID; ++i) { nodesmap[i]=new Gnome::Canvas::Ellipse(displayed_graph, cm[i].x-20, cm[i].y-20, cm[i].x+20, cm[i].y+20); *(nodesmap[i]) << Gnome::Canvas::Properties::fill_color("blue"); *(nodesmap[i]) << Gnome::Canvas::Properties::outline_color("black"); (nodesmap[i])->signal_event().connect(sigc::bind(sigc::mem_fun(*this, &GraphDisplayerCanvas::event_handler),i)); } } GraphDisplayerCanvas::~GraphDisplayerCanvas() { Graph::NodeMap id(g); Graph::NodeMap xc(g); Graph::NodeMap yc(g); int j=1; for (NodeIt i(g); i!=INVALID; ++i) { double x1,y1,x2,y2; nodesmap[i]->get_bounds(x1, y1, x2, y2); id[i]=j++; xc[i]=(x1+x2)/2; yc[i]=(y1+y2)/2; } GraphWriter writer(std::cout,g); writer.addNodeMap("id", id); writer.addNodeMap("coordinates_x", xc); writer.addNodeMap("coordinates_y", yc); writer.run(); } //MainWin: class MainWin : public Gtk::Window { public: MainWin(const std::string& title, Graph &, CoordinatesMap &); protected: //Member widgets: GraphDisplayerCanvas gd_canvas; }; MainWin::MainWin(const std::string& title, Graph & graph, CoordinatesMap & cm):gd_canvas(graph, cm) { set_title (title); add(gd_canvas); set_default_size(900,600); show_all(); } ///This class is responsible for being able ///to read xy datastructure from file. It is ///based on BaseMap. The set method sets the ///appropriate value in the final xy NodeMap ///that was given to the constructor. class CoordReaderMap: public MapBase { CoordinatesMap & cm; char xoy; public: CoordReaderMap(char xory, CoordinatesMap & coordmap); void set(Node node, double coord); }; ///The constructor expects for an xy NodeMap, ///and we have to tell it, for which value ///of the xy vector is responsible the actual ///copy. CoordReaderMap::CoordReaderMap(char xory, CoordinatesMap & coordmap): cm(coordmap) { switch(xory) { case 'x': case 'y': xoy=xory; break; default: throw UninitializedParameter() ; } } ///set method sets the appropriate value in the ///xy type NodeMap that is under construction void CoordReaderMap::set(Node node, double coord) { switch(xoy) { case 'x': cm[node].x=coord; break; case 'y': cm[node].y=coord; break; default: throw UninitializedParameter() ; } } //main(): int main(int argc, char *argv[]) { if(argc<2) { std::cerr << "USAGE: gd " << endl; return 0; } Coordinates coosvector; Graph g; CoordinatesMap cm(g); Graph::EdgeMap cap(g); //we create one object to read x coordinates //and one to read y coordinate of nodes and write them to cm NodeMap. CoordReaderMap xreader('x',cm); CoordReaderMap yreader('y',cm); std::ifstream is(argv[1]); GraphReader reader(is, g); reader.addNodeMap("coordinates_x", xreader); reader.addNodeMap("coordinates_y", yreader); reader.run(); Gnome::Canvas::init(); Gtk::Main app(argc, argv); MainWin mainwin("Displayed Graph", g, cm); app.run(mainwin); return 0; }