COIN-OR::LEMON - Graph Library

source: lemon-0.x/gui/graph_displayer_canvas-event.cc @ 1512:e54392395480

Last change on this file since 1512:e54392395480 was 1512:e54392395480, checked in by Hegyi Péter, 15 years ago

NodeMap? values are now visualizable. Todo: default map-values

  • Property exe set to *
File size: 13.0 KB
Line 
1#include <graph_displayer_canvas.h>
2#include <broken_edge.h>
3#include <math.h>
4
5
6bool 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
14void 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
52int GraphDisplayerCanvas::get_actual_tool()
53{
54  return actual_tool;
55}
56
57bool 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        //repositioning node and its text
103        active_item->move(dx, dy);
104        nodetextmap[active_node]->move(dx, dy);
105
106        clicked_x=e->motion.x;
107        clicked_y=e->motion.y;
108
109        //all the edges connected to the moved point has to be redrawn
110        EdgeIt ei;
111
112        g.firstOut(ei,active_node);
113
114        for(;ei!=INVALID;g.nextOut(ei))
115        {
116            Gnome::Canvas::Points coos;
117            double x1, x2, y1, y2;
118
119            nodesmap[g.source(ei)]->get_bounds(x1, y1, x2, y2);
120            coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
121
122            nodesmap[g.target(ei)]->get_bounds(x1, y1, x2, y2);
123            coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
124
125            if(isbutton==3)
126              {
127                edgesmap[ei]->set_points(coos);
128              }
129            else
130              {
131                edgesmap[ei]->set_points(coos,true);
132              }
133
134            //reposition of edgetext
135            xy<double> text_pos=edgesmap[ei]->get_arrow_pos();
136            text_pos+=(xy<double>(10,10));
137            edgetextmap[ei]->property_x().set_value(text_pos.x);
138            edgetextmap[ei]->property_y().set_value(text_pos.y);
139        }
140
141        g.firstIn(ei,active_node);
142        for(;ei!=INVALID;g.nextIn(ei))
143        {
144            Gnome::Canvas::Points coos;
145            double x1, x2, y1, y2;
146
147            nodesmap[g.source(ei)]->get_bounds(x1, y1, x2, y2);
148            coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
149
150            nodesmap[g.target(ei)]->get_bounds(x1, y1, x2, y2);
151            coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
152
153            if(isbutton==3)
154              {
155                edgesmap[ei]->set_points(coos);
156              }
157            else
158              {
159                edgesmap[ei]->set_points(coos,true);
160              }
161
162            xy<double> text_pos=edgesmap[ei]->get_arrow_pos();
163            text_pos+=(xy<double>(10,10));
164            edgetextmap[ei]->property_x().set_value(text_pos.x);
165            edgetextmap[ei]->property_y().set_value(text_pos.y);
166        }
167      }
168    default: break;
169  }
170
171  return true;
172}
173
174bool GraphDisplayerCanvas::create_node_event_handler(GdkEvent* e)
175{
176  switch(e->type)
177    {
178
179      //draw the new node in red at the clicked place
180    case GDK_BUTTON_PRESS:
181      isbutton=1;
182
183      active_node=NodeIt(g,g.addNode());
184
185      //initiating values corresponding to new node in maps
186     
187
188      window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
189
190      nodesmap[active_node]=new Gnome::Canvas::Ellipse(displayed_graph, clicked_x-20, clicked_y-20, clicked_x+20, clicked_y+20);
191      active_item=(Gnome::Canvas::Item *)(nodesmap[active_node]);
192      *(nodesmap[active_node]) << Gnome::Canvas::Properties::fill_color("red");
193      *(nodesmap[active_node]) << Gnome::Canvas::Properties::outline_color("black");
194      (nodesmap[active_node])->show();
195
196      nodetextmap[active_node]=new Gnome::Canvas::Text(displayed_graph, clicked_x+node_property_defaults[N_RADIUS]+5, clicked_y+node_property_defaults[N_RADIUS]+5, "");
197      nodetextmap[active_node]->property_fill_color().set_value("darkblue");
198
199      mapwin->update_node(active_node);
200
201      break;
202
203      //move the new node
204    case GDK_MOTION_NOTIFY:
205      {
206        double world_motion_x, world_motion_y;
207        GdkEvent * generated=new GdkEvent();
208        window_to_world (e->motion.x, e->motion.y, world_motion_x, world_motion_y);
209        generated->motion.x=world_motion_x;
210        generated->motion.y=world_motion_y;
211        generated->type=GDK_MOTION_NOTIFY;
212        move_event_handler(generated);     
213        break;
214      }
215
216      //finalize the new node
217    case GDK_BUTTON_RELEASE:
218      isbutton=0;
219      *active_item << Gnome::Canvas::Properties::fill_color("blue");
220      active_item=NULL;
221      active_node=INVALID;
222      updateScrollRegion();
223      break;
224    default:
225      break;
226    }
227  return false;
228}
229
230bool GraphDisplayerCanvas::create_edge_event_handler(GdkEvent* e)
231{
232  switch(e->type)
233    {
234    case GDK_BUTTON_PRESS:
235      //in edge creation right button has special meaning
236      if(e->button.button!=3)
237        {
238          //there is not yet selected node
239          if(active_node==INVALID)
240            {
241              //we mark the location of the event to be able to calculate parameters of dragging
242              clicked_x=e->button.x;
243              clicked_y=e->button.y;
244              active_item=(get_item_at(e->button.x, e->button.y));
245              active_node=INVALID;
246              for (NodeIt i(g); i!=INVALID; ++i)
247                {
248                  if(nodesmap[i]==active_item)
249                    {
250                      active_node=i;
251                    }
252                }
253              //the clicked item is really a node
254              if(active_node!=INVALID)
255                {
256                  *(nodesmap[active_node]) << Gnome::Canvas::Properties::fill_color("red");
257                  isbutton=1;
258                }
259              //clicked item was not a node. It could be e.g. edge.
260              else
261                {
262                  active_item=NULL;
263                }
264            }
265          //we only have to do sg. if the mouse button
266          // is pressed already once AND the click was
267          // on a node that was found in the set of
268          //nodes, and now we only search for the second
269          //node
270          else
271            {
272              target_item=(get_item_at(e->button.x, e->button.y));
273              Graph::NodeIt target_node=INVALID;
274              for (NodeIt i(g); i!=INVALID; ++i)
275                {
276                  if(nodesmap[i]==target_item)
277                    {
278                      target_node=i;
279                    }
280                }
281              //the clicked item is a node, the edge can be drawn
282              if(target_node!=INVALID)
283                {
284                  if(target_node!=active_node)         
285                    {
286                      *(nodesmap[target_node]) << Gnome::Canvas::Properties::fill_color("red");
287
288                      //creating new edge
289                      active_edge=EdgeIt(g,g.addEdge(active_node, target_node));
290
291                      //initiating values corresponding to new edge in maps
292                      mapstorage.init_maps_for_edge(active_edge);
293         
294                      //calculating coordinates of new edge
295                      Gnome::Canvas::Points coos;
296                      double x1, x2, y1, y2;
297         
298                      active_item->get_bounds(x1, y1, x2, y2);
299                      coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
300
301                      target_item->get_bounds(x1, y1, x2, y2);
302                      coos.push_back(Gnome::Art::Point((x1+x2)/2,(y1+y2)/2));
303
304                      //drawing new edge
305                      edgesmap[active_edge]=new BrokenEdge(displayed_graph, coos, *this);
306                      *(edgesmap[active_edge]) << Gnome::Canvas::Properties::fill_color("green");
307                      edgesmap[active_edge]->property_width_pixels().set_value(10);
308
309                      //redraw nodes to blank terminations of the new edge
310                      target_item->raise_to_top();
311                      active_item->raise_to_top();
312
313                      //initializing edge-text as well, to empty string
314                      xy<double> text_pos=edgesmap[active_edge]->get_arrow_pos();
315                      text_pos+=(xy<double>(10,10));
316
317                      edgetextmap[active_edge]=new Gnome::Canvas::Text(displayed_graph, text_pos.x, text_pos.y, "");
318                      edgetextmap[active_edge]->property_fill_color().set_value("darkgreen");
319
320                      //updating its properties
321                      mapwin->update_edge(active_edge);
322                    }
323                  else
324                    {
325                      target_node=INVALID;
326                      std::cout << "Loop edge is not yet implemented!" << std::endl;
327                    }
328                }
329              //clicked item was not a node. it could be an e.g. edge. we do not deal with it furthermore.
330              else
331                {
332                  target_item=NULL;
333                }
334            }
335        }
336      break;
337    case GDK_BUTTON_RELEASE:
338      isbutton=0;
339      //we clear settings in two cases
340      //1: the edge is ready (target_item has valid value)
341      //2: the edge creation is cancelled with right button
342      if((target_item)||(e->button.button==3))
343        {
344          if(active_item)
345            {
346              *active_item << Gnome::Canvas::Properties::fill_color("blue");
347              active_item=NULL;
348            }
349          if(target_item)
350            {
351              *target_item << Gnome::Canvas::Properties::fill_color("blue");
352              target_item=NULL;
353            }
354          active_node=INVALID;
355          active_edge=INVALID;
356        }
357      break;
358    default:
359      break;
360    }
361  return false;
362}
363
364bool GraphDisplayerCanvas::eraser_event_handler(GdkEvent* e)
365{
366  switch(e->type)
367    {
368    case GDK_BUTTON_PRESS:
369      active_item=(get_item_at(e->button.x, e->button.y));
370      active_node=INVALID;
371      active_edge=INVALID;
372      for (NodeIt i(g); i!=INVALID; ++i)
373        {
374          if(nodesmap[i]==active_item)
375            {
376              active_node=i;
377            }
378        }
379      if(active_node==INVALID)
380        {
381          for (EdgeIt i(g); i!=INVALID; ++i)
382            {
383              if(edgesmap[i]==active_item)
384                {
385                  active_edge=i;
386                }
387            }
388        }
389    *active_item << Gnome::Canvas::Properties::fill_color("red");
390      break;
391
392    case GDK_BUTTON_RELEASE:
393      if(active_item==(get_item_at(e->button.x, e->button.y)))
394        {
395          if(active_node!=INVALID)
396            {
397
398              //collecting edges to delete
399              EdgeIt e;
400              std::set<Graph::Edge> edges_to_delete;
401
402              g.firstOut(e,active_node);
403              for(;e!=INVALID;g.nextOut(e))
404                {
405                      edges_to_delete.insert(e);
406                }
407
408              g.firstIn(e,active_node);
409              for(;e!=INVALID;g.nextIn(e))
410                {
411                      edges_to_delete.insert(e);
412                }
413
414              //deleting collected edges
415              for(std::set<Graph::Edge>::iterator edge_set_it=edges_to_delete.begin();edge_set_it!=edges_to_delete.end();edge_set_it++)
416                {
417                  delete_item(*edge_set_it);
418                }
419              delete_item(active_node);
420            }
421          //a simple edge was chosen
422          else
423            {
424              delete_item(active_edge);
425            }
426
427         
428        }
429      //pointer was moved, deletion is cancelled
430      else
431        {
432          if(active_node!=INVALID)
433            {
434              *active_item << Gnome::Canvas::Properties::fill_color("blue");
435            }
436          else
437            {
438              *active_item << Gnome::Canvas::Properties::fill_color("green");
439            }
440        }
441      //reseting datas
442      active_item=NULL;
443      active_edge=INVALID;
444      active_node=INVALID;
445      break;
446
447    case GDK_MOTION_NOTIFY:
448      break;
449
450    default:
451      break;
452    }
453  return true;
454}
455
456void GraphDisplayerCanvas::delete_item(NodeIt node_to_delete)
457{
458  delete(nodetextmap[node_to_delete]);
459  delete(nodesmap[node_to_delete]);
460  g.erase(node_to_delete);
461}
462
463void GraphDisplayerCanvas::delete_item(EdgeIt edge_to_delete)
464{
465  delete(edgetextmap[edge_to_delete]);
466  delete(edgesmap[edge_to_delete]);
467  g.erase(edge_to_delete);
468}
469
470void GraphDisplayerCanvas::delete_item(Graph::Edge edge_to_delete)
471{
472  delete(edgetextmap[edge_to_delete]);
473  delete(edgesmap[edge_to_delete]);
474  g.erase(edge_to_delete);
475}
476
477void GraphDisplayerCanvas::text_reposition(xy<double> new_place)
478{
479  new_place+=(xy<double>(10,10));
480  edgetextmap[active_edge]->property_x().set_value(new_place.x);
481  edgetextmap[active_edge]->property_y().set_value(new_place.y);
482}
483
484void GraphDisplayerCanvas::toggle_edge_activity(BrokenEdge* active_bre, bool on)
485{
486  if(on)
487    {
488      if(active_edge!=INVALID)
489        {
490          std::cout << "ERROR!!!! Valid edge found!" << std::endl;
491        }
492      else
493        {
494          for (EdgeIt i(g); i!=INVALID; ++i)
495            {
496              if(edgesmap[i]==active_bre)
497                {
498                  active_edge=i;
499                }
500            }
501        }
502    }
503  else
504    {
505      if(active_edge!=INVALID)
506        {
507          active_edge=INVALID;
508        }
509      else
510        {
511          std::cout << "ERROR!!!! Invalid edge found!" << std::endl;
512        }
513    }
514
515}
Note: See TracBrowser for help on using the repository browser.