1 /* 2 * Copyright 2012-2014 Thomas Schöps 3 * Copyright 2013-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 22 #ifndef OPENORIENTEERING_DRAW_PATH_H 23 #define OPENORIENTEERING_DRAW_PATH_H 24 25 #include <memory> 26 27 #include <QtGlobal> 28 #include <QObject> 29 #include <QPoint> 30 #include <QPointer> 31 #include <QString> 32 33 #include "core/map_coord.h" 34 #include "tools/draw_line_and_area_tool.h" 35 36 class QAction; 37 class QCursor; 38 class QKeyEvent; 39 class QMouseEvent; 40 class QPainter; 41 class QToolButton; 42 43 namespace OpenOrienteering { 44 45 class AzimuthInfoHelper; 46 class ConstrainAngleToolHelper; 47 class FollowPathToolHelper; 48 class KeyButtonBar; 49 class MapEditorController; 50 class MapWidget; 51 class PathObject; 52 class SnappingToolHelper; 53 class SnappingToolHelperSnapInfo; 54 class Symbol; 55 56 57 /** 58 * Tool to draw arbitrarily shaped PathObjects. 59 */ 60 class DrawPathTool : public DrawLineAndAreaTool 61 { 62 Q_OBJECT 63 public: 64 DrawPathTool(MapEditorController* editor, QAction* tool_action, bool is_helper_tool, bool allow_closing_paths); 65 ~DrawPathTool() override; 66 67 void init() override; 68 const QCursor& getCursor() const override; 69 70 bool mousePressEvent(QMouseEvent* event, const MapCoordF& map_coord, MapWidget* widget) override; 71 bool mouseMoveEvent(QMouseEvent* event, const MapCoordF& map_coord, MapWidget* widget) override; 72 bool mouseReleaseEvent(QMouseEvent* event, const MapCoordF& map_coord, MapWidget* widget) override; 73 bool mouseDoubleClickEvent(QMouseEvent* event, const MapCoordF& map_coord, MapWidget* widget) override; 74 75 bool keyPressEvent(QKeyEvent* event) override; 76 bool keyReleaseEvent(QKeyEvent* event) override; 77 78 void draw(QPainter* painter, MapWidget* widget) override; 79 80 protected slots: 81 void updateDirtyRect(); 82 void setDrawingSymbol(const OpenOrienteering::Symbol* symbol) override; 83 84 /** This slot listens to changes in the map's object selection. */ 85 virtual void objectSelectionChanged(); 86 87 protected: 88 void updatePreviewPath() override; 89 /** Should be called when moving the cursor without the draw button being held */ 90 void updateHover(); 91 /** Called by updateHover() if the user is currently drawing */ 92 void updateDrawHover(); 93 /** Updates the last three points of the path to form a bezier curve */ 94 void createPreviewCurve(MapCoord position, qreal direction); 95 /** Closes the preview path */ 96 void closeDrawing(); 97 void finishDrawing() override; 98 void abortDrawing() override; 99 void undoLastPoint(); 100 /** When not drawing but when the current selection is a single path, 101 * removes the last point from that path, or deletes the whole path if 102 * there are too few remaining points. 103 * Returns true if the path was modified or deleted. */ 104 bool removeLastPointFromSelectedPath(); 105 void updateAngleHelper(); 106 bool pickAngle(const MapCoordF& coord, MapWidget* widget); 107 void updateSnapHelper(); 108 109 /** Starts appending to another, existing object */ 110 void startAppending(SnappingToolHelperSnapInfo& snap_info); 111 112 /** Starts following another, existing path */ 113 void startFollowing(SnappingToolHelperSnapInfo& snap_info, const MapCoord& snap_coord); 114 void updateFollowing(); 115 void finishFollowing(); 116 117 /** 118 * Checks if the user dragged the mouse away a certain minimum distance from 119 * the click point and if yes, returns the drag angle, otherwise returns 0. 120 */ 121 qreal calculateRotation(const QPoint& mouse_pos, const MapCoordF& mouse_pos_map) const; 122 /** 123 * Activates or deactivates dash point drawing depending on if a line symbol 124 * with dash symbols is selected. 125 */ 126 void updateDashPointDrawing(); 127 void updateStatusText(); 128 129 130 QPointer<KeyButtonBar> key_button_bar; 131 QPointer<QToolButton> dash_points_button; 132 QPointer<QToolButton> azimuth_button; 133 134 MapWidget* cur_map_widget; 135 136 QPoint click_pos; 137 MapCoordF click_pos_map; 138 139 QPoint cur_pos; 140 MapCoordF cur_pos_map; 141 142 /** The beginning of the current curve in the preview path. */ 143 MapCoordF previous_pos_map; 144 /** A control point defining the tangent at the beginning of the current curve. */ 145 MapCoordF previous_drag_map; 146 147 std::unique_ptr<ConstrainAngleToolHelper> angle_helper; 148 MapCoordF constrained_pos_map; 149 150 std::unique_ptr<AzimuthInfoHelper> azimuth_helper; 151 152 std::unique_ptr<SnappingToolHelper> snap_helper; 153 154 PathObject* append_to_object; 155 156 std::unique_ptr<FollowPathToolHelper> follow_helper; 157 MapCoordVector::size_type follow_start_index; 158 159 qreal previous_point_direction = 0; 160 161 bool allow_closing_paths = true; 162 bool ctrl_pressed = false; 163 bool shift_pressed = false; 164 bool left_mouse_down = false; 165 bool appending = false; 166 bool following = false; 167 bool picking_angle = false; ///< Indicates picking of the initial angle from an object. 168 bool picked_angle = false; ///< Indicates an active angle picked from another object. 169 bool dragging = false; 170 bool draw_dash_points = false; 171 bool create_segment = false; 172 bool create_spline_corner = false; ///< For drawing bezier splines without parallel handles 173 bool path_has_preview_point = false; 174 bool previous_point_is_curve_point = false; 175 bool created_point_at_last_mouse_press = false; ///< Used for finishing on double click. 176 bool finished_path_is_selected = false; ///< True just after finishing a path 177 178 }; 179 180 181 } // namespace OpenOrienteering 182 183 #endif 184