summaryrefslogtreecommitdiffstats
path: root/src/ui/tools/eraser-tool.h
blob: 5198ebd3dd2bd2e6b95a5ecde528ed0bcf3d4c7e (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
// SPDX-License-Identifier: GPL-2.0-or-later
#ifndef ERASER_TOOL_H_SEEN
#define ERASER_TOOL_H_SEEN

/*
 * Handwriting-like drawing mode
 *
 * Authors:
 *   Mitsuru Oka <oka326@parkcity.ne.jp>
 *   Lauris Kaplinski <lauris@kaplinski.com>
 *
 * The original dynadraw code:
 *   Paul Haeberli <paul@sgi.com>
 *
 * Copyright (C) 1998 The Free Software Foundation
 * Copyright (C) 1999-2002 authors
 * Copyright (C) 2001-2002 Ximian, Inc.
 * Copyright (C) 2008 Jon A. Cruz
 *
 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
 */

#include <2geom/point.h>

#include "message-stack.h"
#include "style.h"
#include "ui/tools/dynamic-base.h"
#include "object/sp-use.h"

namespace Inkscape {
namespace UI {
namespace Tools {

enum class EraserToolMode
{
    DELETE,
    CUT,
    CLIP
};
static inline constexpr auto DEFAULT_ERASER_MODE = EraserToolMode::CUT;

/** Represents an item to erase */
struct EraseTarget
{
    SPItem *item = nullptr;    ///< Pointer to the item to be erased
    bool was_selected = false; ///< Whether the item was part of selection

    EraseTarget(SPItem *ptr, bool sel)
        : item{ptr}
        , was_selected{sel}
    {}
    inline bool operator==(EraseTarget const &other) const noexcept { return item == other.item; }
};

class EraserTool : public DynamicBase {

private:
    // non-static data:
    EraserToolMode mode = DEFAULT_ERASER_MODE;
    bool nowidth = false;
    std::vector<MessageId> _our_messages;
    SPItem *_acid = nullptr;
    std::vector<SPItem *> _survivers;
    Pref<bool> _break_apart;
    Pref<int> _mode_int;

    // static data:
    static constexpr uint32_t trace_color_rgba  = 0xff0000ff; // RGBA red
    static constexpr SPWindRule trace_wind_rule = SP_WIND_RULE_EVENODD;

    static constexpr double tolerance = 0.1;

    static constexpr double epsilon       = 0.5e-6;
    static constexpr double epsilon_start = 0.5e-2;
    static constexpr double vel_start     = 1e-5;

    static constexpr double drag_default = 1.0;
    static constexpr double drag_min     = 0.0;
    static constexpr double drag_max     = 1.0;

    static constexpr double min_pressure     = 0.0;
    static constexpr double max_pressure     = 1.0;
    static constexpr double default_pressure = 1.0;

    static constexpr double min_tilt     = -1.0;
    static constexpr double max_tilt     = 1.0;
    static constexpr double default_tilt = 0.0;

public:
    // public member functions
    EraserTool(SPDesktop *desktop);
    ~EraserTool() override;
    bool root_handler(GdkEvent *event) final;

    using Error = std::uint64_t;
    static constexpr Error ALL_GOOD     = 0x0;
    static constexpr Error NON_EXISTENT = 0x1 << 1;
    static constexpr Error NO_AREA_PATH = 0x1 << 2;
    static constexpr Error RASTER_IMAGE = 0x1 << 3;
    static constexpr Error ERROR_GROUP  = 0x1 << 4;

private:
    // private member functions
    void _accumulate();
    bool _apply(Geom::Point p);
    bool _booleanErase(EraseTarget target, bool store_survivers);
    void _brush();
    void _cancel();
    void _clearCurrent();
    void _clearStatusBar();
    void _clipErase(SPItem *item) const;
    void _completeBezier(double tolerance_sq, bool releasing);
    bool _cutErase(EraseTarget target, bool store_survivers);
    bool _doWork();
    void _drawTemporaryBox();
    void _extinput(GdkEvent *event);
    void _failedBezierFallback();
    std::vector<EraseTarget> _filterByCollision(std::vector<EraseTarget> const &items, SPItem *with) const;
    std::vector<EraseTarget> _filterCutEraseables(std::vector<EraseTarget> const &items, bool silent = false);
    std::vector<EraseTarget> _findItemsToErase();
    void _fitAndSplit(bool releasing);
    void _fitDrawLastPoint();
    bool _handleKeypress(GdkEventKey const *key);
    void _handleStrokeStyle(SPItem *item) const;
    SPItem *_insertAcidIntoDocument(SPDocument *document);
    bool _performEraseOperation(std::vector<EraseTarget> const &items_to_erase, bool store_survivers);
    void _reset(Geom::Point p);
    void _setStatusBarMessage(char *message);
    void _updateMode();

    static void _generateNormalDist2(double &r1, double &r2);
    static void _addCap(SPCurve &curve, Geom::Point const &pre, Geom::Point const &from, Geom::Point const &to,
                        Geom::Point const &post, double rounding);
    static bool _isStraightSegment(SPItem *path);
    static Error _uncuttableItemType(SPItem *item);
    bool _probeUnlinkCutClonedGroup(EraseTarget &original_target, SPUse* clone, SPGroup* cloned_group,
                                    bool store_survivers = true);
};

} // namespace Tools
} // namespace UI
} // namespace Inkscape

#endif // ERASER_TOOL_H_SEEN

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