COIN-OR::LEMON - Graph Library

source: glemon-0.x/graph_displayer_canvas-event.cc @ 31:66e85f44a66f

gui
Last change on this file since 31:66e85f44a66f was 31:66e85f44a66f, checked in by Hegyi Péter, 15 years ago

Uh, long comment arrives... Zoom update does not happen after editorial steps. Nodes initial color is light blue, if there is any item under them. Strange node-text relations disappeared. Initial values of new items are given now in a more common way. The wood-cutter way of handling default values of properties is now changed.

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