summaryrefslogtreecommitdiffstats
path: root/src/ui/tools/pen-tool.h
blob: bd48ce775e8e2580fbbecf8eb295dbda6ebe9a9a (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
// SPDX-License-Identifier: GPL-2.0-or-later
/** \file
 * PenTool: a context for pen tool events.
 *//*
 * Authors: see git history
 *
 * Copyright (C) 2018 Authors
 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
 */
#ifndef SEEN_PEN_CONTEXT_H
#define SEEN_PEN_CONTEXT_H

#include <sigc++/sigc++.h>

#include "ui/tools/freehand-base.h"
#include "live_effects/effect.h"

#define SP_PEN_CONTEXT(obj) (dynamic_cast<Inkscape::UI::Tools::PenTool*>((Inkscape::UI::Tools::ToolBase*)obj))
#define SP_IS_PEN_CONTEXT(obj) (dynamic_cast<const Inkscape::UI::Tools::PenTool*>((const Inkscape::UI::Tools::ToolBase*)obj) != NULL)

namespace Inkscape {

class CanvasItemCtrl;
class CanvasItemCurve;

namespace UI {
namespace Tools {

/**
 * PenTool: a context for pen tool events.
 */
class PenTool : public FreehandBase {
public:
    PenTool(SPDesktop *desktop,
        std::string prefs_path = "/tools/freehand/pen",
        const std::string& cursor_filename = "pen.svg");
    ~PenTool() override;

    enum Mode {
        MODE_CLICK,
        MODE_DRAG
    };

    enum State {
        POINT,
        CONTROL,
        CLOSE,
        STOP,
        DEAD
    };

    Geom::Point p[5];
    Geom::Point previous;
    /** \invar npoints in {0, 2, 5}. */
    // npoints somehow determines the type of the node (what does it mean, exactly? the number of Bezier handles?)
    gint npoints = 0;

    Mode mode = MODE_CLICK;
    State state = POINT;
    bool polylines_only = false;
    bool polylines_paraxial = false;
    Geom::Point paraxial_angle;

    bool spiro = false;  // Spiro mode active?
    bool bspline = false; // BSpline mode active?
    int num_clicks = 0;;

    unsigned int expecting_clicks_for_LPE = 0; // if positive, finish the path after this many clicks
    Inkscape::LivePathEffect::Effect *waiting_LPE = nullptr; // if NULL, waiting_LPE_type in SPDrawContext is taken into account
    SPLPEItem *waiting_item = nullptr;

    Inkscape::CanvasItemCtrl *c0 = nullptr; // Start point of path.
    Inkscape::CanvasItemCtrl *c1 = nullptr; // End point of path.
    
    Inkscape::CanvasItemCurve *cl0 = nullptr;
    Inkscape::CanvasItemCurve *cl1 = nullptr;
    
    bool events_disabled = false;

    void nextParaxialDirection(Geom::Point const &pt, Geom::Point const &origin, guint state);
    void setPolylineMode();
    bool hasWaitingLPE();
    void waitForLPEMouseClicks(Inkscape::LivePathEffect::EffectType effect_type, unsigned int num_clicks, bool use_polylines = true);

protected:
    void set(const Inkscape::Preferences::Entry& val) override;
    bool root_handler(GdkEvent* event) override;
    bool item_handler(SPItem* item, GdkEvent* event) override;

private:
    bool _handleButtonPress(GdkEventButton const &bevent);
    bool _handleMotionNotify(GdkEventMotion const &mevent);
    bool _handleButtonRelease(GdkEventButton const &revent);
    bool _handle2ButtonPress(GdkEventButton const &bevent);
    bool _handleKeyPress(GdkEvent *event);
    //this function changes the colors red, green and blue making them transparent or not depending on if the function uses spiro
    void _bsplineSpiroColor();
    //creates a node in bspline or spiro modes
    void _bsplineSpiro(bool shift);
    //creates a node in bspline or spiro modes
    void _bsplineSpiroOn();
    //creates a CUSP node
    void _bsplineSpiroOff();
    //continues the existing curve in bspline or spiro mode
    void _bsplineSpiroStartAnchor(bool shift);
    //continues the existing curve with the union node in bspline or spiro modes
    void _bsplineSpiroStartAnchorOn();
    //continues an existing curve with the union node in CUSP mode
    void _bsplineSpiroStartAnchorOff();
    //modifies the "red_curve" when it detects movement
    void _bsplineSpiroMotion(guint const state);
    //closes the curve with the last node in bspline or spiro mode
    void _bsplineSpiroEndAnchorOn();
    //closes the curve with the last node in CUSP mode
    void _bsplineSpiroEndAnchorOff();
    //apply the effect
    void _bsplineSpiroBuild();

    void _setInitialPoint(Geom::Point const p);
    void _setSubsequentPoint(Geom::Point const p, bool statusbar, guint status = 0);
    void _setCtrl(Geom::Point const p, guint state);
    void _finishSegment(Geom::Point p, guint state);
    bool _undoLastPoint();

    void _finish(gboolean closed);

    void _resetColors();

    void _disableEvents();
    void _enableEvents();

    void _setToNearestHorizVert(Geom::Point &pt, guint const state) const;

    void _setAngleDistanceStatusMessage(Geom::Point const p, int pc_point_to_compare, gchar const *message);

    void _lastpointToLine();
    void _lastpointToCurve();
    void _lastpointMoveScreen(gdouble x, gdouble y);
    void _lastpointMove(gdouble x, gdouble y);
    void _redrawAll();

    void _endpointSnapHandle(Geom::Point &p, guint const state);
    void _endpointSnap(Geom::Point &p, guint const state);

    void _cancel();

    sigc::connection _desktop_destroy;
};

}
}
}

#endif /* !SEEN_PEN_CONTEXT_H */

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