1 /*
2  *    Copyright 2012, 2013 Thomas Schöps
3  *    Copyright 2014, 2015 Kai Pastor
4  *
5  *    This file is part of OpenOrienteering.
6  *
7  *    OpenOrienteering is free software: you can redistribute it and/or modify
8  *    it under the terms of the GNU General Public License as published by
9  *    the Free Software Foundation, either version 3 of the License, or
10  *    (at your option) any later version.
11  *
12  *    OpenOrienteering is distributed in the hope that it will be useful,
13  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *    GNU General Public License for more details.
16  *
17  *    You should have received a copy of the GNU General Public License
18  *    along with OpenOrienteering.  If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 
22 #ifndef OPENORIENTEERING_DRAW_RECTANGLE_H
23 #define OPENORIENTEERING_DRAW_RECTANGLE_H
24 
25 #include <vector>
26 
27 #include <QObject>
28 #include <QPoint>
29 #include <QString>
30 
31 #include "core/map_coord.h"
32 #include "tools/draw_line_and_area_tool.h"
33 
34 #include <QPointer>
35 #include <QScopedPointer>
36 
37 class QAction;
38 class QCursor;
39 class QKeyEvent;
40 class QMouseEvent;
41 class QPainter;
42 class QToolButton;
43 
44 namespace OpenOrienteering {
45 
46 class ConstrainAngleToolHelper;
47 class KeyButtonBar;
48 class MapEditorController;
49 class MapWidget;
50 class SnappingToolHelper;
51 
52 
53 /**
54  * Tool to draw rectangular PathObjects (but also 45 degree angles).
55  */
56 class DrawRectangleTool : public DrawLineAndAreaTool
57 {
58 Q_OBJECT
59 public:
60 	DrawRectangleTool(MapEditorController* editor, QAction* tool_action, bool is_helper_tool);
61     ~DrawRectangleTool() override;
62 
63 	void init() override;
64 	const QCursor& getCursor() const override;
65 
66 	bool mousePressEvent(QMouseEvent* event, const MapCoordF& map_coord, MapWidget* widget) override;
67 	bool mouseMoveEvent(QMouseEvent* event, const MapCoordF& map_coord, MapWidget* widget) override;
68 	bool mouseReleaseEvent(QMouseEvent* event, const MapCoordF& map_coord, MapWidget* widget) override;
69 	bool mouseDoubleClickEvent(QMouseEvent* event, const MapCoordF& map_coord, MapWidget* widget) override;
70 
71 	bool keyPressEvent(QKeyEvent* event) override;
72     bool keyReleaseEvent(QKeyEvent* event) override;
73 
74 	void draw(QPainter* painter, MapWidget* widget) override;
75 
76 protected slots:
77 	void updateDirtyRect();
78 
79 protected:
80 	void finishDrawing() override;
81 	void abortDrawing() override;
82 
83 	/**
84 	 * Deletes the last drawn point.
85 	 *
86 	 * Calls updateRectangle() which will set the than-last point
87 	 * to constrained_pos_map.
88 	 */
89 	void undoLastPoint();
90 
91 	/** Picks a direction from an existing object. */
92 	void pickDirection(const MapCoordF& coord, MapWidget* widget);
93 
94 	/** Checks if the current drawing direction is parallel to the angle. */
95 	bool drawingParallelTo(double angle) const;
96 
97 	/**
98 	 * Updates the preview after cursor position changes.
99 	 * May call updateRectangle() internally.
100 	 */
101 	void updateHover(bool mouse_down);
102 
103 	/**
104 	 * Calculates the closing vector.
105 	 *
106 	 * The "closing vector" gives the direction from the current drawing position
107 	 * perpendicular to the start point.
108 	 */
109 	MapCoordF calculateClosingVector() const;
110 
111 	/**
112 	 * Deletes all points from the preview path which were introduced to close
113 	 * it temporarily (for preview visualization).
114 	 */
115 	void deleteClosePoint();
116 
117 	/**
118 	 * Recalculates the rectangle shape based on the current input.
119 	 *
120 	 * This will set the "last" point to constrained_pos_map.
121 	 */
122 	void updateRectangle();
123 
124 	void updateStatusText();
125 
126 	QPoint click_pos;
127 	MapCoordF click_pos_map;
128 	QPoint cur_pos;
129 	MapCoordF cur_pos_map;
130 	MapCoordF constrained_pos_map;
131 	bool dragging;
132 	bool draw_dash_points = true;
133 	bool shift_pressed    = false;
134 	bool ctrl_pressed     = false;
135 	bool picked_direction = false;
136 	bool snapped_to_line  = false;
137 	MapCoord snapped_to_line_a;
138 	MapCoord snapped_to_line_b;
139 
140 	/**
141 	 * This can be set to true when a mouse button is pressed down to disable all
142 	 * actions for the next mouse button release.
143 	 */
144 	bool no_more_effect_on_click = false;
145 
146 	/**
147 	 * List of angles for first, second, etc. edge.
148 	 * Includes the currently edited angle.
149 	 * The index of currently edited point in preview_path is angles.size().
150 	 */
151 	std::vector< double > angles;
152 
153 	/** Vector in forward drawing direction */
154 	MapCoordF forward_vector;
155 
156 	QScopedPointer<ConstrainAngleToolHelper> angle_helper;
157 	QScopedPointer<SnappingToolHelper> snap_helper;
158 	MapWidget* cur_map_widget;
159 
160 	QPointer<KeyButtonBar> key_button_bar;
161 	QPointer<QToolButton> dash_points_button;
162 };
163 
164 
165 }  // namespace OpenOrienteering
166 #endif
167