summaryrefslogtreecommitdiffstats
path: root/src/ui/tool/multi-path-manipulator.h
blob: c00436c73b1c2c982c2ec6bfc353c9c8a7e00aca (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
// SPDX-License-Identifier: GPL-2.0-or-later
/** @file
 * Multi path manipulator - a tool component that edits multiple paths at once
 */
/* 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_MULTI_PATH_MANIPULATOR_H
#define SEEN_UI_TOOL_MULTI_PATH_MANIPULATOR_H

#include <cstddef>
#include <sigc++/connection.h>
#include <2geom/path-sink.h>
#include "node.h"
#include "commit-events.h"
#include "manipulator.h"
#include "modifier-tracker.h"
#include "node-types.h"
#include "shape-record.h"

struct SPCanvasGroup;

namespace Inkscape {
namespace UI {

class PathManipulator;
class MultiPathManipulator;
struct PathSharedData;

/**
 * Manipulator that manages multiple path manipulators active at the same time.
 */
class MultiPathManipulator : public PointManipulator {
public:
    MultiPathManipulator(PathSharedData &data, sigc::connection &chg);
    ~MultiPathManipulator() override;
    bool event(Inkscape::UI::Tools::ToolBase *, GdkEvent *event) override;

    bool empty() { return _mmap.empty(); }
    unsigned size() { return _mmap.size(); }
    void setItems(std::set<ShapeRecord> const &);
    void clear() { _mmap.clear(); }
    void cleanup();

    void selectSubpaths();
    void shiftSelection(int dir);
    void invertSelectionInSubpaths();

    void setNodeType(NodeType t);
    void setSegmentType(SegmentType t);

    void insertNodesAtExtrema(ExtremumType extremum);
    void insertNodes();
    void insertNode(Geom::Point pt);
    void alertLPE();
    void duplicateNodes();
    void copySelectedPath(Geom::PathBuilder *builder);
    void joinNodes();
    void breakNodes();
    void deleteNodes(bool keep_shape = true);
    void joinSegments();
    void deleteSegments();
    void alignNodes(Geom::Dim2 d, AlignTargetNode target = AlignTargetNode::MID_NODE);
    void distributeNodes(Geom::Dim2 d);
    void reverseSubpaths();
    void move(Geom::Point const &delta);

    void showOutline(bool show);
    void showHandles(bool show);
    void showPathDirection(bool show);
    void setLiveOutline(bool set);
    void setLiveObjects(bool set);
    void updateOutlineColors();
    void updateHandles();
    void updatePaths();
    
    sigc::signal<void> signal_coords_changed; /// Emitted whenever the coordinates
        /// shown in the status bar need updating
private:
    typedef std::pair<ShapeRecord, std::shared_ptr<PathManipulator> > MapPair;
    typedef std::map<ShapeRecord, std::shared_ptr<PathManipulator> > MapType;

    template <typename R>
    void invokeForAll(R (PathManipulator::*method)()) {
        for (MapType::iterator i = _mmap.begin(); i != _mmap.end(); ) {
            // Sometimes the PathManipulator got freed at loop end, thus
            // invalidating the iterator so make sure that next_i will
            // be a valid iterator and then assign i to it.
            MapType::iterator next_i = i;
            ++next_i;
            // i->second is a std::shared_ptr so try to hold on to it so
            // it won't get freed prematurely by the WriteXML() method or
            // whatever. See https://bugs.launchpad.net/inkscape/+bug/1617615
            // Applicable to empty paths.
            std::shared_ptr<PathManipulator> hold(i->second);
            ((hold.get())->*method)();
            i = next_i;
        }
    }
    template <typename R, typename A>
    void invokeForAll(R (PathManipulator::*method)(A), A a) {
        for (auto & i : _mmap) {
            ((i.second.get())->*method)(a);
        }
    }
    template <typename R, typename A>
    void invokeForAll(R (PathManipulator::*method)(A const &), A const &a) {
        for (auto & i : _mmap) {
            ((i.second.get())->*method)(a);
        }
    }
    template <typename R, typename A, typename B>
    void invokeForAll(R (PathManipulator::*method)(A,B), A a, B b) {
        for (auto & i : _mmap) {
            ((i.second.get())->*method)(a, b);
        }
    }

    void _commit(CommitEvent cps);
    void _done(gchar const *reason, bool alert_LPE = true);
    void _doneWithCleanup(gchar const *reason, bool alert_LPE = false);
    guint32 _getOutlineColor(ShapeRole role, SPObject *object);

    MapType _mmap;
public:
    PathSharedData const &_path_data;
private:
    sigc::connection &_changed;
    ModifierTracker _tracker;
    bool _show_handles;
    bool _show_outline;
    bool _show_path_direction;
    bool _live_outline;
    bool _live_objects;

    friend class PathManipulator;
};

} // 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 :