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 | } |
---|