summaryrefslogtreecommitdiffstats
path: root/src/ui/tool/path-manipulator.h
blob: ca861c6320266a8e076b05cdf6cf34a1174772e9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
// SPDX-License-Identifier: GPL-2.0-or-later
/** @file
 * Path manipulator - a component that edits a single path on-canvas
 */
/* Authors:
 *   Krzysztof Kosiński <tweenk.pl@gmail.com>
 *
 * Copyright (C) 2009 Authors
 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
 */

#ifndef SEEN_UI_TOOL_PATH_MANIPULATOR_H
#define SEEN_UI_TOOL_PATH_MANIPULATOR_H

#include <string>
#include <memory>
#include <2geom/pathvector.h>
#include <2geom/path-sink.h>
#include <2geom/affine.h>
#include "ui/tool/node.h"
#include "ui/tool/manipulator.h"
#include "live_effects/lpe-bspline.h"

struct SPCanvasItem;
class SPCurve;
class SPPath;

namespace Inkscape {

class CanvasItemBpath;

namespace XML { class Node; }

namespace UI {

class PathManipulator;
class ControlPointSelection;
class PathManipulatorObserver;
class CurveDragPoint;
class PathCanvasGroups;
class MultiPathManipulator;
class Node;
class Handle;

struct PathSharedData {
    NodeSharedData node_data;
    Inkscape::CanvasItemGroup *outline_group;
    Inkscape::CanvasItemGroup *dragpoint_group;
};

/**
 * Manipulator that edits a single path using nodes with handles.
 * Currently only cubic bezier and linear segments are supported, but this might change
 * some time in the future.
 */
class PathManipulator : public PointManipulator {
public:
    typedef SPPath *ItemType;

    PathManipulator(MultiPathManipulator &mpm, SPObject *path, Geom::Affine const &edit_trans,
        guint32 outline_color, Glib::ustring lpe_key);
    ~PathManipulator() override;
    bool event(Inkscape::UI::Tools::ToolBase *, GdkEvent *) override;

    bool empty();
    void writeXML();
    void update(bool alert_LPE = false); // update display, but don't commit
    void clear(); // remove all nodes from manipulator
    SPObject *item() { return _path; }

    void selectSubpaths();
    void invertSelectionInSubpaths();

    void insertNodeAtExtremum(ExtremumType extremum);
    void insertNodes();
    void insertNode(Geom::Point);
    void insertNode(NodeList::iterator first, double t, bool take_selection);
    void duplicateNodes();
    void copySelectedPath(Geom::PathBuilder *builder);
    void weldNodes(NodeList::iterator preserve_pos = NodeList::iterator());
    void weldSegments();
    void breakNodes();
    void deleteNodes(bool keep_shape = true);
    void deleteSegments();
    void reverseSubpaths(bool selected_only);
    void setSegmentType(SegmentType);

    void scaleHandle(Node *n, int which, int dir, bool pixel);
    void rotateHandle(Node *n, int which, int dir, bool pixel);

    void showOutline(bool show);
    void showHandles(bool show);
    void showPathDirection(bool show);
    void setLiveOutline(bool set);
    void setLiveObjects(bool set);
    void updateHandles();
    void updatePath();
    void setControlsTransform(Geom::Affine const &);
    void hideDragPoint();
    MultiPathManipulator &mpm() { return _multi_path_manipulator; }

    NodeList::iterator subdivideSegment(NodeList::iterator after, double t);
    NodeList::iterator extremeNode(NodeList::iterator origin, bool search_selected,
        bool search_unselected, bool closest);

    int _bsplineGetSteps() const;
    // this is necessary for Tab-selection in MultiPathManipulator
    SubpathList &subpathList() { return _subpaths; }

    static bool is_item_type(void *item);
private:
    typedef NodeList Subpath;
    typedef std::shared_ptr<NodeList> SubpathPtr;

    void _createControlPointsFromGeometry();

    void _recalculateIsBSpline();
    bool _isBSpline() const;
    double _bsplineHandlePosition(Handle *h, bool check_other = true);
    Geom::Point _bsplineHandleReposition(Handle *h, bool check_other = true);
    Geom::Point _bsplineHandleReposition(Handle *h, double pos);
    void _createGeometryFromControlPoints(bool alert_LPE = false);
    unsigned _deleteStretch(NodeList::iterator first, NodeList::iterator last, bool keep_shape);
    std::string _createTypeString();
    void _updateOutline();
    //void _setOutline(Geom::PathVector const &);
    void _getGeometry();
    void _setGeometry();
    Glib::ustring _nodetypesKey();
    Inkscape::XML::Node *_getXMLNode();

    void _selectionChangedM(std::vector<SelectableControlPoint *> pvec, bool selected);
    void _selectionChanged(SelectableControlPoint * p, bool selected);
    bool _nodeClicked(Node *, GdkEventButton *);
    void _handleGrabbed();
    bool _handleClicked(Handle *, GdkEventButton *);
    void _handleUngrabbed();

    void _externalChange(unsigned type);
    void _removeNodesFromSelection();
    void _commit(Glib::ustring const &annotation);
    void _commit(Glib::ustring const &annotation, gchar const *key);
    Geom::Coord _updateDragPoint(Geom::Point const &);
    void _updateOutlineOnZoomChange();
    double _getStrokeTolerance();
    Handle *_chooseHandle(Node *n, int which);

    SubpathList _subpaths;
    MultiPathManipulator &_multi_path_manipulator;
    SPObject *_path; ///< can be an SPPath or an Inkscape::LivePathEffect::Effect  !!!
    std::unique_ptr<SPCurve> _spcurve; // in item coordinates
    Inkscape::CanvasItemBpath *_outline = nullptr;
    CurveDragPoint *_dragpoint; // an invisible control point hovering over curve
    PathManipulatorObserver *_observer;
    Geom::Affine _d2i_transform; ///< desktop-to-item transform
    Geom::Affine _i2d_transform; ///< item-to-desktop transform, inverse of _d2i_transform
    Geom::Affine _edit_transform; ///< additional transform to apply to editing controls
    bool _show_handles = true;
    bool _show_outline = false;
    bool _show_path_direction = false;
    bool _live_outline = true;
    bool _live_objects = true;
    bool _is_bspline = false;
    Glib::ustring _lpe_key;

    friend class PathManipulatorObserver;
    friend class CurveDragPoint;
    friend class Node;
    friend class Handle;
};

} // namespace UI
} // namespace Inkscape

#endif

/*
  Local Variables:
  mode:c++
  c-file-style:"stroustrup"
  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
  indent-tabs-mode:nil
  fill-column:99
  End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :