graph_displayer_canvas.h
author ladanyi
Wed, 10 Jan 2007 14:56:16 +0000
changeset 186 013afe9ee040
parent 179 1f436ea3ef4f
child 187 b465e2c34f23
permissions -rw-r--r--
Removed this extra widget thing, because it is now developed in my private branch.
alpar@174
     1
/* -*- C++ -*-
alpar@174
     2
 *
alpar@174
     3
 * This file is a part of LEMON, a generic C++ optimization library
alpar@174
     4
 *
alpar@174
     5
 * Copyright (C) 2003-2006
alpar@174
     6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
alpar@174
     7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
alpar@174
     8
 *
alpar@174
     9
 * Permission to use, modify and distribute this software is granted
alpar@174
    10
 * provided that this copyright notice appears in all copies. For
alpar@174
    11
 * precise terms see the accompanying LICENSE file.
alpar@174
    12
 *
alpar@174
    13
 * This software is provided "AS IS" with no warranty of any kind,
alpar@174
    14
 * express or implied, and with no claim as to its suitability for any
alpar@174
    15
 * purpose.
alpar@174
    16
 *
alpar@174
    17
 */
ladanyi@6
    18
ladanyi@6
    19
#ifndef GRAPH_DISPLAYER_CANVAS_H
ladanyi@6
    20
#define GRAPH_DISPLAYER_CANVAS_H
ladanyi@6
    21
hegyi@21
    22
class GraphDisplayerCanvas;
hegyi@21
    23
ladanyi@53
    24
#include "all_include.h"
hegyi@96
    25
#include "nbtab.h"
ladanyi@6
    26
#include <libgnomecanvasmm.h>
ladanyi@6
    27
#include <libgnomecanvasmm/polygon.h>
hegyi@150
    28
#include <lemon/dim2.h>
ladanyi@6
    29
ladanyi@6
    30
///This class is the canvas, on which the graph can be drawn.
ladanyi@6
    31
class GraphDisplayerCanvas : public Gnome::Canvas::CanvasAA
ladanyi@6
    32
{
ladanyi@98
    33
  friend class BrokenEdge;
ladanyi@147
    34
  friend class LoopEdge;
ladanyi@147
    35
ladanyi@147
    36
  class EdgeBase : public Gnome::Canvas::Group
ladanyi@147
    37
  {
ladanyi@147
    38
    protected:
ladanyi@147
    39
      ///Reference to the canvas, on which the graph is drawn.
ladanyi@147
    40
ladanyi@147
    41
      ///It is needed, because some datas needed from
ladanyi@147
    42
      ///graph can be accessed by this or should be sent
ladanyi@147
    43
      ///as parameter, but it would be complicated
ladanyi@147
    44
      GraphDisplayerCanvas& canvas;
ladanyi@147
    45
ladanyi@147
    46
      ///The edge that the class displays.
ladanyi@147
    47
ladanyi@147
    48
      ///It is needed, because some datas needed from
ladanyi@147
    49
      ///graph can be accessed by this or should be sent
ladanyi@147
    50
      ///as parameter, but it would be complicated
ladanyi@147
    51
      Edge edge;
ladanyi@147
    52
ladanyi@147
    53
      Gnome::Canvas::Polygon arrow;
ladanyi@147
    54
ladanyi@147
    55
      void drawArrow(XY);
ladanyi@147
    56
    public:
ladanyi@147
    57
      EdgeBase(Gnome::Canvas::Group&, Edge, GraphDisplayerCanvas&);
ladanyi@147
    58
      virtual ~EdgeBase();
ladanyi@147
    59
      virtual void draw() = 0;
ladanyi@147
    60
      virtual void setLineWidth(int) = 0;
ladanyi@147
    61
      virtual void setFillColor(Gdk::Color) = 0;
hegyi@149
    62
      virtual Gnome::Canvas::Item * getLine() = 0;
ladanyi@147
    63
  };
ladanyi@98
    64
hegyi@118
    65
  ///Edge displayer class
hegyi@118
    66
hegyi@118
    67
  ///This class is responsible for displaying edges in graph.
hegyi@118
    68
  ///The displayed edge is broken in the middle. The
hegyi@118
    69
  ///aim of this is to be able to indicate direction of edges
hegyi@118
    70
  ///and to be able to display more then one edges between the
hegyi@118
    71
  ///same source and target
ladanyi@147
    72
  class BrokenEdge : public EdgeBase
hegyi@89
    73
  {
ladanyi@147
    74
    private:
ladanyi@147
    75
      Gnome::Canvas::Line line;
hegyi@118
    76
ladanyi@147
    77
      ///Indicates whether the button of mouse is pressed or not at the moment.
ladanyi@147
    78
      bool isbutton;
hegyi@118
    79
ladanyi@147
    80
      ///At this location was the mousebutton pressed. Horizontal component.
hegyi@118
    81
ladanyi@147
    82
      ///It helps to calculate the
ladanyi@147
    83
      ///distance of dragging.
ladanyi@147
    84
      double clicked_x;
hegyi@118
    85
ladanyi@147
    86
      ///At this location was the mousebutton pressed. Vertical component.
hegyi@118
    87
ladanyi@147
    88
      ///It helps to calculate the
ladanyi@147
    89
      ///distance of dragging.
ladanyi@147
    90
      double clicked_y;
hegyi@89
    91
ladanyi@147
    92
      ///event handler for forming broken edges
hegyi@89
    93
ladanyi@147
    94
      ///\param event the
ladanyi@147
    95
      ///event to handle
ladanyi@147
    96
      bool edgeFormerEventHandler(GdkEvent* event);
hegyi@89
    97
ladanyi@147
    98
    public:
ladanyi@147
    99
      ///Constructor of broken edge class.
hegyi@118
   100
ladanyi@147
   101
      ///\param g the group to which the edge belongs
ladanyi@147
   102
      ///\param _edge the represented edge
ladanyi@147
   103
      ///\param gc the canvas
ladanyi@147
   104
      BrokenEdge(Gnome::Canvas::Group&, Edge, GraphDisplayerCanvas&);
hegyi@118
   105
ladanyi@147
   106
      ///Destructor of broken edge class
hegyi@118
   107
ladanyi@147
   108
      ///Frees up
ladanyi@147
   109
      ///reserved memory
ladanyi@147
   110
      ~BrokenEdge();
hegyi@118
   111
ladanyi@147
   112
      ///The function that draws the edge based on collected data
ladanyi@147
   113
      void draw();
hegyi@118
   114
ladanyi@147
   115
      void setLineWidth(int);
ladanyi@147
   116
      void setFillColor(Gdk::Color);
hegyi@149
   117
hegyi@149
   118
      Gnome::Canvas::Item * getLine() { return (Gnome::Canvas::Item *)(&line); };
ladanyi@147
   119
  };
hegyi@118
   120
ladanyi@147
   121
  class LoopEdge : public EdgeBase
ladanyi@147
   122
  {
ladanyi@147
   123
    private:
ladanyi@147
   124
      Gnome::Canvas::Ellipse line;
ladanyi@151
   125
      bool edgeFormerEventHandler(GdkEvent* e);
ladanyi@151
   126
      bool isbutton;
ladanyi@147
   127
    public:
ladanyi@147
   128
      LoopEdge(Gnome::Canvas::Group&, Edge, GraphDisplayerCanvas&);
ladanyi@147
   129
      ~LoopEdge();
ladanyi@147
   130
      void draw();
ladanyi@147
   131
      void setLineWidth(int);
ladanyi@147
   132
      void setFillColor(Gdk::Color);
hegyi@149
   133
      Gnome::Canvas::Item * getLine() { return (Gnome::Canvas::Item *)(&line); };
hegyi@89
   134
  };
hegyi@118
   135
hegyi@118
   136
  ///Type of canvas, on which the graph is drawn
ladanyi@6
   137
  typedef Gnome::Canvas::CanvasAA Parent;
ladanyi@6
   138
ladanyi@6
   139
public:
hegyi@118
   140
  ///Constructor
hegyi@118
   141
hegyi@118
   142
  ///\param nbt the tab of the window, in which the graph is displayed
hegyi@118
   143
  GraphDisplayerCanvas(NoteBookTab & nbt);
hegyi@118
   144
hegyi@118
   145
  ///destructor of the class
ladanyi@6
   146
  virtual ~GraphDisplayerCanvas();
ladanyi@6
   147
hegyi@179
   148
  ///Returns a color of the rainbow based on a map value and the min and max value of the given map
hegyi@179
   149
hegyi@179
   150
  ///min and max is purple, between them there is a linear assign
hegyi@179
   151
  Gdk::Color rainbowColorCounter(double, double, double);
hegyi@179
   152
hegyi@118
   153
  ///Changes the width of edge(s) according to the given map.
hegyi@118
   154
hegyi@118
   155
  ///\param mapname is the name of the map which contains the values to be set
hegyi@118
   156
  ///\param edge if it is given, only the width of the given edge will be set, instead of all of them.
hegyi@118
   157
  int changeEdgeWidth (std::string mapname, Edge edge=INVALID);
hegyi@118
   158
hegyi@118
   159
  ///Resets width of edge(s) to the default value
hegyi@118
   160
hegyi@118
   161
  ///\param edge if it is given, only the width of the
hegyi@118
   162
  ///given edge will be reset, instead of all of them.
hegyi@118
   163
  int resetEdgeWidth (Edge edge=INVALID);
hegyi@118
   164
hegyi@118
   165
  ///Changes the color of edge(s) according to the given map.
hegyi@118
   166
ladanyi@6
   167
  ///\param mapname is the name of the map which contains the new values
hegyi@118
   168
  ///\param edge if it is given, only the color of the given edge will be set, instead of all of them.
hegyi@118
   169
  int changeEdgeColor (std::string mapname, Edge edge=INVALID);
ladanyi@6
   170
hegyi@118
   171
  ///Resets color of edge(s) to the default value
hegyi@118
   172
hegyi@118
   173
  ///\param edge if it is given, only the color of the
hegyi@118
   174
  ///given edge will be reset, instead of all of them.
hegyi@118
   175
  int resetEdgeColor (Edge edge=INVALID);
hegyi@118
   176
hegyi@118
   177
  ///Changes the label of edge(s) according to the given map.
hegyi@118
   178
ladanyi@6
   179
  ///\param mapname is the name of the map which contains the new values
hegyi@118
   180
  ///\param edge if it is given, only the label of the given edge will be set, instead of all of them.
hegyi@118
   181
  int changeEdgeText (std::string mapname, Edge edge=INVALID);
ladanyi@6
   182
hegyi@118
   183
  ///Resets label of edge(s) to the default value
hegyi@118
   184
hegyi@118
   185
  ///\param edge if it is given, only the color of the
hegyi@118
   186
  ///given edge will be reset, instead of all of them.
hegyi@118
   187
  int resetEdgeText (Edge edge=INVALID);
hegyi@118
   188
hegyi@118
   189
  ///Changes the radius of node(s) according to the given map.
hegyi@118
   190
ladanyi@6
   191
  ///\param mapname is the name of the map which contains the new values
hegyi@118
   192
  ///\param node if it is given, only the radius of the given node will be set, instead of all of them.
hegyi@118
   193
  int changeNodeRadius (std::string mapname, Node node=INVALID);
hegyi@28
   194
hegyi@118
   195
  ///Resets radius of node(s) to the default value
hegyi@118
   196
hegyi@118
   197
  ///\param node if it is given, only the radius of the
hegyi@118
   198
  ///given node will be reset, instead of all of them.
hegyi@118
   199
  int resetNodeRadius (Node node=INVALID);
hegyi@118
   200
hegyi@118
   201
  ///Changes the color of node(s) according to the given map.
hegyi@118
   202
hegyi@28
   203
  ///\param mapname is the name of the map which contains the new values
hegyi@118
   204
  ///\param node if it is given, only the color of the given node will be set, instead of all of them.
hegyi@118
   205
  int changeNodeColor (std::string mapname, Node node=INVALID);
hegyi@28
   206
hegyi@118
   207
  ///Resets color of node(s) to the default value
hegyi@118
   208
hegyi@118
   209
  ///\param node if it is given, only the color of the
hegyi@118
   210
  ///given node will be reset, instead of all of them.
hegyi@118
   211
  int resetNodeColor (Node node=INVALID);
hegyi@118
   212
hegyi@118
   213
  ///Changes the label of node(s) according to the given map.
hegyi@118
   214
hegyi@28
   215
  ///\param mapname is the name of the map which contains the new values
hegyi@118
   216
  ///\param node if it is given, only the label of the given node will be set, instead of all of them.
hegyi@118
   217
  int changeNodeText (std::string mapname, Node node=INVALID);
hegyi@28
   218
hegyi@118
   219
  ///Resets label of node(s) to the default value
ladanyi@6
   220
hegyi@118
   221
  ///\param node if it is given, only the label of the
hegyi@118
   222
  ///given node will be reset, instead of all of them.
hegyi@118
   223
  int resetNodeText (Node node=INVALID);
hegyi@94
   224
hegyi@118
   225
  ///This function is called, when any of the displayed attributes have to be updated, or changed
hegyi@118
   226
hegyi@118
   227
  ///\param itisedge if true, edge property has to be changed, else node property
hegyi@118
   228
  ///\param prop the id of property that has to changed or updated
hegyi@118
   229
  void propertyChange(bool itisedge, int prop);
hegyi@118
   230
hegyi@118
   231
  ///updates the given property
hegyi@118
   232
hegyi@118
   233
  ///\param edge if it is not INVALID, only the property of the given edge will be updated, instead of all of them
hegyi@118
   234
  ///\param prop the property to update
hegyi@118
   235
  void propertyUpdate(Edge edge, int prop);
hegyi@118
   236
hegyi@118
   237
  ///updates the given property
hegyi@118
   238
hegyi@118
   239
  ///\param node if it is not INVALID, only the property of the given node will be updated, instead of all of them
hegyi@118
   240
  ///\param prop the property to update
hegyi@118
   241
  void propertyUpdate(Node node, int prop);
hegyi@118
   242
hegyi@118
   243
  ///updates all the property for the given edge
hegyi@94
   244
  void propertyUpdate(Edge);
hegyi@118
   245
hegyi@118
   246
  ///updates all the property for the given node
hegyi@94
   247
  void propertyUpdate(Node);
hegyi@94
   248
ladanyi@6
   249
  ///Callback for 'ViewZoomIn' action.
ladanyi@6
   250
  virtual void zoomIn();
ladanyi@6
   251
  ///Callback for 'ViewZoomOut' action.
ladanyi@6
   252
  virtual void zoomOut();
ladanyi@6
   253
  ///Callback for 'ViewZoomFit' action.
ladanyi@6
   254
  virtual void zoomFit();
ladanyi@6
   255
  ///Callback for 'ViewZoom100' action.
ladanyi@6
   256
  virtual void zoom100();
ladanyi@6
   257
  ///Sets the scroll region of the convas to the bounding box of the graph.
ladanyi@6
   258
  void updateScrollRegion();
ladanyi@6
   259
hegyi@9
   260
  ///This function changes the tool in the graph-editor's hand
hegyi@9
   261
  void changeEditorialTool(int);
hegyi@9
   262
ladanyi@6
   263
protected:
ladanyi@6
   264
hegyi@118
   265
  //maximizing, minimizing, restoring window, etc.
ladanyi@6
   266
  virtual bool on_expose_event(GdkEventExpose *);
ladanyi@6
   267
ladanyi@6
   268
private:
ladanyi@6
   269
ladanyi@6
   270
  ///This function is responsible for the correct
ladanyi@6
   271
  ///reaction of any action happened in the territory
ladanyi@6
   272
  ///of the canvas
hegyi@25
   273
  ///DEPRECATED!!!!
hegyi@30
   274
  bool eventHandler(GdkEvent* e, Node n);
ladanyi@6
   275
hegyi@9
   276
  ///actual event handler
hegyi@9
   277
  ///
hegyi@9
   278
  ///Actual event handler should be stored, to be able to disconnect it and later reconnect it.
hegyi@9
   279
  sigc::connection actual_handler;
hegyi@9
   280
hegyi@9
   281
  ///event handler for the case when move-tool is active
hegyi@30
   282
  bool moveEventHandler(GdkEvent*);
hegyi@9
   283
  ///event handler for the case when create_node-tool is active
hegyi@30
   284
  bool createNodeEventHandler(GdkEvent*);
hegyi@9
   285
  ///event handler for the case when create_edge-tool is active
hegyi@30
   286
  bool createEdgeEventHandler(GdkEvent*);
hegyi@13
   287
  ///event handler for the case when eraser-tool is active
hegyi@30
   288
  bool eraserEventHandler(GdkEvent*);
hegyi@149
   289
  ///event handler for the case when map editor tool is active
hegyi@149
   290
  bool mapEditEventHandler(GdkEvent*);
hegyi@13
   291
hegyi@160
   292
private:
hegyi@160
   293
  ///moves node according to the given parameters
hegyi@160
   294
  void moveNode(double, double,  Gnome::Canvas::Item * item=NULL, Node node=INVALID);
hegyi@160
   295
hegyi@21
   296
public:
hegyi@25
   297
  ///Moves the text to new place
hegyi@150
   298
  void textReposition(XY);
hegyi@118
   299
ladanyi@147
   300
  ///Activates an edge belonging to an EdgeBase
hegyi@118
   301
hegyi@35
   302
  ///After we have activated an edge this way,
hegyi@35
   303
  ///the GDC object will know, which edge is under forming
hegyi@118
   304
  ///therefore it can redraw the necessary elements on the canvas,
ladanyi@147
   305
  ///for example the text belonging to the \ref EdgeBase can be
hegyi@35
   306
  ///redrawn (\ref textReposition).
ladanyi@147
   307
  void toggleEdgeActivity(EdgeBase*, bool);
hegyi@25
   308
hegyi@25
   309
public:
hegyi@118
   310
hegyi@118
   311
  ///Returns the actual tool in hand
hegyi@30
   312
  int getActualTool();
hegyi@21
   313
hegyi@154
   314
  ///Sets node representation settings
hegyi@157
   315
  void setView(bool, bool, double, double);
hegyi@154
   316
hegyi@154
   317
  ///Gets node representation settings
hegyi@157
   318
  void getView(bool &, bool &, double&, double&);
hegyi@154
   319
hegyi@118
   320
  ///draws the graph
hegyi@118
   321
hegyi@118
   322
  ///Called when opening a file.
ladanyi@53
   323
  void drawGraph();
hegyi@118
   324
hegyi@118
   325
  ///Clears the canvas
hegyi@118
   326
hegyi@118
   327
  ///It achieves this by deleting all data
hegyi@118
   328
  ///structure used to help handle the displayed graph.
ladanyi@53
   329
  void clear();
ladanyi@53
   330
hegyi@37
   331
  ///creates a new Nodemap
hegyi@118
   332
hegyi@118
   333
  ///\param init initial value of the map
hegyi@118
   334
  ///\param mapname name of new map
hegyi@118
   335
  int addNewNodeMap(double init,std::string mapname);
hegyi@37
   336
  ///creates a new Edgemap
hegyi@118
   337
hegyi@118
   338
  ///\param init initial value of the map
hegyi@118
   339
  ///\param mapname name of new map
hegyi@118
   340
  int addNewEdgeMap(double init,std::string mapname);
hegyi@37
   341
hegyi@160
   342
  void reDesignGraph();
hegyi@160
   343
hegyi@172
   344
  ///Show whether the graph is already drawn.
hegyi@172
   345
  bool is_drawn;
hegyi@172
   346
hegyi@21
   347
private:
hegyi@14
   348
  ///Deletes the given element.
alpar@62
   349
  void deleteItem(Node);
hegyi@14
   350
  ///Deletes the given element.
alpar@62
   351
  void deleteItem(Edge);
hegyi@9
   352
hegyi@21
   353
private:
hegyi@21
   354
ladanyi@6
   355
  ///Map of nodes of graph
ladanyi@6
   356
  Graph::NodeMap<Gnome::Canvas::Ellipse *> nodesmap;
ladanyi@6
   357
ladanyi@6
   358
  ///Map of edges of graph
ladanyi@147
   359
  Graph::EdgeMap<EdgeBase*> edgesmap;
ladanyi@6
   360
ladanyi@6
   361
  ///Map of texts to write on edges
ladanyi@6
   362
  Graph::EdgeMap<Gnome::Canvas::Text *> edgetextmap;
ladanyi@6
   363
hegyi@28
   364
  ///Map of texts to write on nodes
hegyi@28
   365
  Graph::NodeMap<Gnome::Canvas::Text *> nodetextmap;
hegyi@28
   366
ladanyi@6
   367
  ///Group of graphical elements of displayed_graph
ladanyi@6
   368
  Gnome::Canvas::Group displayed_graph;
ladanyi@6
   369
hegyi@88
   370
private:
ladanyi@6
   371
  ///Indicates whether the button of mouse is pressed or not
hegyi@20
   372
  int isbutton;
ladanyi@6
   373
hegyi@21
   374
  ///Stores the actual tool in hand
hegyi@21
   375
  int actual_tool;
hegyi@21
   376
ladanyi@6
   377
  ///At this location was the mousebutton pressed.
ladanyi@6
   378
  ///It helps to calculate the distance of dragging.
ladanyi@6
   379
  double clicked_x, clicked_y;
ladanyi@6
   380
ladanyi@6
   381
  ///Remembers which Gnome::Canvas::Item was pressed.
hegyi@118
   382
hegyi@118
   383
  ///this variable is needed, to work on it after selection
hegyi@118
   384
  Gnome::Canvas::Item * active_item;
hegyi@118
   385
hegyi@118
   386
  ///Remembers which Gnome::Canvas::Item was pressed.
hegyi@118
   387
hegyi@118
   388
  ///this variable is used at edge creation, it will
hegyi@118
   389
  ///be the secondly selected node. No local variable
hegyi@118
   390
  ///can be used for this purpose inside the function,
hegyi@118
   391
  ///because the node selected by button press, and
hegyi@118
   392
  ///the edge is created by button release. Both of
hegyi@118
   393
  ///them is different function call.
hegyi@118
   394
  Gnome::Canvas::Item * target_item;
hegyi@118
   395
hegyi@118
   396
  ///selected node (for any editing)
alpar@62
   397
  Node active_node;
hegyi@118
   398
hegyi@118
   399
  ///selected edge (for any editing)
alpar@62
   400
  Edge active_edge;
hegyi@118
   401
hegyi@118
   402
  ///the edge that is selected by clicking on the red arrow in the middle of it
hegyi@118
   403
hegyi@118
   404
  ///This edge is stored only for the purpose of reshape it.
hegyi@118
   405
  ///That is why it is selected in a different manner.
alpar@62
   406
  Edge forming_edge;
hegyi@35
   407
hegyi@118
   408
  ///Map displayed by label can be edited.
hegyi@118
   409
  std::string nodemap_to_edit;
hegyi@118
   410
hegyi@118
   411
  ///Map displayed by label can be edited.
hegyi@118
   412
  std::string edgemap_to_edit;
ladanyi@6
   413
ladanyi@6
   414
  static const int zoom_step = 5;
hegyi@19
   415
hegyi@154
   416
  ///Is node radius autoscaled
hegyi@154
   417
  bool autoscale;
hegyi@154
   418
  
hegyi@156
   419
  ///Should we track zoomfactor changes
hegyi@156
   420
  bool zoomtrack;
hegyi@156
   421
hegyi@156
   422
  ///to store the zoom factor when it was "fixed"
hegyi@156
   423
  double fixed_zoom_factor;
hegyi@156
   424
  
hegyi@157
   425
  ///Node radius size
hegyi@157
   426
  double radius_size;
hegyi@154
   427
hegyi@157
   428
  ///Edge width
hegyi@157
   429
  double edge_width;
hegyi@154
   430
hegyi@166
   431
  ///Was redesign run on this graph already?
hegyi@166
   432
  ///
hegyi@166
   433
  ///If not, the layout will be modified randomly
hegyi@166
   434
  ///to avoid frozen layout because of wrong
hegyi@166
   435
  ///initial state
hegyi@166
   436
  bool was_redesigned;
hegyi@160
   437
  
hegyi@88
   438
private:
hegyi@88
   439
hegyi@118
   440
  ///reference to the container, in which the canvas is
hegyi@96
   441
  NoteBookTab & mytab;
hegyi@55
   442
hegyi@148
   443
  XY calcArrowPos(XY, XY, XY, XY, int);
ladanyi@184
   444
ladanyi@184
   445
  bool background_set;
ladanyi@184
   446
  Glib::RefPtr<Gdk::Pixbuf> refBackground;
ladanyi@184
   447
  Gnome::Canvas::Pixbuf *background;
ladanyi@184
   448
public:
ladanyi@184
   449
  void setBackground();
ladanyi@6
   450
};
ladanyi@6
   451
ladanyi@6
   452
#endif //GRAPH_DISPLAYER_CANVAS_H