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