summaryrefslogtreecommitdiffstats
path: root/src/seltrans.h
blob: 7a4e0830ca42cdfb9331378381368119f59cb24b (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
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
// SPDX-License-Identifier: GPL-2.0-or-later
#ifndef SEEN_SELTRANS_H
#define SEEN_SELTRANS_H

/*
 * Helper object for transforming selected items
 *
 * Authors:
 *   Lauris Kaplinski <lauris@kaplinski.com>
 *   Carl Hetherington <inkscape@carlh.net>
 *   Diederik van Lierop <mail@diedenrezi.nl>
 *
 * Copyright (C) 2006      Johan Engelen <johan@shouraizou.nl>
 * Copyright (C) 1999-2002 Lauris Kaplinski
 *
 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
 */

#include <2geom/point.h>
#include <2geom/affine.h>
#include <2geom/rect.h>
#include <cstddef>
#include <sigc++/sigc++.h>
#include <vector>

#include "message-context.h"
#include "seltrans-handles.h"
#include "selcue.h"

#include "object/sp-item.h"
#include "ui/knot/knot.h"

class  SPDesktop;
struct SPCanvasItem;
struct SPSelTransHandle;

namespace Inkscape {

class CanvasItemCtrl;
class CanvasItemCurve;

Geom::Scale calcScaleFactors(Geom::Point const &initial_point, Geom::Point const &new_point, Geom::Point const &origin, bool const skew = false);

namespace XML {
    class Node;
}

class SelTrans
{
public:
    SelTrans(SPDesktop *desktop);
    ~SelTrans();

    void increaseState();
    void resetState();
    void setCenter(Geom::Point const &p);
    void grab(Geom::Point const &p, double x, double y, bool show_handles, bool translating);
    void transform(Geom::Affine const &rel_affine, Geom::Point const &norm);
    void ungrab();
    void stamp();
    void moveTo(Geom::Point const &xy, unsigned int state);
    void stretch(SPSelTransHandle const &handle, Geom::Point &pt, unsigned int state);
    void scale(Geom::Point &pt, unsigned int state);
    void skew(SPSelTransHandle const &handle, Geom::Point &pt, unsigned int state);
    void rotate(Geom::Point &pt, unsigned int state);
    void align(guint state, SPSelTransHandle const &handle);
    int request(SPSelTransHandle const &handle, Geom::Point &pt, unsigned int state);
    int scaleRequest(Geom::Point &pt, unsigned int state);
    int stretchRequest(SPSelTransHandle const &handle, Geom::Point &pt, unsigned int state);
    int skewRequest(SPSelTransHandle const &handle, Geom::Point &pt, unsigned int state);
    int rotateRequest(Geom::Point &pt, unsigned int state);
    int centerRequest(Geom::Point &pt, unsigned int state);

    int handleRequest(SPKnot *knot, Geom::Point *position, unsigned int state, SPSelTransHandle const &handle);
    void handleGrab(SPKnot *knot, unsigned int state, SPSelTransHandle const &handle);
    void handleClick(SPKnot *knot, unsigned int state, SPSelTransHandle const &handle);
    void handleNewEvent(SPKnot *knot, Geom::Point *position, unsigned int state, SPSelTransHandle const &handle);

    enum Show
    {
        SHOW_CONTENT,
        SHOW_OUTLINE
    };

    void setShow(Show s) {
        _show = s;
    }
    bool isEmpty() {
        return _empty;
    }
    bool isGrabbed() {
        return _grabbed;
    }
    bool centerIsVisible() {
        return ( knots[0]->is_visible());
    }

    void getNextClosestPoint(bool reverse);

private:
    class BoundingBoxPrefsObserver: public Preferences::Observer
    {
    public:
        BoundingBoxPrefsObserver(SelTrans &sel_trans);

        void notify(Preferences::Entry const &val) override;

    private:
        SelTrans &_sel_trans;
    };

    friend class Inkscape::SelTrans::BoundingBoxPrefsObserver;

    void _updateHandles();
    void _updateVolatileState();
    void _selChanged(Inkscape::Selection *selection);
    void _selModified(Inkscape::Selection *selection, unsigned int flags);
    void _boundingBoxPrefsChanged(int prefs_bbox);
    void _makeHandles();
    void _showHandles(SPSelTransType type);
    Geom::Point _getGeomHandlePos(Geom::Point const &visual_handle_pos);
    Geom::Point _calcAbsAffineDefault(Geom::Scale const default_scale);
    Geom::Point _calcAbsAffineGeom(Geom::Scale const geom_scale);
    void _keepClosestPointOnly(Geom::Point const &p);

    enum State {
        STATE_SCALE, //scale or stretch
        STATE_ROTATE, //rotate or skew
        STATE_ALIGN //on canvas align
    };

    SPDesktop *_desktop;

    std::vector<SPItem *> _items;
    std::vector<SPObject const *> _objects_const;
    std::vector<Geom::Affine> _items_affines;
    std::vector<Geom::Point> _items_centers;

    std::vector<Inkscape::SnapCandidatePoint> _snap_points;
    std::vector<Inkscape::SnapCandidatePoint> _bbox_points;
    std::vector<Inkscape::SnapCandidatePoint> _all_snap_sources_sorted;
    std::vector<Inkscape::SnapCandidatePoint>::iterator _all_snap_sources_iter;
    Inkscape::SelCue _selcue;

    Inkscape::Selection *_selection;
    State _state;
    Show _show;

    bool _grabbed = false;
    bool _show_handles = true;
    bool _empty;
    bool _changed;

    SPItem::BBoxType _snap_bbox_type;

    Geom::OptRect _bbox;
    Geom::OptRect _stroked_bbox;
    Geom::OptRect _geometric_bbox;
    double _strokewidth;

    Geom::Affine _current_relative_affine;
    Geom::Affine _absolute_affine;
    Geom::Affine _relative_affine;
    /* According to Merriam - Webster's online dictionary
     * Affine: a transformation (as a translation, a rotation, or a uniform stretching) that carries straight
     * lines into straight lines and parallel lines into parallel lines but may alter distance between points
     * and angles between lines <affine geometry>
     */

    Geom::Point _opposite; ///< opposite point to where a scale is taking place
    Geom::Point _opposite_for_specpoints;
    Geom::Point _opposite_for_bboxpoints;
    Geom::Point _origin_for_specpoints;
    Geom::Point _origin_for_bboxpoints;

    double _handle_x;
    double _handle_y;

    std::optional<Geom::Point> _center;
    bool _center_is_set; ///< we've already set _center, no need to reread it from items

    SPKnot *knots[NUMHANDS];
    Inkscape::CanvasItemCtrl *_norm;
    Inkscape::CanvasItemCtrl *_grip;
    Inkscape::CanvasItemCurve *_l[4];
    std::vector<SPItem*> _stamp_cache;
    bool _stamped = false;
    Geom::Point _origin; ///< position of origin for transforms
    Geom::Point _point; ///< original position of the knot being used for the current transform
    Geom::Point _point_geom; ///< original position of the knot being used for the current transform
    Inkscape::MessageContext _message_context;
    sigc::connection _sel_changed_connection;
    sigc::connection _sel_modified_connection;
    BoundingBoxPrefsObserver _bounding_box_prefs_observer;
};

}

#endif // SEEN_SELTRANS_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 :