alpar@174: /* -*- C++ -*- alpar@174: * alpar@174: * This file is a part of LEMON, a generic C++ optimization library alpar@174: * alpar@174: * Copyright (C) 2003-2006 alpar@174: * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport alpar@174: * (Egervary Research Group on Combinatorial Optimization, EGRES). alpar@174: * alpar@174: * Permission to use, modify and distribute this software is granted alpar@174: * provided that this copyright notice appears in all copies. For alpar@174: * precise terms see the accompanying LICENSE file. alpar@174: * alpar@174: * This software is provided "AS IS" with no warranty of any kind, alpar@174: * express or implied, and with no claim as to its suitability for any alpar@174: * purpose. alpar@174: * alpar@174: */ ladanyi@6: ladanyi@6: #ifndef GRAPH_DISPLAYER_CANVAS_H ladanyi@6: #define GRAPH_DISPLAYER_CANVAS_H ladanyi@6: hegyi@21: class GraphDisplayerCanvas; hegyi@21: ladanyi@53: #include "all_include.h" hegyi@96: #include "nbtab.h" ladanyi@6: #include ladanyi@6: #include hegyi@150: #include ladanyi@6: ladanyi@6: ///This class is the canvas, on which the graph can be drawn. ladanyi@6: class GraphDisplayerCanvas : public Gnome::Canvas::CanvasAA ladanyi@6: { ladanyi@98: friend class BrokenEdge; ladanyi@147: friend class LoopEdge; ladanyi@147: ladanyi@147: class EdgeBase : public Gnome::Canvas::Group ladanyi@147: { ladanyi@147: protected: ladanyi@147: ///Reference to the canvas, on which the graph is drawn. ladanyi@147: ladanyi@147: ///It is needed, because some datas needed from ladanyi@147: ///graph can be accessed by this or should be sent ladanyi@147: ///as parameter, but it would be complicated ladanyi@147: GraphDisplayerCanvas& canvas; ladanyi@147: ladanyi@147: ///The edge that the class displays. ladanyi@147: ladanyi@147: ///It is needed, because some datas needed from ladanyi@147: ///graph can be accessed by this or should be sent ladanyi@147: ///as parameter, but it would be complicated ladanyi@147: Edge edge; ladanyi@147: ladanyi@147: Gnome::Canvas::Polygon arrow; ladanyi@147: ladanyi@147: void drawArrow(XY); ladanyi@147: public: ladanyi@147: EdgeBase(Gnome::Canvas::Group&, Edge, GraphDisplayerCanvas&); ladanyi@147: virtual ~EdgeBase(); ladanyi@147: virtual void draw() = 0; ladanyi@147: virtual void setLineWidth(int) = 0; ladanyi@147: virtual void setFillColor(Gdk::Color) = 0; hegyi@149: virtual Gnome::Canvas::Item * getLine() = 0; ladanyi@147: }; ladanyi@98: hegyi@118: ///Edge displayer class hegyi@118: hegyi@118: ///This class is responsible for displaying edges in graph. hegyi@118: ///The displayed edge is broken in the middle. The hegyi@118: ///aim of this is to be able to indicate direction of edges hegyi@118: ///and to be able to display more then one edges between the hegyi@118: ///same source and target ladanyi@147: class BrokenEdge : public EdgeBase hegyi@89: { ladanyi@147: private: ladanyi@147: Gnome::Canvas::Line line; hegyi@118: ladanyi@147: ///Indicates whether the button of mouse is pressed or not at the moment. ladanyi@147: bool isbutton; hegyi@118: ladanyi@147: ///At this location was the mousebutton pressed. Horizontal component. hegyi@118: ladanyi@147: ///It helps to calculate the ladanyi@147: ///distance of dragging. ladanyi@147: double clicked_x; hegyi@118: ladanyi@147: ///At this location was the mousebutton pressed. Vertical component. hegyi@118: ladanyi@147: ///It helps to calculate the ladanyi@147: ///distance of dragging. ladanyi@147: double clicked_y; hegyi@89: ladanyi@147: ///event handler for forming broken edges hegyi@89: ladanyi@147: ///\param event the ladanyi@147: ///event to handle ladanyi@147: bool edgeFormerEventHandler(GdkEvent* event); hegyi@89: ladanyi@147: public: ladanyi@147: ///Constructor of broken edge class. hegyi@118: ladanyi@147: ///\param g the group to which the edge belongs ladanyi@147: ///\param _edge the represented edge ladanyi@147: ///\param gc the canvas ladanyi@147: BrokenEdge(Gnome::Canvas::Group&, Edge, GraphDisplayerCanvas&); hegyi@118: ladanyi@147: ///Destructor of broken edge class hegyi@118: ladanyi@147: ///Frees up ladanyi@147: ///reserved memory ladanyi@147: ~BrokenEdge(); hegyi@118: ladanyi@147: ///The function that draws the edge based on collected data ladanyi@147: void draw(); hegyi@118: ladanyi@147: void setLineWidth(int); ladanyi@147: void setFillColor(Gdk::Color); hegyi@149: hegyi@149: Gnome::Canvas::Item * getLine() { return (Gnome::Canvas::Item *)(&line); }; ladanyi@147: }; hegyi@118: ladanyi@147: class LoopEdge : public EdgeBase ladanyi@147: { ladanyi@147: private: ladanyi@147: Gnome::Canvas::Ellipse line; ladanyi@151: bool edgeFormerEventHandler(GdkEvent* e); ladanyi@151: bool isbutton; ladanyi@147: public: ladanyi@147: LoopEdge(Gnome::Canvas::Group&, Edge, GraphDisplayerCanvas&); ladanyi@147: ~LoopEdge(); ladanyi@147: void draw(); ladanyi@147: void setLineWidth(int); ladanyi@147: void setFillColor(Gdk::Color); hegyi@149: Gnome::Canvas::Item * getLine() { return (Gnome::Canvas::Item *)(&line); }; hegyi@89: }; hegyi@118: hegyi@118: ///Type of canvas, on which the graph is drawn ladanyi@6: typedef Gnome::Canvas::CanvasAA Parent; ladanyi@6: ladanyi@6: public: hegyi@118: ///Constructor hegyi@118: hegyi@118: ///\param nbt the tab of the window, in which the graph is displayed hegyi@118: GraphDisplayerCanvas(NoteBookTab & nbt); hegyi@118: hegyi@118: ///destructor of the class ladanyi@6: virtual ~GraphDisplayerCanvas(); ladanyi@6: hegyi@179: ///Returns a color of the rainbow based on a map value and the min and max value of the given map hegyi@179: hegyi@179: ///min and max is purple, between them there is a linear assign hegyi@179: Gdk::Color rainbowColorCounter(double, double, double); hegyi@179: hegyi@118: ///Changes the width of edge(s) according to the given map. hegyi@118: hegyi@118: ///\param mapname is the name of the map which contains the values to be set hegyi@118: ///\param edge if it is given, only the width of the given edge will be set, instead of all of them. hegyi@118: int changeEdgeWidth (std::string mapname, Edge edge=INVALID); hegyi@118: hegyi@118: ///Resets width of edge(s) to the default value hegyi@118: hegyi@118: ///\param edge if it is given, only the width of the hegyi@118: ///given edge will be reset, instead of all of them. hegyi@118: int resetEdgeWidth (Edge edge=INVALID); hegyi@118: hegyi@118: ///Changes the color of edge(s) according to the given map. hegyi@118: ladanyi@6: ///\param mapname is the name of the map which contains the new values hegyi@118: ///\param edge if it is given, only the color of the given edge will be set, instead of all of them. hegyi@118: int changeEdgeColor (std::string mapname, Edge edge=INVALID); ladanyi@6: hegyi@118: ///Resets color of edge(s) to the default value hegyi@118: hegyi@118: ///\param edge if it is given, only the color of the hegyi@118: ///given edge will be reset, instead of all of them. hegyi@118: int resetEdgeColor (Edge edge=INVALID); hegyi@118: hegyi@118: ///Changes the label of edge(s) according to the given map. hegyi@118: ladanyi@6: ///\param mapname is the name of the map which contains the new values hegyi@118: ///\param edge if it is given, only the label of the given edge will be set, instead of all of them. hegyi@118: int changeEdgeText (std::string mapname, Edge edge=INVALID); ladanyi@6: hegyi@118: ///Resets label of edge(s) to the default value hegyi@118: hegyi@118: ///\param edge if it is given, only the color of the hegyi@118: ///given edge will be reset, instead of all of them. hegyi@118: int resetEdgeText (Edge edge=INVALID); hegyi@118: hegyi@118: ///Changes the radius of node(s) according to the given map. hegyi@118: ladanyi@6: ///\param mapname is the name of the map which contains the new values hegyi@118: ///\param node if it is given, only the radius of the given node will be set, instead of all of them. hegyi@118: int changeNodeRadius (std::string mapname, Node node=INVALID); hegyi@28: hegyi@118: ///Resets radius of node(s) to the default value hegyi@118: hegyi@118: ///\param node if it is given, only the radius of the hegyi@118: ///given node will be reset, instead of all of them. hegyi@118: int resetNodeRadius (Node node=INVALID); hegyi@118: hegyi@118: ///Changes the color of node(s) according to the given map. hegyi@118: hegyi@28: ///\param mapname is the name of the map which contains the new values hegyi@118: ///\param node if it is given, only the color of the given node will be set, instead of all of them. hegyi@118: int changeNodeColor (std::string mapname, Node node=INVALID); hegyi@28: hegyi@118: ///Resets color of node(s) to the default value hegyi@118: hegyi@118: ///\param node if it is given, only the color of the hegyi@118: ///given node will be reset, instead of all of them. hegyi@118: int resetNodeColor (Node node=INVALID); hegyi@118: hegyi@118: ///Changes the label of node(s) according to the given map. hegyi@118: hegyi@28: ///\param mapname is the name of the map which contains the new values hegyi@118: ///\param node if it is given, only the label of the given node will be set, instead of all of them. hegyi@118: int changeNodeText (std::string mapname, Node node=INVALID); hegyi@28: hegyi@118: ///Resets label of node(s) to the default value ladanyi@6: hegyi@118: ///\param node if it is given, only the label of the hegyi@118: ///given node will be reset, instead of all of them. hegyi@118: int resetNodeText (Node node=INVALID); hegyi@94: hegyi@118: ///This function is called, when any of the displayed attributes have to be updated, or changed hegyi@118: hegyi@118: ///\param itisedge if true, edge property has to be changed, else node property hegyi@118: ///\param prop the id of property that has to changed or updated hegyi@118: void propertyChange(bool itisedge, int prop); hegyi@118: hegyi@118: ///updates the given property hegyi@118: hegyi@118: ///\param edge if it is not INVALID, only the property of the given edge will be updated, instead of all of them hegyi@118: ///\param prop the property to update hegyi@118: void propertyUpdate(Edge edge, int prop); hegyi@118: hegyi@118: ///updates the given property hegyi@118: hegyi@118: ///\param node if it is not INVALID, only the property of the given node will be updated, instead of all of them hegyi@118: ///\param prop the property to update hegyi@118: void propertyUpdate(Node node, int prop); hegyi@118: hegyi@118: ///updates all the property for the given edge hegyi@94: void propertyUpdate(Edge); hegyi@118: hegyi@118: ///updates all the property for the given node hegyi@94: void propertyUpdate(Node); hegyi@94: ladanyi@6: ///Callback for 'ViewZoomIn' action. ladanyi@6: virtual void zoomIn(); ladanyi@6: ///Callback for 'ViewZoomOut' action. ladanyi@6: virtual void zoomOut(); ladanyi@6: ///Callback for 'ViewZoomFit' action. ladanyi@6: virtual void zoomFit(); ladanyi@6: ///Callback for 'ViewZoom100' action. ladanyi@6: virtual void zoom100(); ladanyi@6: ///Sets the scroll region of the convas to the bounding box of the graph. ladanyi@6: void updateScrollRegion(); ladanyi@6: hegyi@9: ///This function changes the tool in the graph-editor's hand hegyi@9: void changeEditorialTool(int); hegyi@9: ladanyi@6: protected: ladanyi@6: hegyi@118: //maximizing, minimizing, restoring window, etc. ladanyi@6: virtual bool on_expose_event(GdkEventExpose *); ladanyi@6: ladanyi@6: private: ladanyi@6: ladanyi@6: ///This function is responsible for the correct ladanyi@6: ///reaction of any action happened in the territory ladanyi@6: ///of the canvas hegyi@25: ///DEPRECATED!!!! hegyi@30: bool eventHandler(GdkEvent* e, Node n); ladanyi@6: hegyi@9: ///actual event handler hegyi@9: /// hegyi@9: ///Actual event handler should be stored, to be able to disconnect it and later reconnect it. hegyi@9: sigc::connection actual_handler; hegyi@9: hegyi@9: ///event handler for the case when move-tool is active hegyi@30: bool moveEventHandler(GdkEvent*); hegyi@9: ///event handler for the case when create_node-tool is active hegyi@30: bool createNodeEventHandler(GdkEvent*); hegyi@9: ///event handler for the case when create_edge-tool is active hegyi@30: bool createEdgeEventHandler(GdkEvent*); hegyi@13: ///event handler for the case when eraser-tool is active hegyi@30: bool eraserEventHandler(GdkEvent*); hegyi@149: ///event handler for the case when map editor tool is active hegyi@149: bool mapEditEventHandler(GdkEvent*); hegyi@13: hegyi@160: private: hegyi@160: ///moves node according to the given parameters hegyi@160: void moveNode(double, double, Gnome::Canvas::Item * item=NULL, Node node=INVALID); hegyi@160: hegyi@21: public: hegyi@25: ///Moves the text to new place hegyi@150: void textReposition(XY); hegyi@118: ladanyi@147: ///Activates an edge belonging to an EdgeBase hegyi@118: hegyi@35: ///After we have activated an edge this way, hegyi@35: ///the GDC object will know, which edge is under forming hegyi@118: ///therefore it can redraw the necessary elements on the canvas, ladanyi@147: ///for example the text belonging to the \ref EdgeBase can be hegyi@35: ///redrawn (\ref textReposition). ladanyi@147: void toggleEdgeActivity(EdgeBase*, bool); hegyi@25: hegyi@25: public: hegyi@118: hegyi@118: ///Returns the actual tool in hand hegyi@30: int getActualTool(); hegyi@21: hegyi@154: ///Sets node representation settings hegyi@157: void setView(bool, bool, double, double); hegyi@154: hegyi@154: ///Gets node representation settings hegyi@157: void getView(bool &, bool &, double&, double&); hegyi@154: hegyi@118: ///draws the graph hegyi@118: hegyi@118: ///Called when opening a file. ladanyi@53: void drawGraph(); hegyi@118: hegyi@118: ///Clears the canvas hegyi@118: hegyi@118: ///It achieves this by deleting all data hegyi@118: ///structure used to help handle the displayed graph. ladanyi@53: void clear(); ladanyi@53: hegyi@37: ///creates a new Nodemap hegyi@118: hegyi@118: ///\param init initial value of the map hegyi@118: ///\param mapname name of new map hegyi@118: int addNewNodeMap(double init,std::string mapname); hegyi@37: ///creates a new Edgemap hegyi@118: hegyi@118: ///\param init initial value of the map hegyi@118: ///\param mapname name of new map hegyi@118: int addNewEdgeMap(double init,std::string mapname); hegyi@37: hegyi@160: void reDesignGraph(); hegyi@160: hegyi@172: ///Show whether the graph is already drawn. hegyi@172: bool is_drawn; hegyi@172: hegyi@21: private: hegyi@14: ///Deletes the given element. alpar@62: void deleteItem(Node); hegyi@14: ///Deletes the given element. alpar@62: void deleteItem(Edge); hegyi@9: hegyi@21: private: hegyi@21: ladanyi@6: ///Map of nodes of graph ladanyi@6: Graph::NodeMap nodesmap; ladanyi@6: ladanyi@6: ///Map of edges of graph ladanyi@147: Graph::EdgeMap edgesmap; ladanyi@6: ladanyi@6: ///Map of texts to write on edges ladanyi@6: Graph::EdgeMap edgetextmap; ladanyi@6: hegyi@28: ///Map of texts to write on nodes hegyi@28: Graph::NodeMap nodetextmap; hegyi@28: ladanyi@6: ///Group of graphical elements of displayed_graph ladanyi@6: Gnome::Canvas::Group displayed_graph; ladanyi@6: hegyi@88: private: ladanyi@6: ///Indicates whether the button of mouse is pressed or not hegyi@20: int isbutton; ladanyi@6: hegyi@21: ///Stores the actual tool in hand hegyi@21: int actual_tool; hegyi@21: ladanyi@6: ///At this location was the mousebutton pressed. ladanyi@6: ///It helps to calculate the distance of dragging. ladanyi@6: double clicked_x, clicked_y; ladanyi@6: ladanyi@6: ///Remembers which Gnome::Canvas::Item was pressed. hegyi@118: hegyi@118: ///this variable is needed, to work on it after selection hegyi@118: Gnome::Canvas::Item * active_item; hegyi@118: hegyi@118: ///Remembers which Gnome::Canvas::Item was pressed. hegyi@118: hegyi@118: ///this variable is used at edge creation, it will hegyi@118: ///be the secondly selected node. No local variable hegyi@118: ///can be used for this purpose inside the function, hegyi@118: ///because the node selected by button press, and hegyi@118: ///the edge is created by button release. Both of hegyi@118: ///them is different function call. hegyi@118: Gnome::Canvas::Item * target_item; hegyi@118: hegyi@118: ///selected node (for any editing) alpar@62: Node active_node; hegyi@118: hegyi@118: ///selected edge (for any editing) alpar@62: Edge active_edge; hegyi@118: hegyi@118: ///the edge that is selected by clicking on the red arrow in the middle of it hegyi@118: hegyi@118: ///This edge is stored only for the purpose of reshape it. hegyi@118: ///That is why it is selected in a different manner. alpar@62: Edge forming_edge; hegyi@35: hegyi@118: ///Map displayed by label can be edited. hegyi@118: std::string nodemap_to_edit; hegyi@118: hegyi@118: ///Map displayed by label can be edited. hegyi@118: std::string edgemap_to_edit; ladanyi@6: ladanyi@6: static const int zoom_step = 5; hegyi@19: hegyi@154: ///Is node radius autoscaled hegyi@154: bool autoscale; hegyi@154: hegyi@156: ///Should we track zoomfactor changes hegyi@156: bool zoomtrack; hegyi@156: hegyi@156: ///to store the zoom factor when it was "fixed" hegyi@156: double fixed_zoom_factor; hegyi@156: hegyi@157: ///Node radius size hegyi@157: double radius_size; hegyi@154: hegyi@157: ///Edge width hegyi@157: double edge_width; hegyi@154: hegyi@166: ///Was redesign run on this graph already? hegyi@166: /// hegyi@166: ///If not, the layout will be modified randomly hegyi@166: ///to avoid frozen layout because of wrong hegyi@166: ///initial state hegyi@166: bool was_redesigned; hegyi@160: hegyi@88: private: hegyi@88: hegyi@118: ///reference to the container, in which the canvas is hegyi@96: NoteBookTab & mytab; hegyi@55: hegyi@148: XY calcArrowPos(XY, XY, XY, XY, int); ladanyi@184: ladanyi@184: bool background_set; ladanyi@184: Glib::RefPtr refBackground; ladanyi@184: Gnome::Canvas::Pixbuf *background; ladanyi@184: public: ladanyi@184: void setBackground(); ladanyi@6: }; ladanyi@6: ladanyi@6: #endif //GRAPH_DISPLAYER_CANVAS_H