summaryrefslogtreecommitdiffstats
path: root/src/ui/tool/manipulator.h
blob: 308ad1c9d4fac8129b5b5c85bf1f432caf81791a (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
// SPDX-License-Identifier: GPL-2.0-or-later
/** @file
 * Manipulator - edits something 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_MANIPULATOR_H
#define SEEN_UI_TOOL_MANIPULATOR_H

#include <set>
#include <map>
#include <cstddef>
#include <sigc++/sigc++.h>
#include <glib.h>
#include <gdk/gdk.h>
#include "ui/tools/tool-base.h"

class SPDesktop;
namespace Inkscape {
namespace UI {

class ManipulatorGroup;
class ControlPointSelection;

/**
 * @brief Tool component that processes events and does something in response to them.
 * Note: this class is probably redundant.
 */
class Manipulator {
friend class ManipulatorGroup;
public:
    Manipulator(SPDesktop *d)
        : _desktop(d)
    {}
    virtual ~Manipulator() = default;
    
    /// Handle input event. Returns true if handled.
    virtual bool event(Inkscape::UI::Tools::ToolBase *, GdkEvent *)=0;
    SPDesktop *const _desktop;
};

/**
 * @brief Tool component that edits something on the canvas using selectable control points.
 * Note: this class is probably redundant.
 */
class PointManipulator : public Manipulator, public sigc::trackable {
public:
    PointManipulator(SPDesktop *d, ControlPointSelection &sel)
        : Manipulator(d)
        , _selection(sel)
    {}

    /// Type of extremum points to add in PathManipulator::insertNodeAtExtremum
    enum ExtremumType {
        EXTR_MIN_X = 0,
        EXTR_MAX_X,
        EXTR_MIN_Y,
        EXTR_MAX_Y
    };
protected:
    ControlPointSelection &_selection;
};

/** Manipulator that aggregates several manipulators of the same type.
 * The order of invoking events on the member manipulators is undefined.
 * To make this class more useful, derive from it and add actions that can be performed
 * on all manipulators in the set.
 *
 * This is not used at the moment and is probably useless. */
template <typename T>
class MultiManipulator : public PointManipulator {
public:
    //typedef typename T::ItemType ItemType;
    typedef typename std::pair<void*, std::shared_ptr<T> > MapPair;
    typedef typename std::map<void*, std::shared_ptr<T> > MapType;

    MultiManipulator(SPDesktop *d, ControlPointSelection &sel)
        : PointManipulator(d, sel)
    {}
    void addItem(void *item) {
        std::shared_ptr<T> m(_createManipulator(item));
        _mmap.insert(MapPair(item, m));
    }
    void removeItem(void *item) {
        _mmap.erase(item);
    }
    void clear() {
        _mmap.clear();
    }
    bool contains(void *item) {
        return _mmap.find(item) != _mmap.end();
    }
    bool empty() {
        return _mmap.empty();
    }
    
    void setItems(std::vector<gpointer> list) { // this function is not called anywhere ... delete ?
        std::set<void*> to_remove;
        for (typename MapType::iterator mi = _mmap.begin(); mi != _mmap.end(); ++mi) {
            to_remove.insert(mi->first);
        }
        for (auto i:list) {
            if (_isItemType(i)) {
                // erase returns the number of items removed
                // if nothing was removed, it means this item did not have a manipulator - add it
                if (!to_remove.erase(i)) addItem(i);
            }
        }
        for (auto ri : to_remove) {
            removeItem(ri);
        }
    }

    /** Invoke a method on all managed manipulators.
     * Example:
     * @code m.invokeForAll(&SomeManipulator::someMethod); @endcode
     */
    template <typename R>
    void invokeForAll(R (T::*method)()) {
        for (typename MapType::iterator i = _mmap.begin(); i != _mmap.end(); ++i) {
            ((i->second.get())->*method)();
        }
    }
    template <typename R, typename A>
    void invokeForAll(R (T::*method)(A), A a) {
        for (typename MapType::iterator i = _mmap.begin(); i != _mmap.end(); ++i) {
            ((i->second.get())->*method)(a);
        }
    }
    template <typename R, typename A>
    void invokeForAll(R (T::*method)(A const &), A const &a) {
        for (typename MapType::iterator i = _mmap.begin(); i != _mmap.end(); ++i) {
            ((i->second.get())->*method)(a);
        }
    }
    template <typename R, typename A, typename B>
    void invokeForAll(R (T::*method)(A,B), A a, B b) {
        for (typename MapType::iterator i = _mmap.begin(); i != _mmap.end(); ++i) {
            ((i->second.get())->*method)(a, b);
        }
    }
    
    bool event(Inkscape::UI::Tools::ToolBase *event_context, GdkEvent *event) override {
        for (typename MapType::iterator i = _mmap.begin(); i != _mmap.end(); ++i) {
            if ((*i).second->event(event_context, event)) return true;
        }
        return false;
    }
protected:
    virtual T *_createManipulator(void *item) = 0;
    virtual bool _isItemType(void *item) = 0;
    MapType _mmap;
};

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