1 // This example was started by Guillaume Laurent. |
|
2 // It has become a place to dump code that tests parts of the |
|
3 // gnomemm canvas code. Little thought has been given to the |
|
4 // actual on-screen output. |
|
5 |
|
6 #include <libgnomecanvasmm.h> |
|
7 #include <libgnomecanvasmm/polygon.h> |
|
8 |
|
9 #include <fstream> |
|
10 #include <iostream> |
|
11 |
|
12 #include <lemon/list_graph.h> |
|
13 #include <lemon/graph_reader.h> |
|
14 #include <lemon/graph_writer.h> |
|
15 #include <lemon/graph_utils.h> |
|
16 #include <lemon/maps.h> |
|
17 #include <lemon/error.h> |
|
18 #include <lemon/xy.h> |
|
19 |
|
20 using namespace lemon; |
|
21 |
|
22 typedef xy<double> Coordinates; |
|
23 typedef ListGraph Graph; |
|
24 typedef Graph::NodeMap<Coordinates> CoordinatesMap; |
|
25 typedef Graph::Node Node; |
|
26 typedef Graph::EdgeIt EdgeIt; |
|
27 typedef Graph::NodeIt NodeIt; |
|
28 |
|
29 class GraphDisplayerCanvas : public Gnome::Canvas::CanvasAA |
|
30 { |
|
31 typedef Gnome::Canvas::CanvasAA Parent; |
|
32 |
|
33 public: |
|
34 GraphDisplayerCanvas(Graph &, CoordinatesMap &); |
|
35 virtual ~GraphDisplayerCanvas(); |
|
36 |
|
37 private: |
|
38 |
|
39 ///Event handler function that handles dragging nodes of displayed_graph |
|
40 bool event_handler(GdkEvent* e, Node n); |
|
41 |
|
42 ///The graph, on which we work |
|
43 Graph g; |
|
44 ///Map of nodes of planefigure |
|
45 Graph::NodeMap<Gnome::Canvas::Ellipse *> nodesmap; |
|
46 ///Map of edges of planefigure |
|
47 Graph::EdgeMap<Gnome::Canvas::Line *> edgesmap; |
|
48 ///Group of graphical elements of displayed_graph |
|
49 Gnome::Canvas::Group displayed_graph; |
|
50 |
|
51 ///Indicates whether the button of mouse is pressed or not |
|
52 bool isbutton; |
|
53 |
|
54 ///At this location was the mousebutton pressed. |
|
55 ///It helps to calculate the distance of dragging. |
|
56 double clicked_x, clicked_y; |
|
57 |
|
58 ///Remembers which Gnome::Canvas::Item was pressed. |
|
59 ///this variable is needed, because |
|
60 ///1. we cannot query the item at he cursor as fast as it could not cause a Segmentation Fault |
|
61 ///2. we would like to handle only ony item per movement, therefore quering it is not a working solution |
|
62 Gnome::Canvas::Item * active_item; |
|
63 |
|
64 |
|
65 }; |
|
66 |
|
67 |
|
68 ///This function moves only one node of displayed_graph, |
|
69 ///but recalculate the location of weight point, |
|
70 ///and also redraw the sides of the planefigure. |
|
71 bool GraphDisplayerCanvas::event_handler(GdkEvent* e, Node n) |
|
72 { |
|
73 switch(e->type) |
|
74 { |
|
75 case GDK_BUTTON_PRESS: |
|
76 clicked_x=e->button.x; |
|
77 clicked_y=e->button.y; |
|
78 active_item=(get_item_at(e->button.x, e->button.y)); |
|
79 isbutton=true; |
|
80 break; |
|
81 case GDK_BUTTON_RELEASE: |
|
82 isbutton=false; |
|
83 active_item=NULL; |
|
84 break; |
|
85 case GDK_MOTION_NOTIFY: |
|
86 if(isbutton) |
|
87 { |
|
88 double dx=e->motion.x-clicked_x; |
|
89 double dy=e->motion.y-clicked_y; |
|
90 active_item->move(dx, dy); |
|
91 clicked_x=e->motion.x; |
|
92 clicked_y=e->motion.y; |
|
93 |
|
94 EdgeIt e; |
|
95 |
|
96 g.firstOut(e,n); |
|
97 for(;e!=INVALID;g.nextOut(e)) |
|
98 { |
|
99 Gnome::Canvas::Points coos; |
|
100 double x1, x2, y1, y2; |
|
101 |
|
102 nodesmap[g.source(e)]->get_bounds(x1, y1, x2, y2); |
|
103 coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2)); |
|
104 |
|
105 nodesmap[g.target(e)]->get_bounds(x1, y1, x2, y2); |
|
106 coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2)); |
|
107 |
|
108 edgesmap[e]->property_points().set_value(coos); |
|
109 } |
|
110 |
|
111 g.firstIn(e,n); |
|
112 for(;e!=INVALID;g.nextIn(e)) |
|
113 { |
|
114 Gnome::Canvas::Points coos; |
|
115 double x1, x2, y1, y2; |
|
116 |
|
117 nodesmap[g.source(e)]->get_bounds(x1, y1, x2, y2); |
|
118 coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2)); |
|
119 |
|
120 nodesmap[g.target(e)]->get_bounds(x1, y1, x2, y2); |
|
121 coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2)); |
|
122 |
|
123 edgesmap[e]->property_points().set_value(coos); |
|
124 } |
|
125 } |
|
126 default: break; |
|
127 } |
|
128 return true; |
|
129 } |
|
130 |
|
131 GraphDisplayerCanvas::GraphDisplayerCanvas(Graph & gr, CoordinatesMap & cm):g(gr),nodesmap(g),edgesmap(g),displayed_graph(*(root()), 0, 0),isbutton(false),active_item(NULL) |
|
132 { |
|
133 for (EdgeIt i(g); i!=INVALID; ++i) |
|
134 { |
|
135 Gnome::Canvas::Points coos; |
|
136 coos.push_back(Gnome::Art::Point(cm[g.source(i)].x,cm[g.source(i)].y)); |
|
137 coos.push_back(Gnome::Art::Point(cm[g.target(i)].x,cm[g.target(i)].y)); |
|
138 edgesmap[i]=new Gnome::Canvas::Line(displayed_graph, coos); |
|
139 *(edgesmap[i]) << Gnome::Canvas::Properties::fill_color("green"); |
|
140 edgesmap[i]->property_width_pixels().set_value(10); |
|
141 } |
|
142 for (NodeIt i(g); i!=INVALID; ++i) |
|
143 { |
|
144 nodesmap[i]=new Gnome::Canvas::Ellipse(displayed_graph, cm[i].x-20, cm[i].y-20, cm[i].x+20, cm[i].y+20); |
|
145 *(nodesmap[i]) << Gnome::Canvas::Properties::fill_color("blue"); |
|
146 *(nodesmap[i]) << Gnome::Canvas::Properties::outline_color("black"); |
|
147 (nodesmap[i])->signal_event().connect(sigc::bind(sigc::mem_fun(*this, &GraphDisplayerCanvas::event_handler),i)); |
|
148 } |
|
149 |
|
150 } |
|
151 |
|
152 GraphDisplayerCanvas::~GraphDisplayerCanvas() |
|
153 { |
|
154 Graph::NodeMap <int> id(g); |
|
155 Graph::NodeMap <double> xc(g); |
|
156 Graph::NodeMap <double> yc(g); |
|
157 |
|
158 int j=1; |
|
159 |
|
160 for (NodeIt i(g); i!=INVALID; ++i) |
|
161 { |
|
162 double x1,y1,x2,y2; |
|
163 nodesmap[i]->get_bounds(x1, y1, x2, y2); |
|
164 |
|
165 id[i]=j++; |
|
166 xc[i]=(x1+x2)/2; |
|
167 yc[i]=(y1+y2)/2; |
|
168 } |
|
169 |
|
170 GraphWriter<Graph> writer(std::cout,g); |
|
171 |
|
172 writer.addNodeMap("id", id); |
|
173 writer.addNodeMap("coordinates_x", xc); |
|
174 writer.addNodeMap("coordinates_y", yc); |
|
175 writer.run(); |
|
176 } |
|
177 |
|
178 |
|
179 //MainWin: |
|
180 class MainWin : public Gtk::Window |
|
181 { |
|
182 public: |
|
183 MainWin(const std::string& title, Graph &, CoordinatesMap &); |
|
184 |
|
185 protected: |
|
186 //Member widgets: |
|
187 GraphDisplayerCanvas gd_canvas; |
|
188 }; |
|
189 |
|
190 MainWin::MainWin(const std::string& title, Graph & graph, CoordinatesMap & cm):gd_canvas(graph, cm) |
|
191 { |
|
192 set_title (title); |
|
193 add(gd_canvas); |
|
194 set_default_size(900,600); |
|
195 |
|
196 show_all(); |
|
197 } |
|
198 |
|
199 |
|
200 ///This class is responsible for being able |
|
201 ///to read xy datastructure from file. It is |
|
202 ///based on BaseMap. The set method sets the |
|
203 ///appropriate value in the final xy NodeMap |
|
204 ///that was given to the constructor. |
|
205 class CoordReaderMap: public MapBase <Node, double> |
|
206 { |
|
207 CoordinatesMap & cm; |
|
208 char xoy; |
|
209 |
|
210 public: |
|
211 CoordReaderMap(char xory, CoordinatesMap & coordmap); |
|
212 void set(Node node, double coord); |
|
213 }; |
|
214 |
|
215 ///The constructor expects for an xy NodeMap, |
|
216 ///and we have to tell it, for which value |
|
217 ///of the xy vector is responsible the actual |
|
218 ///copy. |
|
219 CoordReaderMap::CoordReaderMap(char xory, CoordinatesMap & coordmap): cm(coordmap) |
|
220 { |
|
221 switch(xory) |
|
222 { |
|
223 case 'x': |
|
224 case 'y': |
|
225 xoy=xory; |
|
226 break; |
|
227 default: |
|
228 throw UninitializedParameter() ; |
|
229 } |
|
230 } |
|
231 |
|
232 ///set method sets the appropriate value in the |
|
233 ///xy type NodeMap that is under construction |
|
234 void CoordReaderMap::set(Node node, double coord) |
|
235 { |
|
236 switch(xoy) |
|
237 { |
|
238 case 'x': |
|
239 cm[node].x=coord; |
|
240 break; |
|
241 case 'y': |
|
242 cm[node].y=coord; |
|
243 break; |
|
244 default: |
|
245 throw UninitializedParameter() ; |
|
246 } |
|
247 } |
|
248 |
|
249 //main(): |
|
250 |
|
251 int main(int argc, char *argv[]) |
|
252 { |
|
253 if(argc<2) |
|
254 { |
|
255 std::cerr << "USAGE: gd <input filename.lgf>" << endl; |
|
256 return 0; |
|
257 } |
|
258 |
|
259 Coordinates coosvector; |
|
260 |
|
261 Graph g; |
|
262 |
|
263 CoordinatesMap cm(g); |
|
264 Graph::EdgeMap<double> cap(g); |
|
265 |
|
266 //we create one object to read x coordinates |
|
267 //and one to read y coordinate of nodes and write them to cm NodeMap. |
|
268 CoordReaderMap xreader('x',cm); |
|
269 CoordReaderMap yreader('y',cm); |
|
270 |
|
271 std::ifstream is(argv[1]); |
|
272 |
|
273 GraphReader<Graph> reader(is, g); |
|
274 reader.addNodeMap("coordinates_x", xreader); |
|
275 reader.addNodeMap("coordinates_y", yreader); |
|
276 reader.run(); |
|
277 |
|
278 Gnome::Canvas::init(); |
|
279 Gtk::Main app(argc, argv); |
|
280 |
|
281 MainWin mainwin("Displayed Graph", g, cm); |
|
282 app.run(mainwin); |
|
283 |
|
284 return 0; |
|
285 } |
|