Context for the "About" label
[inkscape.git] / src / ui / tool / control-point.h
blob43ef623c1ab9207f6b4a810fe33bab91a6d99a46
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* Authors:
3 * Krzysztof KosiƄski <tweenk.pl@gmail.com>
4 * Jon A. Cruz <jon@joncruz.org>
6 * Copyright (C) 2012 Authors
7 * Copyright (C) 2009 Authors
8 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
9 */
11 #ifndef INKSCAPE_UI_TOOL_CONTROL_POINT_H
12 #define INKSCAPE_UI_TOOL_CONTROL_POINT_H
14 #include <cstddef>
15 #include <boost/noncopyable.hpp>
16 #include <gdkmm/pixbuf.h>
17 #include <sigc++/signal.h>
18 #include <sigc++/trackable.h>
20 #include <2geom/point.h>
22 #include "display/control/canvas-item-ctrl.h"
23 #include "display/control/canvas-item-enums.h"
24 #include "display/control/canvas-item-ptr.h"
25 #include "enums.h" // TEMP TEMP
26 #include <sigc++/scoped_connection.h>
28 class SPDesktop;
30 namespace Inkscape { struct MotionEvent; struct ButtonReleaseEvent; }
32 namespace Inkscape::UI {
34 namespace Tools { class ToolBase; }
36 /**
37 * Draggable point, the workhorse of on-canvas editing.
39 * Control points (formerly known as knots) are graphical representations of some significant
40 * point in the drawing. The drawing can be changed by dragging the point and the things that are
41 * attached to it with the mouse. Example things that could be edited with draggable points
42 * are gradient stops, the place where text is attached to a path, text kerns, nodes and handles
43 * in a path, and many more.
45 * @par Control point event handlers
46 * @par
47 * The control point has several virtual methods which allow you to react to things that
48 * happen to it. The most important ones are the grabbed, dragged, ungrabbed and moved functions.
49 * When a drag happens, the order of calls is as follows:
50 * - <tt>grabbed()</tt>
51 * - <tt>dragged()</tt>
52 * - <tt>dragged()</tt>
53 * - <tt>dragged()</tt>
54 * - ...
55 * - <tt>dragged()</tt>
56 * - <tt>ungrabbed()</tt>
58 * The control point can also respond to clicks and double clicks. On a double click,
59 * clicked() is called, followed by doubleclicked(). When deriving from SelectableControlPoint,
60 * you need to manually call the superclass version at the appropriate point in your handler.
62 * @par Which method to override?
63 * @par
64 * You might wonder which hook to use when you want to do things when the point is relocated.
65 * Here are some tips:
66 * - If the point is used to edit an object, override the move() method.
67 * - If the point can usually be dragged wherever you like but can optionally be constrained
68 * to axes or the like, add a handler for <tt>signal_dragged</tt> that modifies its new
69 * position argument.
70 * - If the point has additional canvas items tied to it (like handle lines), override
71 * the setPosition() method.
73 class ControlPoint
74 : boost::noncopyable
75 , public sigc::trackable
77 public:
78 /**
79 * Enumeration representing the possible states of the control point, used to determine
80 * its appearance.
82 * @todo resolve this to be in sync with the five standard GTK states.
84 enum State
86 /** Normal state. */
87 STATE_NORMAL,
89 /** Mouse is hovering over the control point. */
90 STATE_MOUSEOVER,
92 /** First mouse button pressed over the control point. */
93 STATE_CLICKED
96 virtual ~ControlPoint();
98 ControlPoint (ControlPoint const &other) = delete;
99 void operator=(ControlPoint const &other) = delete;
101 /// @name Adjust the position of the control point
102 /// @{
103 /** Current position of the control point. */
104 Geom::Point const &position() const { return _position; }
107 * Move the control point to new position with side effects.
108 * This is called after each drag. Override this method if only some positions make sense
109 * for a control point (like a point that must always be on a path and can't modify it),
110 * or when moving a control point changes the positions of other points.
112 virtual void move(Geom::Point const &pos);
115 * Relocate the control point without side effects.
116 * Overload this method only if there is an additional graphical representation
117 * that must be updated (like the lines that connect handles to nodes). If you override it,
118 * you must also call the superclass implementation of the method.
119 * @todo Investigate whether this method should be protected
121 virtual void setPosition(Geom::Point const &pos);
124 * Apply an arbitrary affine transformation to a control point. This is used
125 * by ControlPointSelection, and is important for things like nodes with handles.
126 * The default implementation simply moves the point according to the transform.
128 virtual void transform(Geom::Affine const &m);
131 * Apply any node repairs, by default no fixing is applied but Nodes will update
132 * smooth nodes to make sure nodes are kept consistent.
134 virtual void fixNeighbors() {};
136 /// @}
138 /// @name Toggle the point's visibility
139 /// @{
140 bool visible() const;
143 * Set the visibility of the control point. An invisible point is not drawn on the canvas
144 * and cannot receive any events.
146 virtual void setVisible(bool v);
147 /// @}
149 /// @name Transfer grab from another event handler
150 /// @{
152 * Transfer the grab to another point. This method allows one to create a draggable point
153 * that should be dragged instead of the one that received the grabbed signal.
154 * This is used to implement dragging out handles in the new node tool, for example.
156 * This method will NOT emit the ungrab signal of @c prev_point, because this would complicate
157 * using it with selectable control points. If you use this method while dragging, you must emit
158 * the ungrab signal yourself.
160 * Note that this will break horribly if you try to transfer grab between points in different
161 * desktops, which doesn't make much sense anyway.
163 void transferGrab(ControlPoint *from, MotionEvent const &event);
164 /// @}
166 /// @name Inspect the state of the control point
167 /// @{
168 State state() const { return _state; }
170 bool mouseovered() const { return this == mouseovered_point; }
171 /// @}
173 /** Holds the currently mouseovered control point. */
174 static ControlPoint *mouseovered_point;
177 * Emitted when the mouseovered point changes. The parameter is the new mouseovered point.
178 * When a point ceases to be mouseovered, the parameter will be NULL.
180 static sigc::signal<void (ControlPoint*)> signal_mouseover_change;
182 static Glib::ustring format_tip(char const *format, ...) G_GNUC_PRINTF(1,2);
184 // temporarily public, until snap delay is refactored a little
185 virtual bool _eventHandler(Inkscape::UI::Tools::ToolBase *event_context, CanvasEvent const &event);
186 SPDesktop *const _desktop; ///< The desktop this control point resides on.
188 bool doubleClicked() const { return _double_clicked; }
190 // make handle look like "selected" one without participating in selection
191 void set_selected_appearance(bool selected);
193 protected:
195 * Create a regular control point.
196 * Derive to have constructors with a reasonable number of parameters.
198 * @param d Desktop for this control
199 * @param initial_pos Initial position of the control point in desktop coordinates
200 * @param anchor Where is the control point rendered relative to its desktop coordinates
201 * @param type Logical type of the control point.
202 * @param group The canvas group the point's canvas item should be created in
204 ControlPoint(SPDesktop *d, Geom::Point const &initial_pos, SPAnchorType anchor,
205 Inkscape::CanvasItemCtrlType type,
206 Inkscape::CanvasItemGroup *group = nullptr);
208 /// @name Handle control point events in subclasses
209 /// @{
211 * Called when the user moves the point beyond the drag tolerance with the first button held
212 * down.
214 * @param event Motion event when drag tolerance was exceeded.
215 * @return true if you called transferGrab() during this method.
217 virtual bool grabbed(MotionEvent const &event);
220 * Called while dragging, but before moving the knot to new position.
222 * @param pos Old position, always equal to position()
223 * @param new_pos New position (after drag). This is passed as a non-const reference,
224 * so you can change it from the handler - that's how constrained dragging is implemented.
225 * @param event Motion event.
227 virtual void dragged(Geom::Point &new_pos, MotionEvent const &event);
230 * Called when the control point finishes a drag.
232 * @param event Button release event
234 virtual void ungrabbed(ButtonReleaseEvent const *event);
237 * Called when the control point is clicked, at mouse button release.
238 * Improperly implementing this method can cause the default context menu not to appear when a control
239 * point is right-clicked.
241 * @param event Button release event
242 * @return true if the click had some effect, false if it did nothing.
244 virtual bool clicked(ButtonReleaseEvent const &event);
247 * Called when the control point is doubleclicked, at mouse button release.
249 * @param event Button release event
251 virtual bool doubleclicked(ButtonReleaseEvent const &event);
252 /// @}
254 /// @name Manipulate the control point's appearance in subclasses
255 /// @{
258 * Change the state of the knot.
259 * Alters the appearance of the knot to match one of the states: normal, mouseover
260 * or clicked.
262 virtual void _setState(State state);
264 void _handleControlStyling();
266 void _setSize(unsigned int size);
267 void _setControlType(Inkscape::CanvasItemCtrlType type);
268 void _setAnchor(SPAnchorType anchor);
270 virtual Glib::ustring _getTip(unsigned /*state*/) const { return ""; }
271 virtual Glib::ustring _getDragTip(MotionEvent const &event) const { return ""; }
272 virtual bool _hasDragTips() const { return false; }
274 CanvasItemPtr<Inkscape::CanvasItemCtrl> _canvas_item_ctrl; ///< Visual representation of the control point.
276 State _state = STATE_NORMAL;
278 static Geom::Point const &_last_click_event_point() { return _drag_event_origin; }
279 static Geom::Point const &_last_drag_origin() { return _drag_origin; }
281 static bool _is_drag_cancelled(MotionEvent const &event);
283 static bool _drag_initiated;
285 private:
286 static void _setMouseover(ControlPoint *, unsigned state);
287 static void _clearMouseover();
289 bool _updateTip(unsigned state);
290 bool _updateDragTip(MotionEvent const &event);
292 void _setDefaultColors();
294 void _commonInit();
296 Geom::Point _position; ///< Current position in desktop coordinates
298 sigc::scoped_connection _event_handler_connection;
300 /** Stores the window point over which the cursor was during the last mouse button press. */
301 static Geom::Point _drag_event_origin;
302 /** Stores the desktop point from which the last drag was initiated. */
303 static Geom::Point _drag_origin;
304 static bool _event_grab;
306 bool _double_clicked = false;
307 bool _selected_appearance = false;
310 } // namespace Inkscape::UI
312 #endif // INKSCAPE_UI_TOOL_CONTROL_POINT_H
315 Local Variables:
316 mode:c++
317 c-file-style:"stroustrup"
318 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
319 indent-tabs-mode:nil
320 fill-column:99
321 End:
323 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :