graph_displayer_canvas-event.cc
author hegyi
Thu, 12 Oct 2006 11:39:29 +0000
changeset 160 14a76109b561
parent 153 d79a71382836
child 174 95872af46fc4
permissions -rwxr-xr-x
Node antigravity and edge elasticity based graph layout redesigner.
ladanyi@53
     1
#include "graph_displayer_canvas.h"
alpar@59
     2
#include <cmath>
hegyi@27
     3
hegyi@27
     4
hegyi@27
     5
bool GraphDisplayerCanvas::on_expose_event(GdkEventExpose *event)
hegyi@27
     6
{
hegyi@27
     7
  Gnome::Canvas::CanvasAA::on_expose_event(event);
hegyi@27
     8
  //usleep(10000);
hegyi@27
     9
  //rezoom();
hegyi@27
    10
  return true;
hegyi@27
    11
}
hegyi@27
    12
hegyi@27
    13
void GraphDisplayerCanvas::changeEditorialTool(int newtool)
hegyi@27
    14
{
hegyi@34
    15
  if(actual_tool!=newtool)
hegyi@34
    16
    {
hegyi@27
    17
hegyi@34
    18
      actual_handler.disconnect();
hegyi@27
    19
hegyi@34
    20
      switch(actual_tool)
hegyi@34
    21
	{
hegyi@34
    22
	case CREATE_EDGE:
hegyi@34
    23
	  {
hegyi@34
    24
	    GdkEvent * generated=new GdkEvent();
hegyi@34
    25
	    generated->type=GDK_BUTTON_RELEASE;
hegyi@34
    26
	    generated->button.button=3;
hegyi@34
    27
	    createEdgeEventHandler(generated);      
hegyi@34
    28
	    break;
hegyi@34
    29
	  }
hegyi@149
    30
	case MAP_EDIT:
hegyi@35
    31
	  {
hegyi@35
    32
	    break;
hegyi@35
    33
	  }
hegyi@34
    34
	default:
hegyi@34
    35
	  break;
hegyi@34
    36
	}
hegyi@27
    37
hegyi@34
    38
      active_item=NULL; 
hegyi@34
    39
      target_item=NULL; 
hegyi@34
    40
      active_edge=INVALID;	
hegyi@34
    41
      active_node=INVALID;	
hegyi@33
    42
hegyi@27
    43
hegyi@34
    44
      actual_tool=newtool;
hegyi@34
    45
  
hegyi@34
    46
      switch(newtool)
hegyi@34
    47
	{
hegyi@34
    48
	case MOVE:
hegyi@34
    49
	  actual_handler=signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::moveEventHandler), false);
hegyi@34
    50
	  break;
hegyi@27
    51
hegyi@34
    52
	case CREATE_NODE:
hegyi@34
    53
	  actual_handler=signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::createNodeEventHandler), false);
hegyi@34
    54
	  break;
hegyi@27
    55
hegyi@34
    56
	case CREATE_EDGE:
hegyi@34
    57
	  actual_handler=signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::createEdgeEventHandler), false);
hegyi@34
    58
	  break;
hegyi@27
    59
hegyi@34
    60
	case ERASER:
hegyi@34
    61
	  actual_handler=signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::eraserEventHandler), false);
hegyi@34
    62
	  break;
hegyi@32
    63
hegyi@149
    64
	case MAP_EDIT:
hegyi@34
    65
	  grab_focus();
hegyi@149
    66
	  actual_handler=signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::mapEditEventHandler), false);
hegyi@34
    67
	  break;
hegyi@34
    68
hegyi@34
    69
	default:
hegyi@34
    70
	  break;
hegyi@34
    71
	}
hegyi@27
    72
    }
hegyi@27
    73
}
hegyi@27
    74
hegyi@30
    75
int GraphDisplayerCanvas::getActualTool()
hegyi@27
    76
{
hegyi@27
    77
  return actual_tool;
hegyi@27
    78
}
hegyi@27
    79
hegyi@30
    80
bool GraphDisplayerCanvas::moveEventHandler(GdkEvent* e)
hegyi@27
    81
{
ladanyi@70
    82
  static Gnome::Canvas::Text *coord_text = 0;
hegyi@27
    83
  switch(e->type)
hegyi@160
    84
    {
hegyi@27
    85
    case GDK_BUTTON_PRESS:
hegyi@27
    86
      //we mark the location of the event to be able to calculate parameters of dragging
hegyi@31
    87
      window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
hegyi@160
    88
      
hegyi@31
    89
      active_item=(get_item_at(clicked_x, clicked_y));
hegyi@27
    90
      active_node=INVALID;
hegyi@96
    91
      for (NodeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
hegyi@27
    92
	{
hegyi@27
    93
	  if(nodesmap[i]==active_item)
hegyi@27
    94
	    {
hegyi@27
    95
	      active_node=i;
hegyi@27
    96
	    }
hegyi@27
    97
	}
hegyi@148
    98
      isbutton=e->button.button;
hegyi@27
    99
      break;
hegyi@27
   100
    case GDK_BUTTON_RELEASE:
ladanyi@70
   101
      if (coord_text)
hegyi@160
   102
	{
hegyi@160
   103
	  delete coord_text;
hegyi@160
   104
	  coord_text = 0;
hegyi@160
   105
	}
hegyi@27
   106
      isbutton=0;
hegyi@27
   107
      active_item=NULL;
hegyi@27
   108
      active_node=INVALID;
hegyi@27
   109
      break;
hegyi@27
   110
    case GDK_MOTION_NOTIFY:
hegyi@27
   111
      //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
hegyi@27
   112
      if(active_node!=INVALID)
hegyi@160
   113
	{
hegyi@160
   114
	  (mytab.mapstorage).modified = true;
hegyi@160
   115
	  
hegyi@160
   116
	  //new coordinates will be the old values,
hegyi@160
   117
	  //because the item will be moved to the
hegyi@160
   118
	  //new coordinate therefore the new movement
hegyi@160
   119
	  //has to be calculated from here
hegyi@160
   120
	  
hegyi@160
   121
	  double new_x, new_y;
hegyi@160
   122
	  
hegyi@160
   123
	  window_to_world (e->motion.x, e->motion.y, new_x, new_y);
hegyi@160
   124
	  
hegyi@160
   125
	  double dx=new_x-clicked_x;
hegyi@160
   126
	  double dy=new_y-clicked_y;
hegyi@160
   127
	  
hegyi@160
   128
	  moveNode(dx, dy);
ladanyi@70
   129
hegyi@160
   130
	  clicked_x=new_x;
hegyi@160
   131
	  clicked_y=new_y;
hegyi@27
   132
hegyi@160
   133
	  // reposition the coordinates text
hegyi@160
   134
	  std::ostringstream ostr;
hegyi@160
   135
	  ostr << "(" <<
hegyi@160
   136
	    (mytab.mapstorage).coords[active_node].x << ", " <<
hegyi@160
   137
	    (mytab.mapstorage).coords[active_node].y << ")";
hegyi@160
   138
	  double radius =
hegyi@160
   139
	    (nodesmap[active_node]->property_x2().get_value() -
hegyi@160
   140
	     nodesmap[active_node]->property_x1().get_value()) / 2.0;
hegyi@160
   141
	  if (coord_text)
hegyi@160
   142
	    {
hegyi@160
   143
	      coord_text->property_text().set_value(ostr.str());
hegyi@160
   144
	      coord_text->property_x().set_value((mytab.mapstorage).coords[active_node].x +
hegyi@160
   145
						 radius);
hegyi@160
   146
	      coord_text->property_y().set_value((mytab.mapstorage).coords[active_node].y -
hegyi@160
   147
						 radius);
hegyi@160
   148
	    }
hegyi@160
   149
	  else
hegyi@160
   150
	    {
hegyi@160
   151
	      coord_text = new Gnome::Canvas::Text(
hegyi@160
   152
						   displayed_graph,
hegyi@160
   153
						   (mytab.mapstorage).coords[active_node].x + radius,
hegyi@160
   154
						   (mytab.mapstorage).coords[active_node].y - radius,
hegyi@160
   155
						   ostr.str());
hegyi@160
   156
	      coord_text->property_fill_color().set_value("black");
hegyi@160
   157
	      coord_text->property_anchor().set_value(Gtk::ANCHOR_SOUTH_WEST);
hegyi@160
   158
	    }
hegyi@31
   159
hegyi@31
   160
hegyi@160
   161
	}
hegyi@160
   162
    default: break;
hegyi@160
   163
    }
hegyi@27
   164
hegyi@160
   165
return false;
hegyi@27
   166
}
hegyi@27
   167
hegyi@148
   168
XY GraphDisplayerCanvas::calcArrowPos(XY moved_node_1, XY moved_node_2, XY fix_node, XY old_arrow_pos, int move_code)
ladanyi@98
   169
{
hegyi@148
   170
  switch(move_code)
hegyi@148
   171
    {
hegyi@148
   172
    case 1:
hegyi@148
   173
      return XY((moved_node_2.x + fix_node.x) / 2.0, (moved_node_2.y + fix_node.y) / 2.0);
hegyi@148
   174
      break;
hegyi@148
   175
    case 2:
hegyi@148
   176
      return old_arrow_pos;
hegyi@148
   177
      break;
hegyi@148
   178
    case 3:
hegyi@148
   179
      {
hegyi@148
   180
	//////////////////////////////////////////////////////////////////////////////////////////////////////
hegyi@148
   181
	/////////// keeps shape-with scalar multiplication - version 2.
hegyi@148
   182
	//////////////////////////////////////////////////////////////////////////////////////////////////////
ladanyi@98
   183
hegyi@148
   184
	//old vector from one to the other node - a
hegyi@150
   185
	XY a_v(moved_node_1.x-fix_node.x,moved_node_1.y-fix_node.y);
hegyi@148
   186
	//new vector from one to the other node - b
hegyi@150
   187
	XY b_v(moved_node_2.x-fix_node.x,moved_node_2.y-fix_node.y);
ladanyi@98
   188
hegyi@148
   189
	double absa=sqrt(a_v.normSquare());
hegyi@148
   190
	double absb=sqrt(b_v.normSquare());
ladanyi@98
   191
hegyi@148
   192
	if ((absa == 0.0) || (absb == 0.0))
hegyi@148
   193
	  {
hegyi@148
   194
	    return old_arrow_pos;
hegyi@148
   195
	  }
hegyi@148
   196
	else
hegyi@148
   197
	  {
hegyi@148
   198
	    //old vector from one node to the breakpoint - c
hegyi@150
   199
	    XY c_v(old_arrow_pos.x-fix_node.x,old_arrow_pos.y-fix_node.y);
hegyi@148
   200
hegyi@148
   201
	    //unit vector with the same direction to a_v
hegyi@150
   202
	    XY a_v_u(a_v.x/absa,a_v.y/absa);
hegyi@148
   203
hegyi@148
   204
	    //normal vector of unit vector with the same direction to a_v
hegyi@150
   205
	    XY a_v_u_n(((-1)*a_v_u.y),a_v_u.x);
hegyi@148
   206
hegyi@148
   207
	    //unit vector with the same direction to b_v
hegyi@150
   208
	    XY b_v_u(b_v.x/absb,b_v.y/absb);
hegyi@148
   209
hegyi@148
   210
	    //normal vector of unit vector with the same direction to b_v
hegyi@150
   211
	    XY b_v_u_n(((-1)*b_v_u.y),b_v_u.x);
hegyi@148
   212
hegyi@148
   213
	    //vector c in a_v_u and a_v_u_n co-ordinate system
hegyi@150
   214
	    XY c_a(c_v*a_v_u,c_v*a_v_u_n);
hegyi@148
   215
hegyi@148
   216
	    //new vector from one node to the breakpoint - d - we have to calculate this one
hegyi@150
   217
	    XY d_v=absb/absa*(c_a.x*b_v_u+c_a.y*b_v_u_n);
hegyi@148
   218
hegyi@148
   219
	    return XY(d_v.x+fix_node.x,d_v.y+fix_node.y);
hegyi@148
   220
	  }
hegyi@148
   221
	break;
hegyi@148
   222
      }
hegyi@148
   223
    default:
hegyi@148
   224
      break;
ladanyi@98
   225
    }
hegyi@148
   226
}
ladanyi@98
   227
ladanyi@98
   228
hegyi@30
   229
bool GraphDisplayerCanvas::createNodeEventHandler(GdkEvent* e)
hegyi@27
   230
{
hegyi@27
   231
  switch(e->type)
ladanyi@63
   232
  {
ladanyi@63
   233
    //move the new node
ladanyi@63
   234
    case GDK_MOTION_NOTIFY:
ladanyi@63
   235
      {
ladanyi@63
   236
        GdkEvent * generated=new GdkEvent();
ladanyi@63
   237
        generated->motion.x=e->motion.x;
ladanyi@63
   238
        generated->motion.y=e->motion.y;
ladanyi@63
   239
        generated->type=GDK_MOTION_NOTIFY;
ladanyi@63
   240
        moveEventHandler(generated);      
ladanyi@63
   241
        break;
ladanyi@63
   242
      }
hegyi@27
   243
ladanyi@63
   244
    case GDK_BUTTON_RELEASE:
hegyi@96
   245
      (mytab.mapstorage).modified = true;
ladanyi@53
   246
hegyi@27
   247
      isbutton=1;
hegyi@27
   248
hegyi@96
   249
      active_node=(mytab.mapstorage).graph.addNode();
hegyi@27
   250
hegyi@27
   251
      //initiating values corresponding to new node in maps
hegyi@27
   252
hegyi@27
   253
      window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
hegyi@27
   254
ladanyi@63
   255
      // update coordinates
hegyi@150
   256
      (mytab.mapstorage).coords.set(active_node, XY(clicked_x, clicked_y));
ladanyi@63
   257
ladanyi@63
   258
      // update all other maps
ladanyi@63
   259
      for (std::map<std::string, Graph::NodeMap<double>*>::const_iterator it =
hegyi@96
   260
          (mytab.mapstorage).nodemap_storage.begin(); it !=
hegyi@96
   261
          (mytab.mapstorage).nodemap_storage.end(); ++it)
ladanyi@63
   262
      {
ladanyi@64
   263
        if ((it->first != "coordinates_x") &&
ladanyi@64
   264
            (it->first != "coordinates_y"))
ladanyi@63
   265
        {
ladanyi@63
   266
          (*(it->second))[active_node] =
hegyi@96
   267
            (mytab.mapstorage).nodemap_default[it->first];
ladanyi@63
   268
        }
ladanyi@63
   269
      }
ladanyi@64
   270
      // increment the id map's default value
ladanyi@134
   271
      (mytab.mapstorage).nodemap_default["label"] += 1.0;
ladanyi@63
   272
ladanyi@53
   273
      nodesmap[active_node]=new Gnome::Canvas::Ellipse(displayed_graph,
ladanyi@63
   274
          clicked_x-20, clicked_y-20, clicked_x+20, clicked_y+20);
hegyi@27
   275
      active_item=(Gnome::Canvas::Item *)(nodesmap[active_node]);
ladanyi@63
   276
      *(nodesmap[active_node]) <<
ladanyi@63
   277
        Gnome::Canvas::Properties::fill_color("blue");
ladanyi@63
   278
      *(nodesmap[active_node]) <<
ladanyi@63
   279
        Gnome::Canvas::Properties::outline_color("black");
ladanyi@63
   280
      active_item->raise_to_top();
ladanyi@63
   281
hegyi@27
   282
      (nodesmap[active_node])->show();
hegyi@28
   283
ladanyi@53
   284
      nodetextmap[active_node]=new Gnome::Canvas::Text(displayed_graph,
ladanyi@63
   285
          clicked_x+node_property_defaults[N_RADIUS]+5,
ladanyi@63
   286
          clicked_y+node_property_defaults[N_RADIUS]+5, "");
hegyi@28
   287
      nodetextmap[active_node]->property_fill_color().set_value("darkblue");
ladanyi@63
   288
      nodetextmap[active_node]->raise_to_top();
hegyi@28
   289
hegyi@94
   290
//       mapwin.updateNode(active_node);
hegyi@94
   291
      propertyUpdate(active_node);
hegyi@28
   292
hegyi@27
   293
      isbutton=0;
hegyi@31
   294
      target_item=NULL;
hegyi@27
   295
      active_item=NULL;
hegyi@27
   296
      active_node=INVALID;
hegyi@27
   297
      break;
hegyi@27
   298
    default:
hegyi@27
   299
      break;
ladanyi@63
   300
  }
hegyi@27
   301
  return false;
hegyi@27
   302
}
hegyi@27
   303
hegyi@30
   304
bool GraphDisplayerCanvas::createEdgeEventHandler(GdkEvent* e)
hegyi@27
   305
{
hegyi@27
   306
  switch(e->type)
ladanyi@63
   307
  {
hegyi@27
   308
    case GDK_BUTTON_PRESS:
hegyi@27
   309
      //in edge creation right button has special meaning
hegyi@27
   310
      if(e->button.button!=3)
ladanyi@63
   311
      {
ladanyi@63
   312
        //there is not yet selected node
ladanyi@63
   313
        if(active_node==INVALID)
ladanyi@63
   314
        {
ladanyi@63
   315
          //we mark the location of the event to be able to calculate parameters of dragging
hegyi@31
   316
ladanyi@63
   317
          window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
hegyi@31
   318
ladanyi@63
   319
          active_item=(get_item_at(clicked_x, clicked_y));
ladanyi@63
   320
          active_node=INVALID;
hegyi@96
   321
          for (NodeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
ladanyi@63
   322
          {
ladanyi@63
   323
            if(nodesmap[i]==active_item)
ladanyi@63
   324
            {
ladanyi@63
   325
              active_node=i;
ladanyi@63
   326
            }
ladanyi@63
   327
          }
ladanyi@63
   328
          //the clicked item is really a node
ladanyi@63
   329
          if(active_node!=INVALID)
ladanyi@63
   330
          {
ladanyi@63
   331
            *(nodesmap[active_node]) << Gnome::Canvas::Properties::fill_color("red");
ladanyi@63
   332
            isbutton=1;
ladanyi@63
   333
          }
ladanyi@63
   334
          //clicked item was not a node. It could be e.g. edge.
ladanyi@63
   335
          else
ladanyi@63
   336
          {
ladanyi@63
   337
            active_item=NULL;
ladanyi@63
   338
          }
ladanyi@63
   339
        }
ladanyi@63
   340
        //we only have to do sg. if the mouse button
ladanyi@63
   341
        // is pressed already once AND the click was
ladanyi@63
   342
        // on a node that was found in the set of 
ladanyi@63
   343
        //nodes, and now we only search for the second 
ladanyi@63
   344
        //node
ladanyi@63
   345
        else
ladanyi@63
   346
        {
ladanyi@63
   347
          window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
ladanyi@63
   348
          target_item=(get_item_at(clicked_x, clicked_y));
ladanyi@63
   349
          Node target_node=INVALID;
hegyi@96
   350
          for (NodeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
ladanyi@63
   351
          {
ladanyi@63
   352
            if(nodesmap[i]==target_item)
ladanyi@63
   353
            {
ladanyi@63
   354
              target_node=i;
ladanyi@63
   355
            }
ladanyi@63
   356
          }
ladanyi@63
   357
          //the clicked item is a node, the edge can be drawn
ladanyi@63
   358
          if(target_node!=INVALID)
ladanyi@63
   359
          {
ladanyi@151
   360
            (mytab.mapstorage).modified = true;
ladanyi@151
   361
ladanyi@151
   362
            *(nodesmap[target_node]) <<
ladanyi@151
   363
              Gnome::Canvas::Properties::fill_color("red");
ladanyi@151
   364
ladanyi@151
   365
            //creating new edge
ladanyi@151
   366
            active_edge=(mytab.mapstorage).graph.addEdge(active_node,
ladanyi@151
   367
                target_node);
ladanyi@151
   368
ladanyi@151
   369
            // update maps
ladanyi@151
   370
            for (std::map<std::string,
ladanyi@151
   371
                Graph::EdgeMap<double>*>::const_iterator it =
ladanyi@151
   372
                (mytab.mapstorage).edgemap_storage.begin(); it !=
ladanyi@151
   373
                (mytab.mapstorage).edgemap_storage.end(); ++it)
ladanyi@151
   374
            {
ladanyi@151
   375
              (*(it->second))[active_edge] =
ladanyi@151
   376
                (mytab.mapstorage).edgemap_default[it->first];
ladanyi@151
   377
            }
ladanyi@151
   378
            // increment the id map's default value
ladanyi@151
   379
            (mytab.mapstorage).edgemap_default["label"] += 1.0;
ladanyi@151
   380
ladanyi@63
   381
            if(target_node!=active_node)		
ladanyi@63
   382
            {
ladanyi@113
   383
              // set the coordinates of the arrow on the new edge
ladanyi@113
   384
              MapStorage& ms = mytab.mapstorage;
ladanyi@113
   385
              ms.arrow_pos.set(active_edge,
ladanyi@113
   386
                  (ms.coords[ms.graph.source(active_edge)] +
ladanyi@113
   387
                   ms.coords[ms.graph.target(active_edge)])/ 2.0);
ladanyi@113
   388
ladanyi@63
   389
              //drawing new edge
ladanyi@98
   390
              edgesmap[active_edge]=new BrokenEdge(displayed_graph, active_edge,
ladanyi@63
   391
                  *this);
ladanyi@63
   392
            }
ladanyi@63
   393
            else
ladanyi@63
   394
            {
ladanyi@151
   395
              // set the coordinates of the arrow on the new edge
ladanyi@151
   396
              MapStorage& ms = mytab.mapstorage;
ladanyi@151
   397
              ms.arrow_pos.set(active_edge,
ladanyi@151
   398
                  (ms.coords[ms.graph.source(active_edge)] +
ladanyi@151
   399
                   XY(0.0, 80.0)));
ladanyi@151
   400
ladanyi@151
   401
              //drawing new edge
ladanyi@151
   402
              edgesmap[active_edge]=new LoopEdge(displayed_graph, active_edge,
ladanyi@151
   403
                  *this);
ladanyi@63
   404
            }
ladanyi@151
   405
ladanyi@151
   406
            //initializing edge-text as well, to empty string
ladanyi@151
   407
            XY text_pos=mytab.mapstorage.arrow_pos[active_edge];
ladanyi@151
   408
            text_pos+=(XY(10,10));
ladanyi@151
   409
ladanyi@151
   410
            edgetextmap[active_edge]=new Gnome::Canvas::Text(displayed_graph,
ladanyi@151
   411
                text_pos.x, text_pos.y, "");
ladanyi@151
   412
            edgetextmap[active_edge]->property_fill_color().set_value(
ladanyi@151
   413
                "darkgreen");
ladanyi@151
   414
            edgetextmap[active_edge]->raise_to_top();
ladanyi@151
   415
ladanyi@151
   416
            propertyUpdate(active_edge);
ladanyi@63
   417
          }
ladanyi@63
   418
          //clicked item was not a node. it could be an e.g. edge. we do not
ladanyi@63
   419
          //deal with it furthermore.
ladanyi@63
   420
          else
ladanyi@63
   421
          {
ladanyi@63
   422
            target_item=NULL;
ladanyi@63
   423
          }
ladanyi@63
   424
        }
ladanyi@63
   425
      }
hegyi@27
   426
      break;
hegyi@27
   427
    case GDK_BUTTON_RELEASE:
hegyi@27
   428
      isbutton=0;
hegyi@27
   429
      //we clear settings in two cases
hegyi@27
   430
      //1: the edge is ready (target_item has valid value)
hegyi@27
   431
      //2: the edge creation is cancelled with right button
hegyi@27
   432
      if((target_item)||(e->button.button==3))
ladanyi@63
   433
      {
ladanyi@63
   434
        if(active_item)
ladanyi@63
   435
        {
ladanyi@63
   436
          *active_item << Gnome::Canvas::Properties::fill_color("blue");
ladanyi@63
   437
          active_item=NULL;
ladanyi@63
   438
        }
ladanyi@63
   439
        if(target_item)
ladanyi@63
   440
        {
ladanyi@63
   441
          *target_item << Gnome::Canvas::Properties::fill_color("blue");
ladanyi@63
   442
          target_item=NULL;
ladanyi@63
   443
        }
ladanyi@63
   444
        active_node=INVALID;
ladanyi@63
   445
        active_edge=INVALID;
ladanyi@63
   446
      }
hegyi@27
   447
      break;
hegyi@27
   448
    default:
hegyi@27
   449
      break;
ladanyi@63
   450
  }
hegyi@27
   451
  return false;
hegyi@27
   452
}
hegyi@27
   453
hegyi@30
   454
bool GraphDisplayerCanvas::eraserEventHandler(GdkEvent* e)
hegyi@27
   455
{
hegyi@27
   456
  switch(e->type)
hegyi@27
   457
    {
hegyi@27
   458
    case GDK_BUTTON_PRESS:
hegyi@43
   459
      //finding the clicked items
hegyi@31
   460
      window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
hegyi@31
   461
      active_item=(get_item_at(clicked_x, clicked_y));
hegyi@27
   462
      active_node=INVALID;
hegyi@27
   463
      active_edge=INVALID;
hegyi@43
   464
      //was it a node?
hegyi@96
   465
      for (NodeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
hegyi@27
   466
	{
hegyi@27
   467
	  if(nodesmap[i]==active_item)
hegyi@27
   468
	    {
hegyi@27
   469
	      active_node=i;
hegyi@27
   470
	    }
hegyi@27
   471
	}
hegyi@43
   472
      //or was it an edge?
hegyi@27
   473
      if(active_node==INVALID)
hegyi@27
   474
	{
hegyi@96
   475
	  for (EdgeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
hegyi@27
   476
	    {
ladanyi@153
   477
	      if(edgesmap[i]->getLine()==active_item)
hegyi@27
   478
		{
hegyi@27
   479
		  active_edge=i;
hegyi@27
   480
		}
hegyi@27
   481
	    }
hegyi@27
   482
	}
hegyi@43
   483
ladanyi@129
   484
      // return if the clicked object is neither an edge nor a node
ladanyi@129
   485
      if (active_edge == INVALID) return false;
ladanyi@129
   486
      
hegyi@43
   487
      //recolor activated item
hegyi@31
   488
      if(active_item)
hegyi@31
   489
	{
hegyi@31
   490
	  *active_item << Gnome::Canvas::Properties::fill_color("red");
hegyi@31
   491
	}
hegyi@27
   492
      break;
hegyi@27
   493
hegyi@27
   494
    case GDK_BUTTON_RELEASE:
hegyi@31
   495
      window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
hegyi@31
   496
      if(active_item)
hegyi@27
   497
	{
hegyi@43
   498
	  //the cursor was not moved since pressing it
hegyi@31
   499
	  if( active_item == ( get_item_at (clicked_x, clicked_y) ) )
hegyi@27
   500
	    {
hegyi@43
   501
	      //a node was found
hegyi@31
   502
	      if(active_node!=INVALID)
hegyi@31
   503
		{
hegyi@96
   504
                  (mytab.mapstorage).modified = true;
hegyi@27
   505
hegyi@31
   506
		  std::set<Graph::Edge> edges_to_delete;
hegyi@27
   507
hegyi@96
   508
		  for(OutEdgeIt e((mytab.mapstorage).graph,active_node);e!=INVALID;++e)
hegyi@31
   509
		    {
hegyi@31
   510
		      edges_to_delete.insert(e);
hegyi@31
   511
		    }
alpar@69
   512
		  
hegyi@96
   513
		  for(InEdgeIt e((mytab.mapstorage).graph,active_node);e!=INVALID;++e)
hegyi@31
   514
		    {
hegyi@31
   515
		      edges_to_delete.insert(e);
hegyi@31
   516
		    }
alpar@69
   517
		  
hegyi@31
   518
		  //deleting collected edges
alpar@69
   519
		  for(std::set<Graph::Edge>::iterator
alpar@69
   520
			edge_set_it=edges_to_delete.begin();
alpar@69
   521
		      edge_set_it!=edges_to_delete.end();
alpar@69
   522
		      ++edge_set_it)
hegyi@31
   523
		    {
hegyi@31
   524
		      deleteItem(*edge_set_it);
hegyi@31
   525
		    }
hegyi@31
   526
		  deleteItem(active_node);
hegyi@31
   527
		}
hegyi@31
   528
	      //a simple edge was chosen
ladanyi@129
   529
	      else if (active_edge != INVALID)
hegyi@27
   530
		{
hegyi@31
   531
		  deleteItem(active_edge);
hegyi@27
   532
		}
hegyi@27
   533
	    }
hegyi@31
   534
	  //pointer was moved, deletion is cancelled
hegyi@27
   535
	  else
hegyi@27
   536
	    {
hegyi@31
   537
	      if(active_node!=INVALID)
hegyi@31
   538
		{
hegyi@31
   539
		  *active_item << Gnome::Canvas::Properties::fill_color("blue");
hegyi@31
   540
		}
ladanyi@129
   541
	      else if (active_edge != INVALID)
hegyi@31
   542
		{
hegyi@31
   543
		  *active_item << Gnome::Canvas::Properties::fill_color("green");
hegyi@31
   544
		}
hegyi@27
   545
	    }
hegyi@27
   546
	}
hegyi@27
   547
      //reseting datas
hegyi@27
   548
      active_item=NULL;
hegyi@27
   549
      active_edge=INVALID;
hegyi@27
   550
      active_node=INVALID;
hegyi@27
   551
      break;
hegyi@27
   552
hegyi@27
   553
    case GDK_MOTION_NOTIFY:
hegyi@27
   554
      break;
hegyi@27
   555
hegyi@27
   556
    default:
hegyi@27
   557
      break;
hegyi@27
   558
    }
hegyi@31
   559
  return false;
hegyi@27
   560
}
hegyi@27
   561
hegyi@149
   562
bool GraphDisplayerCanvas::mapEditEventHandler(GdkEvent* e)
hegyi@32
   563
{
hegyi@149
   564
  if(actual_tool==MAP_EDIT)
hegyi@32
   565
    {
hegyi@149
   566
      switch(e->type)
hegyi@149
   567
	{
hegyi@149
   568
	case GDK_BUTTON_PRESS:
hegyi@149
   569
	  {
hegyi@149
   570
	    //for determine, whether it was an edge
hegyi@149
   571
	    Edge clicked_edge=INVALID;
hegyi@149
   572
	    //for determine, whether it was a node
hegyi@149
   573
	    Node clicked_node=INVALID;
hegyi@43
   574
hegyi@149
   575
	    window_to_world (e->button.x, e->button.y, clicked_x, clicked_y);
hegyi@149
   576
	    active_item=(get_item_at(clicked_x, clicked_y));
hegyi@48
   577
hegyi@149
   578
	    //find the activated item between text of nodes
hegyi@149
   579
	    for (NodeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
hegyi@149
   580
	      {
hegyi@149
   581
		//at the same time only one can be active
hegyi@149
   582
		if(nodetextmap[i]==active_item)
hegyi@149
   583
		  {
hegyi@149
   584
		    clicked_node=i;
hegyi@149
   585
		  }
hegyi@149
   586
	      }
ladanyi@65
   587
hegyi@149
   588
	    //if there was not, search for it between nodes
hegyi@149
   589
	    if(clicked_node==INVALID)
hegyi@149
   590
	      {
hegyi@149
   591
		for (NodeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
hegyi@149
   592
		  {
hegyi@149
   593
		    //at the same time only one can be active
hegyi@149
   594
		    if(nodesmap[i]==active_item)
hegyi@149
   595
		      {
hegyi@149
   596
			clicked_node=i;
hegyi@149
   597
		      }
hegyi@149
   598
		  }
hegyi@149
   599
	      }
hegyi@48
   600
hegyi@149
   601
	    if(clicked_node==INVALID)
hegyi@149
   602
	      {
hegyi@149
   603
		//find the activated item between texts
hegyi@149
   604
		for (EdgeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
hegyi@149
   605
		  {
hegyi@149
   606
		    //at the same time only one can be active
hegyi@149
   607
		    if(edgetextmap[i]==active_item)
hegyi@149
   608
		      {
hegyi@149
   609
			clicked_edge=i;
hegyi@149
   610
		      }
hegyi@149
   611
		  }
hegyi@48
   612
hegyi@149
   613
		//if it was not between texts, search for it between edges
hegyi@149
   614
		if(clicked_edge==INVALID)
hegyi@149
   615
		  {
hegyi@149
   616
		    for (EdgeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
hegyi@149
   617
		      {
hegyi@149
   618
			//at the same time only one can be active
hegyi@149
   619
			if((edgesmap[i]->getLine())==active_item)
hegyi@149
   620
			  {
hegyi@149
   621
			    clicked_edge=i;
hegyi@149
   622
			  }
hegyi@149
   623
		      }
hegyi@149
   624
		  }
hegyi@149
   625
	      }
hegyi@149
   626
hegyi@149
   627
	    //if it was really a node...
hegyi@149
   628
	    if(clicked_node!=INVALID)
hegyi@149
   629
	      {
hegyi@149
   630
		// the id map is not editable
hegyi@149
   631
		if (nodemap_to_edit == "label") return 0;
hegyi@149
   632
hegyi@149
   633
		//and there is activated map
hegyi@149
   634
		if(nodetextmap[clicked_node]->property_text().get_value()!="")
hegyi@149
   635
		  {
hegyi@149
   636
		    //activate the general variable for it
hegyi@149
   637
		    active_node=clicked_node;
hegyi@149
   638
hegyi@149
   639
		    //create a dialog
hegyi@149
   640
		    Gtk::Dialog dialog("Edit value", true);
hegyi@149
   641
		    dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
hegyi@149
   642
		    dialog.add_button(Gtk::Stock::OK, Gtk::RESPONSE_ACCEPT);
hegyi@149
   643
		    Gtk::VBox* vbox = dialog.get_vbox();
hegyi@149
   644
		    Gtk::SpinButton spin(0.0, 4);
hegyi@149
   645
		    spin.set_increments(1.0, 10.0);
hegyi@149
   646
		    spin.set_range(-1000000.0, 1000000.0);
hegyi@149
   647
		    spin.set_numeric(true);
hegyi@149
   648
		    spin.set_value(atof(nodetextmap[active_node]->property_text().get_value().c_str()));
hegyi@149
   649
		    vbox->add(spin);
hegyi@149
   650
		    spin.show();
hegyi@149
   651
		    switch (dialog.run())
hegyi@149
   652
		      {
hegyi@149
   653
		      case Gtk::RESPONSE_NONE:
hegyi@149
   654
		      case Gtk::RESPONSE_CANCEL:
hegyi@149
   655
			break;
hegyi@149
   656
		      case Gtk::RESPONSE_ACCEPT:
hegyi@149
   657
			double new_value = spin.get_value();
hegyi@149
   658
			(*(mytab.mapstorage).nodemap_storage[nodemap_to_edit])[active_node] =
hegyi@149
   659
			  new_value;
hegyi@149
   660
			std::ostringstream ostr;
hegyi@149
   661
			ostr << new_value;
hegyi@149
   662
			nodetextmap[active_node]->property_text().set_value(ostr.str());
hegyi@149
   663
			//mapwin.updateNode(active_node);
hegyi@149
   664
			//mapwin.updateNode(Node(INVALID));
hegyi@149
   665
			propertyUpdate(Node(INVALID));
hegyi@149
   666
		      }
hegyi@149
   667
		  }
hegyi@149
   668
	      }
hegyi@149
   669
	    else
hegyi@149
   670
	      //if it was really an edge...
hegyi@149
   671
	      if(clicked_edge!=INVALID)
hegyi@149
   672
		{
hegyi@149
   673
		  // the id map is not editable
hegyi@149
   674
		  if (edgemap_to_edit == "label") return 0;
hegyi@149
   675
hegyi@149
   676
		  //and there is activated map
hegyi@149
   677
		  if(edgetextmap[clicked_edge]->property_text().get_value()!="")
hegyi@149
   678
		    {
hegyi@149
   679
		      //activate the general variable for it
hegyi@149
   680
		      active_edge=clicked_edge;
hegyi@149
   681
hegyi@149
   682
		      //create a dialog
hegyi@149
   683
		      Gtk::Dialog dialog("Edit value", true);
hegyi@149
   684
		      dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
hegyi@149
   685
		      dialog.add_button(Gtk::Stock::OK, Gtk::RESPONSE_ACCEPT);
hegyi@149
   686
		      Gtk::VBox* vbox = dialog.get_vbox();
hegyi@149
   687
		      Gtk::SpinButton spin(0.0, 4);
hegyi@149
   688
		      spin.set_increments(1.0, 10.0);
hegyi@149
   689
		      spin.set_range(-1000000.0, 1000000.0);
hegyi@149
   690
		      spin.set_numeric(true);
hegyi@149
   691
		      spin.set_value(atof(edgetextmap[active_edge]->property_text().get_value().c_str()));
hegyi@149
   692
		      vbox->add(spin);
hegyi@149
   693
		      spin.show();
hegyi@149
   694
		      switch (dialog.run())
hegyi@149
   695
			{
hegyi@149
   696
			case Gtk::RESPONSE_NONE:
hegyi@149
   697
			case Gtk::RESPONSE_CANCEL:
hegyi@149
   698
			  break;
hegyi@149
   699
			case Gtk::RESPONSE_ACCEPT:
hegyi@149
   700
			  double new_value = spin.get_value();
hegyi@149
   701
			  (*(mytab.mapstorage).edgemap_storage[edgemap_to_edit])[active_edge] =
hegyi@149
   702
			    new_value;
hegyi@149
   703
			  std::ostringstream ostr;
hegyi@149
   704
			  ostr << new_value;
hegyi@149
   705
			  edgetextmap[active_edge]->property_text().set_value(
hegyi@149
   706
									      ostr.str());
hegyi@149
   707
			  //mapwin.updateEdge(active_edge);
hegyi@149
   708
			  //                   mapwin.updateEdge(Edge(INVALID));
hegyi@149
   709
			  propertyUpdate(Edge(INVALID));
hegyi@149
   710
			}
hegyi@149
   711
		    }
hegyi@149
   712
		}
hegyi@149
   713
	    break;
hegyi@149
   714
	  }
hegyi@149
   715
	default:
hegyi@149
   716
	  break;
hegyi@149
   717
	}
hegyi@32
   718
    }
hegyi@35
   719
  return false;  
hegyi@32
   720
}
hegyi@32
   721
alpar@62
   722
void GraphDisplayerCanvas::deleteItem(Node node_to_delete)
hegyi@27
   723
{
hegyi@28
   724
  delete(nodetextmap[node_to_delete]);
hegyi@27
   725
  delete(nodesmap[node_to_delete]);
hegyi@96
   726
  (mytab.mapstorage).graph.erase(node_to_delete);
hegyi@27
   727
}
hegyi@27
   728
alpar@62
   729
void GraphDisplayerCanvas::deleteItem(Edge edge_to_delete)
hegyi@27
   730
{
hegyi@28
   731
  delete(edgetextmap[edge_to_delete]);
hegyi@27
   732
  delete(edgesmap[edge_to_delete]);
hegyi@96
   733
  (mytab.mapstorage).graph.erase(edge_to_delete);
hegyi@27
   734
}
hegyi@27
   735
hegyi@150
   736
void GraphDisplayerCanvas::textReposition(XY new_place)
hegyi@27
   737
{
hegyi@150
   738
  new_place+=(XY(10,10));
hegyi@35
   739
  edgetextmap[forming_edge]->property_x().set_value(new_place.x);
hegyi@35
   740
  edgetextmap[forming_edge]->property_y().set_value(new_place.y);
hegyi@27
   741
}
hegyi@27
   742
ladanyi@147
   743
void GraphDisplayerCanvas::toggleEdgeActivity(EdgeBase* active_bre, bool on)
hegyi@27
   744
{
hegyi@27
   745
  if(on)
ladanyi@147
   746
  {
ladanyi@147
   747
    if(forming_edge!=INVALID)
hegyi@27
   748
    {
ladanyi@147
   749
      std::cerr << "ERROR!!!! Valid edge found!" << std::endl;
hegyi@27
   750
    }
ladanyi@147
   751
    else
ladanyi@147
   752
    {
ladanyi@147
   753
      for (EdgeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
ladanyi@147
   754
      {
ladanyi@147
   755
        if(edgesmap[i]==active_bre)
ladanyi@147
   756
        {
ladanyi@147
   757
          forming_edge=i;
ladanyi@147
   758
        }
ladanyi@147
   759
      }
ladanyi@147
   760
    }
ladanyi@147
   761
  }
hegyi@27
   762
  else
hegyi@27
   763
    {
hegyi@160
   764
      if(forming_edge!=INVALID)
hegyi@160
   765
	{
hegyi@160
   766
	  forming_edge=INVALID;
hegyi@160
   767
	}
hegyi@160
   768
      else
hegyi@160
   769
	{
hegyi@160
   770
	  std::cerr << "ERROR!!!! Invalid edge found!" << std::endl;
hegyi@160
   771
	}
hegyi@27
   772
    }
hegyi@160
   773
}
hegyi@160
   774
hegyi@160
   775
void GraphDisplayerCanvas::moveNode(double dx, double dy, Gnome::Canvas::Item * item, Node node)
hegyi@160
   776
{
hegyi@160
   777
  Gnome::Canvas::Item * moved_item=item;
hegyi@160
   778
  Node moved_node=node;
hegyi@160
   779
hegyi@160
   780
  if(item==NULL && node==INVALID)
ladanyi@147
   781
    {
hegyi@160
   782
      moved_item=active_item;
hegyi@160
   783
      moved_node=active_node;
ladanyi@147
   784
    }
hegyi@160
   785
  else
hegyi@160
   786
    {
hegyi@160
   787
      isbutton=1;
hegyi@160
   788
    }
hegyi@160
   789
hegyi@160
   790
  //repositioning node and its text
hegyi@160
   791
  moved_item->move(dx, dy);
hegyi@160
   792
  nodetextmap[moved_node]->move(dx, dy);
hegyi@160
   793
hegyi@160
   794
  // the new coordinates of the centre of the node 
hegyi@160
   795
  double coord_x = dx + (mytab.mapstorage).coords[moved_node].x;
hegyi@160
   796
  double coord_y = dy + (mytab.mapstorage).coords[moved_node].y;
hegyi@160
   797
hegyi@160
   798
  // write back the new coordinates to the coords map
hegyi@160
   799
  (mytab.mapstorage).coords.set(moved_node, XY(coord_x, coord_y));
hegyi@160
   800
hegyi@160
   801
  //all the edges connected to the moved point has to be redrawn
hegyi@160
   802
  for(OutEdgeIt ei((mytab.mapstorage).graph,moved_node);ei!=INVALID;++ei)
hegyi@160
   803
    {
hegyi@160
   804
      XY arrow_pos;
hegyi@160
   805
hegyi@160
   806
      if (mytab.mapstorage.graph.source(ei) == mytab.mapstorage.graph.target(ei))
hegyi@160
   807
	{
hegyi@160
   808
	  arrow_pos = mytab.mapstorage.arrow_pos[ei] + XY(dx, dy);
hegyi@160
   809
	}
hegyi@160
   810
      else
hegyi@160
   811
	{
hegyi@160
   812
	  XY moved_node_1(coord_x - dx, coord_y - dy);
hegyi@160
   813
	  XY moved_node_2(coord_x, coord_y);
hegyi@160
   814
	  Node target = mytab.mapstorage.graph.target(ei);
hegyi@160
   815
	  XY fix_node(mytab.mapstorage.coords[target].x,
hegyi@160
   816
		      mytab.mapstorage.coords[target].y);
hegyi@160
   817
	  XY old_arrow_pos(mytab.mapstorage.arrow_pos[ei]);
hegyi@160
   818
hegyi@160
   819
	  arrow_pos = calcArrowPos(moved_node_1, moved_node_2, fix_node, old_arrow_pos, isbutton);
hegyi@160
   820
	}
hegyi@160
   821
hegyi@160
   822
      mytab.mapstorage.arrow_pos.set(ei, arrow_pos);
hegyi@160
   823
      edgesmap[ei]->draw();
hegyi@160
   824
hegyi@160
   825
      //reposition of edgetext
hegyi@160
   826
      XY text_pos=mytab.mapstorage.arrow_pos[ei];
hegyi@160
   827
      text_pos+=(XY(10,10));
hegyi@160
   828
      edgetextmap[ei]->property_x().set_value(text_pos.x);
hegyi@160
   829
      edgetextmap[ei]->property_y().set_value(text_pos.y);
hegyi@160
   830
    }
hegyi@160
   831
hegyi@160
   832
  for(InEdgeIt ei((mytab.mapstorage).graph,moved_node);ei!=INVALID;++ei)
hegyi@160
   833
    {
hegyi@160
   834
      if (mytab.mapstorage.graph.source(ei) != mytab.mapstorage.graph.target(ei))
hegyi@160
   835
	{
hegyi@160
   836
	  XY moved_node_1(coord_x - dx, coord_y - dy);
hegyi@160
   837
	  XY moved_node_2(coord_x, coord_y);
hegyi@160
   838
	  Node source = mytab.mapstorage.graph.source(ei);
hegyi@160
   839
	  XY fix_node(mytab.mapstorage.coords[source].x,
hegyi@160
   840
		      mytab.mapstorage.coords[source].y);
hegyi@160
   841
	  XY old_arrow_pos(mytab.mapstorage.arrow_pos[ei]);
hegyi@160
   842
hegyi@160
   843
	  XY arrow_pos;
hegyi@160
   844
	  arrow_pos = calcArrowPos(moved_node_1, moved_node_2, fix_node, old_arrow_pos, isbutton);
hegyi@160
   845
hegyi@160
   846
	  mytab.mapstorage.arrow_pos.set(ei, arrow_pos);
hegyi@160
   847
	  edgesmap[ei]->draw();
hegyi@160
   848
hegyi@160
   849
	  //reposition of edgetext
hegyi@160
   850
	  XY text_pos=mytab.mapstorage.arrow_pos[ei];
hegyi@160
   851
	  text_pos+=(XY(10,10));
hegyi@160
   852
	  edgetextmap[ei]->property_x().set_value(text_pos.x);
hegyi@160
   853
	  edgetextmap[ei]->property_y().set_value(text_pos.y);
hegyi@160
   854
	}
hegyi@160
   855
    }
hegyi@27
   856
}