Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
curve-drag-point.cpp
Go to the documentation of this file.
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>
5 *
6 * Copyright (C) 2009 Authors
7 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
8 */
9
11#include <glib/gi18n.h>
12#include "desktop.h"
17
18#include "object/sp-namedview.h"
19
20namespace Inkscape {
21namespace UI {
22
23
26
28 ControlPoint(pm._multi_path_manipulator._path_data.node_data.desktop, Geom::Point(), SP_ANCHOR_CENTER,
30 pm._multi_path_manipulator._path_data.dragpoint_group),
31 _pm(pm)
32{
33 _canvas_item_ctrl->set_name("CanvasItemCtrl:CurveDragPoint");
34 setVisible(false);
35}
36
38{
39 // do not process any events when the manipulator is empty
40 if (_pm.empty()) {
41 setVisible(false);
42 return false;
43 }
44 return ControlPoint::_eventHandler(event_context, event);
45}
46
48{
50 NodeList::iterator second = first.next();
51
52 // move the handles to 1/3 the length of the segment for line segments
53 if (first->front()->isDegenerate() && second->back()->isDegenerate()) {
55
56 // delta is a vector equal 1/3 of distance from first to second
57 Geom::Point delta = (second->position() - first->position()) / 3.0;
58 // only update the nodes if the mode is bspline
59 if (!_pm._isBSpline()) {
60 first->front()->move(first->front()->position() + delta);
61 second->back()->move(second->back()->position() - delta);
62 }
63 _pm.update();
64 } else {
66 }
67 return false;
68}
69
71{
72 if (!first || !first.next()) return;
73 NodeList::iterator second = first.next();
74
75 // special cancel handling - retract handles when if the segment was degenerate
77 first->front()->retract();
78 second->back()->retract();
79 _pm.update();
80 return;
81 }
82
83 if (_drag_initiated && !(event.modifiers & GDK_SHIFT_MASK)) {
85 SPItem *path = static_cast<SPItem *>(_pm._path);
86 m.setup(_desktop, true, path); // We will not try to snap to "path" itself
88 Inkscape::SnappedPoint sp = m.freeSnap(scp, Geom::OptRect(), false);
89 new_pos = sp.getPoint();
90 m.unSetup();
91 }
92
93 // Magic Bezier Drag Equations follow!
94 // "weight" describes how the influence of the drag should be distributed
95 // among the handles; 0 = front handle only, 1 = back handle only.
96 double weight, t = _t;
97 if (t <= 1.0 / 6.0) weight = 0;
98 else if (t <= 0.5) weight = (pow((6 * t - 1) / 2.0, 3)) / 2;
99 else if (t <= 5.0 / 6.0) weight = (1 - pow((6 * (1-t) - 1) / 2.0, 3)) / 2 + 0.5;
100 else weight = 1;
101
102 Geom::Point delta = new_pos - position();
103 Geom::Point offset0 = ((1-weight)/(3*t*(1-t)*(1-t))) * delta;
104 Geom::Point offset1 = (weight/(3*t*t*(1-t))) * delta;
105
106 //modified so that, if the trace is bspline, it only acts if the SHIFT key is pressed
107 if (!_pm._isBSpline()) {
108 first->front()->move(first->front()->position() + offset0);
109 second->back()->move(second->back()->position() + offset1);
110 } else if (weight >= 0.8) {
111 if (mod_shift(event)) {
112 second->back()->move(new_pos);
113 } else {
114 second->move(second->position() + delta);
115 }
116 } else if (weight <= 0.2) {
117 if (mod_shift(event)) {
118 first->back()->move(new_pos);
119 } else {
120 first->move(first->position() + delta);
121 }
122 } else {
123 first->move(first->position() + delta);
124 second->move(second->position() + delta);
125 }
126 _pm.update();
127}
128
135
137{
138 // This check is probably redundant
139 if (!first || event.button != 1) return false;
140 // the next iterator can be invalid if we click very near the end of path
141 NodeList::iterator second = first.next();
142 if (!second) return false;
143
144 // insert nodes on Ctrl+Alt+click
145 if (mod_ctrl(event) && mod_alt(event)) {
146 _insertNode(false);
147 return true;
148 }
149
150 if (mod_shift(event)) {
151 // if both nodes of the segment are selected, deselect;
152 // otherwise add to selection
153 if (first->selected() && second->selected()) {
155 _pm._selection.erase(second.ptr());
156 } else {
158 _pm._selection.insert(second.ptr());
159 }
160 } else {
161 // without Shift, take selection
163 _pm._selection.insert(first.ptr(), false, false);
164 _pm._selection.insert(second.ptr());
165 }
166 return true;
167}
168
170{
171 if (event.button != 1 || !first || !first.next()) return false;
172 if (mod_ctrl(event)) {
174 _pm.update(true);
175 _pm._commit(_("Remove segment"));
176 } else if (mod_alt(event)) {
178 _pm.update(true);
179 _pm._commit(_("Straighten segments"));
180 } else {
182 _insertNode(true);
183 }
184 return true;
185}
186
187void CurveDragPoint::_insertNode(bool take_selection)
188{
189 // The purpose of this call is to make way for the just created node.
190 // Otherwise clicks on the new node would only work after the user moves the mouse a bit.
191 // PathManipulator will restore visibility when necessary.
192 setVisible(false);
193
194 _pm.insertNode(first, _t, take_selection);
195}
196
197Glib::ustring CurveDragPoint::_getTip(unsigned state) const
198{
199 if (_pm.empty()) return "";
200 if (!first || !first.next()) return "";
201 bool linear = first->front()->isDegenerate() && first.next()->back()->isDegenerate();
202 if (mod_shift(state) && _pm._isBSpline()) {
203 return C_("Path segment tip",
204 "<b>Shift</b>: drag to open or move BSpline handles");
205 }
206 if (mod_shift(state)) {
207 return C_("Path segment tip",
208 "<b>Shift</b>: click to toggle segment selection");
209 }
210 if (mod_ctrl(state) && mod_alt(state)) {
211 return C_("Path segment tip",
212 "<b>Ctrl+Alt</b>: click to insert a node");
213 }
214 if (mod_alt(state)) {
215 return C_("Path segment tip", "<b>Alt</b>: double click to change line type");
216 }
217 if (_pm._isBSpline()) {
218 return C_("Path segment tip", "<b>BSpline segment</b>: drag to shape the segment, doubleclick to insert node, "
219 "click to select (more: Alt, Shift, Ctrl+Alt)");
220 }
221 if (linear) {
222 return C_("Path segment tip", "<b>Linear segment</b>: drag to convert to a Bezier segment, "
223 "doubleclick to insert node, click to select (more: Alt, Shift, Ctrl+Alt)");
224 } else {
225 return C_("Path segment tip", "<b>Bezier segment</b>: drag to shape the segment, doubleclick to insert node, "
226 "click to select (more: Alt, Shift, Ctrl+Alt)");
227 }
228}
229
230} // namespace UI
231} // namespace Inkscape
232
233/*
234 Local Variables:
235 mode:c++
236 c-file-style:"stroustrup"
237 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
238 indent-tabs-mode:nil
239 fill-column:99
240 End:
241*/
242// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
pair< double, double > Point
Definition parser.cpp:7
Axis-aligned rectangle that can be empty.
Definition rect.h:203
Two-dimensional point that doubles as a vector.
Definition point.h:66
Class to store data for points which are snap candidates, either as a source or as a target.
Class describing the result of an attempt to snap.
Geom::Point getPoint() const
std::pair< iterator, bool > insert(const value_type &x, bool notify=true, bool to_update=true)
Add a control point to the selection.
void erase(iterator pos, bool to_update=true)
Remove a point from the selection.
void clear()
Remove all points from the selection, making it empty.
Draggable point, the workhorse of on-canvas editing.
Geom::Point const & position() const
Current position of the control point.
static bool _is_drag_cancelled(MotionEvent const &event)
virtual void setVisible(bool v)
Set the visibility of the control point.
SPDesktop *const _desktop
The desktop this control point resides on.
static Glib::ustring virtual bool _eventHandler(Inkscape::UI::Tools::ToolBase *event_context, CanvasEvent const &event)
CanvasItemPtr< Inkscape::CanvasItemCtrl > _canvas_item_ctrl
Visual representation of the control point.
CurveDragPoint(PathManipulator &pm)
void _insertNode(bool take_selection)
bool grabbed(MotionEvent const &) override
Called when the user moves the point beyond the drag tolerance with the first button held down.
bool clicked(ButtonReleaseEvent const &) override
Called when the control point is clicked, at mouse button release.
void ungrabbed(ButtonReleaseEvent const *) override
Called when the control point finishes a drag.
bool doubleclicked(ButtonReleaseEvent const &) override
Called when the control point is doubleclicked, at mouse button release.
void dragged(Geom::Point &, MotionEvent const &) override
Called while dragging, but before moving the knot to new position.
bool _eventHandler(Inkscape::UI::Tools::ToolBase *event_context, CanvasEvent const &event) override
Glib::ustring _getTip(unsigned state) const override
self next() const
Definition node.h:311
Manipulator that edits a single path using nodes with handles.
void update(bool alert_LPE=false)
Update the display and the outline of the path.
void setSegmentType(SegmentType)
Make selected segments curves / lines.
Geom::Coord _updateDragPoint(Geom::Point const &)
Update the position of the curve drag point such that it is over the nearest point of the path.
void _commit(Glib::ustring const &annotation)
Update the XML representation and put the specified annotation on the undo stack.
bool empty()
Check whether the manipulator has any nodes.
SPObject * _path
can be an SPPath or an Inkscape::LivePathEffect::Effect !!!
ControlPointSelection & _selection
Definition manipulator.h:70
Base class for Event processors.
Definition tool-base.h:107
Geom::Affine const & d2w() const
Transformation from desktop to window coordinates.
Definition desktop.h:419
SPNamedView * getNamedView() const
Definition desktop.h:191
Base class for visual SVG elements.
Definition sp-item.h:109
SnapManager snap_manager
Control point selection - stores a set of control points and applies transformations to them.
Editable view implementation.
@ SP_ANCHOR_CENTER
Definition enums.h:28
Multi path manipulator - a tool component that edits multiple paths at once.
Various utility functions.
Definition affine.h:22
@ SEGMENT_STRAIGHT
Straight linear segment.
Definition node-types.h:31
Helper class to stream background task notifications as a series of messages.
bool mod_alt(unsigned modifiers)
@ SNAPSOURCE_OTHER_HANDLE
Definition snap-enums.h:56
bool mod_ctrl(unsigned modifiers)
@ CANVAS_ITEM_CTRL_TYPE_INVISIPOINT
bool mod_shift(unsigned modifiers)
Path manipulator - a component that edits a single path on-canvas.
unsigned long weight
Definition quantize.cpp:37
Linear linear(double ax, double b)
unsigned button
The button that was pressed/released. (Matches GDK_BUTTON_*.)
A mouse button (left/right/middle) is released.
Abstract base class for events.
unsigned modifiers
The modifiers mask immediately before the event.
Movement of the mouse pointer.
int delta
SPDesktop * desktop