|
1 #include <graph_displayer_canvas.h> |
|
2 #include <broken_edge.h> |
|
3 #include <math.h> |
|
4 |
|
5 |
|
6 bool GraphDisplayerCanvas::on_expose_event(GdkEventExpose *event) |
|
7 { |
|
8 Gnome::Canvas::CanvasAA::on_expose_event(event); |
|
9 //usleep(10000); |
|
10 //rezoom(); |
|
11 return true; |
|
12 } |
|
13 |
|
14 void GraphDisplayerCanvas::changeEditorialTool(int newtool) |
|
15 { |
|
16 actual_handler.disconnect(); |
|
17 |
|
18 if(actual_tool==CREATE_EDGE) |
|
19 { |
|
20 GdkEvent * generated=new GdkEvent(); |
|
21 generated->type=GDK_BUTTON_RELEASE; |
|
22 generated->button.button=3; |
|
23 create_edge_event_handler(generated); |
|
24 } |
|
25 |
|
26 actual_tool=newtool; |
|
27 |
|
28 switch(newtool) |
|
29 { |
|
30 case MOVE: |
|
31 actual_handler=displayed_graph.signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::move_event_handler), false); |
|
32 break; |
|
33 |
|
34 //it has to assigned to canvas, because all the canvas has to be monitored, not only the elements of the already drawn group |
|
35 case CREATE_NODE: |
|
36 actual_handler=signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::create_node_event_handler), false); |
|
37 break; |
|
38 |
|
39 case CREATE_EDGE: |
|
40 actual_handler=displayed_graph.signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::create_edge_event_handler), false); |
|
41 break; |
|
42 |
|
43 case ERASER: |
|
44 actual_handler=displayed_graph.signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::eraser_event_handler), false); |
|
45 break; |
|
46 |
|
47 default: |
|
48 break; |
|
49 } |
|
50 } |
|
51 |
|
52 int GraphDisplayerCanvas::get_actual_tool() |
|
53 { |
|
54 return actual_tool; |
|
55 } |
|
56 |
|
57 bool GraphDisplayerCanvas::move_event_handler(GdkEvent* e) |
|
58 { |
|
59 switch(e->type) |
|
60 { |
|
61 case GDK_BUTTON_PRESS: |
|
62 //we mark the location of the event to be able to calculate parameters of dragging |
|
63 clicked_x=e->button.x; |
|
64 clicked_y=e->button.y; |
|
65 active_item=(get_item_at(e->button.x, e->button.y)); |
|
66 active_node=INVALID; |
|
67 for (NodeIt i(g); i!=INVALID; ++i) |
|
68 { |
|
69 if(nodesmap[i]==active_item) |
|
70 { |
|
71 active_node=i; |
|
72 } |
|
73 } |
|
74 switch(e->button.button) |
|
75 { |
|
76 case 3: |
|
77 isbutton=3; |
|
78 break; |
|
79 default: |
|
80 isbutton=1; |
|
81 break; |
|
82 } |
|
83 break; |
|
84 case GDK_BUTTON_RELEASE: |
|
85 isbutton=0; |
|
86 active_item=NULL; |
|
87 active_node=INVALID; |
|
88 updateScrollRegion(); |
|
89 break; |
|
90 case GDK_MOTION_NOTIFY: |
|
91 //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 |
|
92 if(active_node!=INVALID) |
|
93 { |
|
94 //new coordinates will be the old values, |
|
95 //because the item will be moved to the |
|
96 //new coordinate therefore the new movement |
|
97 //has to be calculated from here |
|
98 |
|
99 double dx=e->motion.x-clicked_x; |
|
100 double dy=e->motion.y-clicked_y; |
|
101 |
|
102 active_item->move(dx, dy); |
|
103 |
|
104 clicked_x=e->motion.x; |
|
105 clicked_y=e->motion.y; |
|
106 |
|
107 //all the edges connected to the moved point has to be redrawn |
|
108 EdgeIt ei; |
|
109 |
|
110 g.firstOut(ei,active_node); |
|
111 |
|
112 for(;ei!=INVALID;g.nextOut(ei)) |
|
113 { |
|
114 Gnome::Canvas::Points coos; |
|
115 double x1, x2, y1, y2; |
|
116 |
|
117 nodesmap[g.source(ei)]->get_bounds(x1, y1, x2, y2); |
|
118 coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2)); |
|
119 |
|
120 nodesmap[g.target(ei)]->get_bounds(x1, y1, x2, y2); |
|
121 coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2)); |
|
122 |
|
123 if(isbutton==3) |
|
124 { |
|
125 edgesmap[ei]->set_points(coos); |
|
126 } |
|
127 else |
|
128 { |
|
129 edgesmap[ei]->set_points(coos,true); |
|
130 } |
|
131 |
|
132 xy<double> text_pos=edgesmap[ei]->get_arrow_pos(); |
|
133 text_pos+=(xy<double>(10,10)); |
|
134 edgetextmap[ei]->property_x().set_value(text_pos.x); |
|
135 edgetextmap[ei]->property_y().set_value(text_pos.y); |
|
136 } |
|
137 |
|
138 g.firstIn(ei,active_node); |
|
139 for(;ei!=INVALID;g.nextIn(ei)) |
|
140 { |
|
141 Gnome::Canvas::Points coos; |
|
142 double x1, x2, y1, y2; |
|
143 |
|
144 nodesmap[g.source(ei)]->get_bounds(x1, y1, x2, y2); |
|
145 coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2)); |
|
146 |
|
147 nodesmap[g.target(ei)]->get_bounds(x1, y1, x2, y2); |
|
148 coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2)); |
|
149 |
|
150 if(isbutton==3) |
|
151 { |
|
152 edgesmap[ei]->set_points(coos); |
|
153 } |
|
154 else |
|
155 { |
|
156 edgesmap[ei]->set_points(coos,true); |
|
157 } |
|
158 |
|
159 xy<double> text_pos=edgesmap[ei]->get_arrow_pos(); |
|
160 text_pos+=(xy<double>(10,10)); |
|
161 edgetextmap[ei]->property_x().set_value(text_pos.x); |
|
162 edgetextmap[ei]->property_y().set_value(text_pos.y); |
|
163 } |
|
164 } |
|
165 default: break; |
|
166 } |
|
167 |
|
168 return true; |
|
169 } |
|
170 |
|
171 bool GraphDisplayerCanvas::create_node_event_handler(GdkEvent* e) |
|
172 { |
|
173 switch(e->type) |
|
174 { |
|
175 |
|
176 //draw the new node in red at the clicked place |
|
177 case GDK_BUTTON_PRESS: |
|
178 isbutton=1; |
|
179 |
|
180 active_node=NodeIt(g,g.addNode()); |
|
181 |
|
182 //initiating values corresponding to new node in maps |
|
183 |
|
184 |
|
185 window_to_world (e->button.x, e->button.y, clicked_x, clicked_y); |
|
186 |
|
187 nodesmap[active_node]=new Gnome::Canvas::Ellipse(displayed_graph, clicked_x-20, clicked_y-20, clicked_x+20, clicked_y+20); |
|
188 active_item=(Gnome::Canvas::Item *)(nodesmap[active_node]); |
|
189 *(nodesmap[active_node]) << Gnome::Canvas::Properties::fill_color("red"); |
|
190 *(nodesmap[active_node]) << Gnome::Canvas::Properties::outline_color("black"); |
|
191 (nodesmap[active_node])->show(); |
|
192 break; |
|
193 |
|
194 //move the new node |
|
195 case GDK_MOTION_NOTIFY: |
|
196 { |
|
197 double world_motion_x, world_motion_y; |
|
198 GdkEvent * generated=new GdkEvent(); |
|
199 window_to_world (e->motion.x, e->motion.y, world_motion_x, world_motion_y); |
|
200 generated->motion.x=world_motion_x; |
|
201 generated->motion.y=world_motion_y; |
|
202 generated->type=GDK_MOTION_NOTIFY; |
|
203 move_event_handler(generated); |
|
204 break; |
|
205 } |
|
206 |
|
207 //finalize the new node |
|
208 case GDK_BUTTON_RELEASE: |
|
209 isbutton=0; |
|
210 *active_item << Gnome::Canvas::Properties::fill_color("blue"); |
|
211 active_item=NULL; |
|
212 active_node=INVALID; |
|
213 updateScrollRegion(); |
|
214 break; |
|
215 default: |
|
216 break; |
|
217 } |
|
218 return false; |
|
219 } |
|
220 |
|
221 bool GraphDisplayerCanvas::create_edge_event_handler(GdkEvent* e) |
|
222 { |
|
223 switch(e->type) |
|
224 { |
|
225 case GDK_BUTTON_PRESS: |
|
226 //in edge creation right button has special meaning |
|
227 if(e->button.button!=3) |
|
228 { |
|
229 //there is not yet selected node |
|
230 if(active_node==INVALID) |
|
231 { |
|
232 //we mark the location of the event to be able to calculate parameters of dragging |
|
233 clicked_x=e->button.x; |
|
234 clicked_y=e->button.y; |
|
235 active_item=(get_item_at(e->button.x, e->button.y)); |
|
236 active_node=INVALID; |
|
237 for (NodeIt i(g); i!=INVALID; ++i) |
|
238 { |
|
239 if(nodesmap[i]==active_item) |
|
240 { |
|
241 active_node=i; |
|
242 } |
|
243 } |
|
244 //the clicked item is really a node |
|
245 if(active_node!=INVALID) |
|
246 { |
|
247 *(nodesmap[active_node]) << Gnome::Canvas::Properties::fill_color("red"); |
|
248 isbutton=1; |
|
249 } |
|
250 //clicked item was not a node. It could be e.g. edge. |
|
251 else |
|
252 { |
|
253 active_item=NULL; |
|
254 } |
|
255 } |
|
256 //we only have to do sg. if the mouse button |
|
257 // is pressed already once AND the click was |
|
258 // on a node that was found in the set of |
|
259 //nodes, and now we only search for the second |
|
260 //node |
|
261 else |
|
262 { |
|
263 target_item=(get_item_at(e->button.x, e->button.y)); |
|
264 Graph::NodeIt target_node=INVALID; |
|
265 for (NodeIt i(g); i!=INVALID; ++i) |
|
266 { |
|
267 if(nodesmap[i]==target_item) |
|
268 { |
|
269 target_node=i; |
|
270 } |
|
271 } |
|
272 //the clicked item is a node, the edge can be drawn |
|
273 if(target_node!=INVALID) |
|
274 { |
|
275 *(nodesmap[target_node]) << Gnome::Canvas::Properties::fill_color("red"); |
|
276 |
|
277 //creating new edge |
|
278 active_edge=EdgeIt(g,g.addEdge(active_node, target_node)); |
|
279 |
|
280 //initiating values corresponding to new edge in maps |
|
281 mapstorage.init_maps_for_edge(active_edge); |
|
282 |
|
283 //calculating coordinates of new edge |
|
284 Gnome::Canvas::Points coos; |
|
285 double x1, x2, y1, y2; |
|
286 |
|
287 active_item->get_bounds(x1, y1, x2, y2); |
|
288 coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2)); |
|
289 |
|
290 target_item->get_bounds(x1, y1, x2, y2); |
|
291 coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2)); |
|
292 |
|
293 //drawing new edge |
|
294 edgesmap[active_edge]=new BrokenEdge(displayed_graph, coos, *this); |
|
295 *(edgesmap[active_edge]) << Gnome::Canvas::Properties::fill_color("green"); |
|
296 edgesmap[active_edge]->property_width_pixels().set_value(10); |
|
297 |
|
298 //redraw nodes to blank terminations of the new edge |
|
299 target_item->raise_to_top(); |
|
300 active_item->raise_to_top(); |
|
301 |
|
302 //initializing edge-text as well, to empty string |
|
303 xy<double> text_pos=edgesmap[active_edge]->get_arrow_pos(); |
|
304 text_pos+=(xy<double>(10,10)); |
|
305 |
|
306 edgetextmap[active_edge]=new Gnome::Canvas::Text(displayed_graph, text_pos.x, text_pos.y, ""); |
|
307 edgetextmap[active_edge]->property_fill_color().set_value("black"); |
|
308 } |
|
309 //clicked item was not a node. it could be an e.g. edge. we do not deal with it furthermore. |
|
310 else |
|
311 { |
|
312 target_item=NULL; |
|
313 } |
|
314 } |
|
315 } |
|
316 break; |
|
317 case GDK_BUTTON_RELEASE: |
|
318 isbutton=0; |
|
319 //we clear settings in two cases |
|
320 //1: the edge is ready (target_item has valid value) |
|
321 //2: the edge creation is cancelled with right button |
|
322 if((target_item)||(e->button.button==3)) |
|
323 { |
|
324 if(active_item) |
|
325 { |
|
326 *active_item << Gnome::Canvas::Properties::fill_color("blue"); |
|
327 active_item=NULL; |
|
328 } |
|
329 if(target_item) |
|
330 { |
|
331 *target_item << Gnome::Canvas::Properties::fill_color("blue"); |
|
332 target_item=NULL; |
|
333 } |
|
334 active_node=INVALID; |
|
335 active_edge=INVALID; |
|
336 } |
|
337 break; |
|
338 default: |
|
339 break; |
|
340 } |
|
341 return false; |
|
342 } |
|
343 |
|
344 bool GraphDisplayerCanvas::eraser_event_handler(GdkEvent* e) |
|
345 { |
|
346 switch(e->type) |
|
347 { |
|
348 case GDK_BUTTON_PRESS: |
|
349 active_item=(get_item_at(e->button.x, e->button.y)); |
|
350 active_node=INVALID; |
|
351 active_edge=INVALID; |
|
352 for (NodeIt i(g); i!=INVALID; ++i) |
|
353 { |
|
354 if(nodesmap[i]==active_item) |
|
355 { |
|
356 active_node=i; |
|
357 } |
|
358 } |
|
359 if(active_node==INVALID) |
|
360 { |
|
361 for (EdgeIt i(g); i!=INVALID; ++i) |
|
362 { |
|
363 if(edgesmap[i]==active_item) |
|
364 { |
|
365 active_edge=i; |
|
366 } |
|
367 } |
|
368 } |
|
369 *active_item << Gnome::Canvas::Properties::fill_color("red"); |
|
370 break; |
|
371 |
|
372 case GDK_BUTTON_RELEASE: |
|
373 if(active_item==(get_item_at(e->button.x, e->button.y))) |
|
374 { |
|
375 if(active_node!=INVALID) |
|
376 { |
|
377 |
|
378 //collecting edges to delete |
|
379 EdgeIt e; |
|
380 std::set<Graph::Edge> edges_to_delete; |
|
381 |
|
382 g.firstOut(e,active_node); |
|
383 for(;e!=INVALID;g.nextOut(e)) |
|
384 { |
|
385 edges_to_delete.insert(e); |
|
386 } |
|
387 |
|
388 g.firstIn(e,active_node); |
|
389 for(;e!=INVALID;g.nextIn(e)) |
|
390 { |
|
391 edges_to_delete.insert(e); |
|
392 } |
|
393 |
|
394 //deleting collected edges |
|
395 for(std::set<Graph::Edge>::iterator edge_set_it=edges_to_delete.begin();edge_set_it!=edges_to_delete.end();edge_set_it++) |
|
396 { |
|
397 delete_item(*edge_set_it); |
|
398 } |
|
399 delete_item(active_node); |
|
400 } |
|
401 //a simple edge was chosen |
|
402 else |
|
403 { |
|
404 delete_item(active_edge); |
|
405 } |
|
406 |
|
407 |
|
408 } |
|
409 //pointer was moved, deletion is cancelled |
|
410 else |
|
411 { |
|
412 if(active_node!=INVALID) |
|
413 { |
|
414 *active_item << Gnome::Canvas::Properties::fill_color("blue"); |
|
415 } |
|
416 else |
|
417 { |
|
418 *active_item << Gnome::Canvas::Properties::fill_color("green"); |
|
419 } |
|
420 } |
|
421 //reseting datas |
|
422 active_item=NULL; |
|
423 active_edge=INVALID; |
|
424 active_node=INVALID; |
|
425 break; |
|
426 |
|
427 case GDK_MOTION_NOTIFY: |
|
428 break; |
|
429 |
|
430 default: |
|
431 break; |
|
432 } |
|
433 return true; |
|
434 } |
|
435 |
|
436 void GraphDisplayerCanvas::delete_item(NodeIt node_to_delete) |
|
437 { |
|
438 delete(nodesmap[node_to_delete]); |
|
439 g.erase(node_to_delete); |
|
440 } |
|
441 |
|
442 void GraphDisplayerCanvas::delete_item(EdgeIt edge_to_delete) |
|
443 { |
|
444 delete(edgesmap[edge_to_delete]); |
|
445 g.erase(edge_to_delete); |
|
446 } |
|
447 |
|
448 void GraphDisplayerCanvas::delete_item(Graph::Edge edge_to_delete) |
|
449 { |
|
450 delete(edgesmap[edge_to_delete]); |
|
451 g.erase(edge_to_delete); |
|
452 } |
|
453 |
|
454 void GraphDisplayerCanvas::text_reposition(xy<double> new_place) |
|
455 { |
|
456 new_place+=(xy<double>(10,10)); |
|
457 edgetextmap[active_edge]->property_x().set_value(new_place.x); |
|
458 edgetextmap[active_edge]->property_y().set_value(new_place.y); |
|
459 } |
|
460 |
|
461 void GraphDisplayerCanvas::toggle_edge_activity(BrokenEdge* active_bre, bool on) |
|
462 { |
|
463 if(on) |
|
464 { |
|
465 if(active_edge!=INVALID) |
|
466 { |
|
467 std::cout << "ERROR!!!! Valid edge found!" << std::endl; |
|
468 } |
|
469 else |
|
470 { |
|
471 for (EdgeIt i(g); i!=INVALID; ++i) |
|
472 { |
|
473 if(edgesmap[i]==active_bre) |
|
474 { |
|
475 active_edge=i; |
|
476 } |
|
477 } |
|
478 } |
|
479 } |
|
480 else |
|
481 { |
|
482 if(active_edge!=INVALID) |
|
483 { |
|
484 active_edge=INVALID; |
|
485 } |
|
486 else |
|
487 { |
|
488 std::cout << "ERROR!!!! Invalid edge found!" << std::endl; |
|
489 } |
|
490 } |
|
491 |
|
492 } |