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