1 /*
2  *    Copyright 2012, 2013 Thomas Schöps
3  *    Copyright 2015-2017 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 #ifndef OPENORIENTEERING_EDIT_TOOL_H
22 #define OPENORIENTEERING_EDIT_TOOL_H
23 
24 #include <utility>
25 #include <vector>
26 
27 #include <Qt>
28 #include <QFlags>
29 #include <QObject>
30 #include <QPointF>
31 #include <QRectF>
32 #include <QRgb>
33 #include <QScopedPointer>
34 #include <QString>
35 
36 #include "core/map_coord.h"
37 #include "tools/tool.h"
38 #include "tools/tool_base.h"
39 
40 class QAction;
41 class QPainter;
42 class QPointF;
43 class QRectF;
44 
45 namespace OpenOrienteering {
46 
47 class MapEditorController;
48 class MapWidget;
49 class Object;
50 class ObjectSelector;
51 
52 using SelectionInfoVector = std::vector<std::pair<int, Object*>>;
53 
54 
55 /**
56  * Base class for object editing tools.
57  */
58 class EditTool : public MapEditorToolBase
59 {
60 public:
61 	/**
62 	 * @brief A type for general information on what is hovered over.
63 	 */
64 	enum HoverFlag
65 	{
66 		OverNothing      = 0,
67 		OverFrame        = 1,
68 		OverObjectNode   = 2,
69 		OverPathEdge     = 4,
70 	};
71 	Q_DECLARE_FLAGS(HoverState, HoverFlag)
72 
73 Q_OBJECT
74 public:
75 	EditTool(MapEditorController* editor, MapEditorTool::Type type, QAction* tool_action);
76 
77 	~EditTool() override;
78 
79 	/**
80 	 * The platform's key for deleting selected objects.
81 	 *
82 	 * OS X use the backspace key for deleting selected objects,
83 	 * while other platforms use the delete key.
84 	 *
85 	 * This causes translation issues and inconsistent behaviour on OS X:
86 	 * - In Finder, moving an object to trash is Cmd+Backspace.
87 	 * - Other programs are reported to use [forward] delete.
88 	 * - Some programs are reported to support multiple keys,
89 	 *   e.g. Delete and Backspace.
90 	 * - A major source of irritation is the absence of a delete key on some
91 	 *   Macbooks. On these keyboards, delete is entered as Fn+Backspace.
92 	 * - Some programs use another key for delete, e.g. "x".
93 	 *   (Note that Cmd-x (aka Cut) will have a similar effect.)
94 	 *
95 	 * \todo Either use a function for testing whether a key means
96 	 *       "delete object", or switch to a QAction based implementation
97 	 *       since QAction supports alternative QKeySequences.
98 	 */
99 #ifdef Q_OS_MACOS
100 	static constexpr Qt::Key DeleteObjectKey = Qt::Key_Backspace;
101 #else
102 	static constexpr Qt::Key DeleteObjectKey = Qt::Key_Delete;
103 #endif
104 
105 protected:
106 	/**
107 	 * Deletes all selected objects and updates the status text.
108 	 */
109 	void deleteSelectedObjects();
110 
111 	/**
112 	 * Creates a replace object undo step for the given object.
113 	 */
114 	void createReplaceUndoStep(Object* object);
115 
116 	/**
117 	 * Returns if the point is inside the click_tolerance from the rect's border.
118 	 */
119 	bool pointOverRectangle(const QPointF& point, const QRectF& rect) const;
120 
121 	/**
122 	 * Returns the point on the rect which is closest to the given point.
123 	 */
124 	static MapCoordF closestPointOnRect(MapCoordF point, const QRectF& rect);
125 
126 	/**
127 	 * Configures the angle helper from the primary directions of the edited objects.
128 	 *
129 	 * If no primary directions are found, the default directions are set.
130 	 */
131 	void setupAngleHelperFromEditedObjects();
132 
133 	/**
134 	 * Draws a bounding box with a dashed line of the given color.
135 	 *
136 	 * @param bounding_box the box extent in map coordinates
137 	 */
138 	void drawBoundingBox(QPainter* painter, MapWidget* widget, const QRectF& bounding_box, const QRgb& color);
139 
140 	/**
141 	 * Draws a bounding path with a dashed line of the given color.
142 	 *
143 	 * @param bounding_box the box extent in map coordinates
144 	 */
145 	void drawBoundingPath(QPainter* painter, MapWidget* widget, const std::vector<QPointF>& bounding_path, const QRgb& color);
146 
147 	/**
148 	 * An utility implementing object selection logic.
149 	 */
150 	QScopedPointer<ObjectSelector> object_selector;
151 };
152 
153 
154 }  // namespace OpenOrienteering
155 
156 
157 Q_DECLARE_OPERATORS_FOR_FLAGS(OpenOrienteering::EditTool::HoverState)
158 
159 
160 #endif
161