1 // SPDX-License-Identifier: LGPL-2.1-or-later 2 // 3 // SPDX-FileCopyrightText: 2014 Calin Cruceru <crucerucalincristian@gmail.com> 4 // 5 6 #ifndef POLYLINEANNOTATION_H 7 #define POLYLINEANNOTATION_H 8 9 #include <QColor> 10 #include <QPointer> 11 12 #include "SceneGraphicsItem.h" 13 #include "GeoDataCoordinates.h" 14 15 16 namespace Marble 17 { 18 19 class PolylineNode; 20 class MergingPolylineNodesAnimation; 21 22 class PolylineAnnotation : public SceneGraphicsItem 23 { 24 friend class MergingPolylineNodesAnimation; 25 26 public: 27 explicit PolylineAnnotation( GeoDataPlacemark *placemark ); 28 ~PolylineAnnotation() override; 29 30 /** 31 * @brief Paints the nodes on the screen and updates the regions which correspond 32 * to each node using the given GeoPainter. 33 */ 34 void paint( GeoPainter *painter, const ViewportParams *viewport, const QString &layer , int tileZoomLevel) override; 35 36 /** 37 * @brief Returns true if either the polyline's associated region or one of its nodes 38 * contains the given QPoint. Note that the return value depends on the state. 39 */ 40 bool containsPoint( const QPoint &eventPos ) const override; 41 42 /** 43 * @brief It is used so far to remove the hover effect while being in the 44 * AddingPolylineNodes state (@see SceneGraphicsItem::dealWithItemChange documentation). 45 */ 46 void dealWithItemChange( const SceneGraphicsItem *other ) override; 47 48 /** 49 * @brief Moves the whole polyline to the destination point. 50 */ 51 void move( const GeoDataCoordinates &source, const GeoDataCoordinates &destination ) override; 52 53 /** 54 * @brief Changes the busy state of the object according to @p enabled. It is mostly used 55 * by Annotate Plugin to not send events to this object anymore but is different than the 56 * focus property (you can have a focused polyline which does not accept events because is 57 * busy). 58 */ 59 void setBusy( bool enabled ); 60 61 /** 62 * @brief Returns whether the annotation is 'busy' or not - this usually means that something 63 * is being performed and it does not accept events anymore. 64 */ 65 bool isBusy() const; 66 67 /** 68 * @brief Iterates through all nodes which form the polyline and sets the IsSelected flag to 69 * false. 70 */ 71 void deselectAllNodes(); 72 73 /** 74 * @brief Iterates through all nodes which form the polyline and deletes the selected ones. 75 */ 76 void deleteAllSelectedNodes(); 77 78 /** 79 * @brief Deletes the last clicked node while being in the Editing state. 80 */ 81 void deleteClickedNode(); 82 83 /** 84 * @brief If the last clicked node is selected, set its IsSelected flag to false and 85 * vice versa. 86 */ 87 void changeClickedNodeSelection(); 88 89 /** 90 * @brief Tests if there are any selected nodes. 91 */ 92 bool hasNodesSelected() const; 93 94 /** 95 * @brief Tests if the last clicked node is selected. 96 */ 97 bool clickedNodeIsSelected() const; 98 99 /** 100 * @brief Returns the animation to be handled by a QObject which can connect signals 101 * and slots. 102 */ 103 QPointer<MergingPolylineNodesAnimation> animation(); 104 105 /** 106 * @brief Provides information for downcasting a SceneGraphicsItem. 107 */ 108 const char *graphicType() const override; 109 110 protected: 111 /** 112 * @brief Protected methods which handle mouse events and are called by 113 * SceneGraphicsItem::sceneEvent() (@see Template Method pattern). Each of these 114 * event handlers are structured according to the state. 115 */ 116 bool mousePressEvent( QMouseEvent *event ) override; 117 bool mouseMoveEvent( QMouseEvent *event ) override; 118 bool mouseReleaseEvent( QMouseEvent *event ) override; 119 120 void dealWithStateChange( SceneGraphicsItem::ActionState previousState ) override; 121 122 private: 123 /** 124 * @brief It is called when the ::paint method is called for the first time. It 125 * initializes the m_nodesList by creating the PolylineNodes. 126 * @see updateRegions() method for more detailed explanation. 127 */ 128 void setupRegionsLists( GeoPainter *painter ); 129 130 /** 131 * @brief As briefly mentioned above, the PolylineNodes instances are not created at 132 * each ::paint call, but only at its first call. Every time the ::paint method is 133 * called after that, each node from the lists of PolylineNodes gets its setRegion() 134 * method called. We need the GeoPainter for doing this because we have to get the 135 * ellipse around the GeoDataCoordinates. 136 */ 137 void updateRegions( GeoPainter *painter ); 138 139 /** 140 * @brief It iterates through all nodes and paints them on the map. It takes into 141 * consideration the active flags of each PolylineNode. 142 */ 143 void drawNodes( GeoPainter *painter ); 144 145 /** 146 * @brief Tests if the polyline's nodes contain the given point and in case they do, it 147 * returns the index of the first one. 148 */ 149 int nodeContains( const QPoint &point ) const; 150 151 /** 152 * @brief Tests if the polyline's virtual nodes contain the given point and in case they 153 * do, it returns the index of the first one. 154 */ 155 int virtualNodeContains( const QPoint &point ) const; 156 157 /** 158 * @brief Returns true/false on how the polyline (its 'lines' excepting its nodes) contain 159 * the given point or not. 160 */ 161 bool polylineContains( const QPoint &point ) const; 162 163 /** 164 * @brief It is called from processOnMove functions and deals with polylines 165 * hovering. 166 */ 167 bool dealWithHovering( QMouseEvent *mouseEvent ); 168 169 /** 170 * @brief Each state has its corresponding event handler, since in each state the 171 * item may behave differently. These are the event handlers for the Editing state. 172 */ 173 bool processEditingOnPress( QMouseEvent *mouseEvent ); 174 bool processEditingOnMove( QMouseEvent *mouseEvent ); 175 bool processEditingOnRelease( QMouseEvent *mouseEvent ); 176 177 /** 178 * @brief These are the event handlers for the MergingPolylineNodes state. 179 */ 180 bool processMergingOnPress( QMouseEvent *mouseEvent ); 181 bool processMergingOnMove( QMouseEvent *mouseEvent ); 182 static bool processMergingOnRelease(QMouseEvent *mouseEvent); 183 184 /** 185 * @brief These are the event handlers for the AddingPolylineNodes state. 186 */ 187 bool processAddingNodesOnPress( QMouseEvent *mouseEvent ); 188 bool processAddingNodesOnMove( QMouseEvent *mouseEvent ); 189 bool processAddingNodesOnRelease( QMouseEvent *mouseEvent ); 190 191 192 193 /** 194 * @brief Since they are used in many functions, the size and color of nodes for each 195 * state are static and have class scope. 196 */ 197 static const int regularDim; 198 static const int selectedDim; 199 static const int mergedDim; 200 static const int hoveredDim; 201 static const QColor regularColor; 202 static const QColor mergedColor; 203 204 const ViewportParams *m_viewport; 205 bool m_regionsInitialized; 206 bool m_busy; 207 208 QVector<PolylineNode> m_nodesList; 209 QVector<PolylineNode> m_virtualNodesList; 210 QRegion m_polylineRegion; 211 212 // Used in Editing state 213 enum EditingInteractingObject { 214 InteractingNothing, // e.g. when hovering 215 InteractingNode, 216 InteractingPolyline 217 }; 218 EditingInteractingObject m_interactingObj; 219 GeoDataCoordinates m_movedPointCoords; 220 int m_clickedNodeIndex; 221 int m_hoveredNodeIndex; 222 223 // Used in Merging Nodes state 224 QPointer<MergingPolylineNodesAnimation> m_animation; 225 int m_firstMergedNode; 226 int m_secondMergedNode; 227 228 // Used in Adding Nodes state 229 int m_virtualHoveredNode; 230 int m_adjustedNode; 231 }; 232 233 } 234 235 #endif 236