summaryrefslogtreecommitdiffstats
path: root/src/display/control/canvas-item.h
blob: 37d5ec7108adc43a670bb1e7258e7754ad9b0e6d (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
// SPDX-License-Identifier: GPL-2.0-or-later
#ifndef SEEN_CANVAS_ITEM_H
#define SEEN_CANVAS_ITEM_H

/**
 * Abstract base class for on-canvas control items.
 */

/*
 * Author:
 *   Tavmjong Bah
 *
 * Copyright (C) 2020 Tavmjong Bah
 *
 * Rewrite of SPCanvasItem
 *
 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
 *
 * A note about coordinates:
 *
 *   1. Canvas items are constructed using document (SVG) coordinates.
 *   2. Calculations are made in canvas units, which is equivalent of SVG units multiplied by zoom factor.
 *      This is true for bounds and closest distance calculations.
 *   3  Drawing is done in screen units which is the same as canvas units but translated.
 *   The document and canvas origins overlap.
 *   The affine contains only scaling and rotating components.
 */

//#define CANVAS_ITEM_DEBUG

#include <gdk/gdk.h>  // GdkEvent
#include <gdkmm/device.h> // Gdk::EventMask
#include <glib.h>     // guint32
#include <sigc++/sigc++.h>

#include <2geom/rect.h>

#include <boost/intrusive/list.hpp>

#include "canvas-item-buffer.h"
#include "canvas-item-enums.h"

class SPItem;

namespace Inkscape {

static guint32 CANVAS_ITEM_COLORS[] = { 0x0000ff7f, 0xff00007f, 0xffff007f };

namespace UI::Widget {
class Canvas;
}

class CanvasItemGroup; // A canvas control that contains other canvas controls.

class CanvasItem {

public:
    CanvasItem(CanvasItemGroup* group);
    virtual ~CanvasItem();

    // Structure
    void set_canvas(UI::Widget::Canvas *canvas) { _canvas = canvas; }
    UI::Widget::Canvas* get_canvas() { return _canvas; }

    void set_parent(CanvasItemGroup *parent) { _parent = parent; }
    CanvasItemGroup* get_parent() { return _parent; }

    void set_item(SPItem *item) { _item = item; }
    SPItem* get_item() { return _item; }

    // Z Position
    bool is_descendant_of(CanvasItem *ancestor);
    void set_z_position(unsigned int n);
    int  get_z_position();    // z position in group.
    // void raise_by(unsigned int n);
    void raise_to_top();    // Move to top of group (last entry).
    // void lower_by(unsigned int n);
    void lower_to_bottom(); // Move to bottom of group (first entry).

    // Geometry
    void request_update();
    virtual void update(Geom::Affine const &affine) = 0;
    Geom::Affine get_affine() { return _affine; }
    Geom::Rect get_bounds() { return _bounds; }

    // Selection
    virtual bool contains(Geom::Point const &p, double tolerance = 0) { return _bounds.interiorContains(p); }
    int grab(Gdk::EventMask event_mask, GdkCursor *cursor = nullptr);
    int grab(Gdk::EventMask event_mask, Glib::RefPtr<Gdk::Cursor> cursor);
    void ungrab();

    // Display
    virtual void render(Inkscape::CanvasItemBuffer *buf) = 0;
    bool is_visible() { return _visible; }
    virtual void hide();
    virtual void show();
    void request_redraw();  // queue redraw request

    // Properties
    virtual void set_fill(guint32 rgba);
    void set_fill(CanvasItemColor color) { set_fill(CANVAS_ITEM_COLORS[color]); }
    virtual void set_stroke(guint32 rgba);
    void set_stroke(CanvasItemColor color) { set_stroke(CANVAS_ITEM_COLORS[color]); }
    void set_name(std::string const &name) { _name = name; }
    std::string get_name() { return _name; }

    // Events
    void set_pickable(bool pickable) { _pickable = pickable; }
    bool is_pickable() { return _pickable; }
    sigc::connection connect_event(sigc::slot<bool, GdkEvent*> slot) {
        return _event_signal.connect(slot);
    }
    virtual bool handle_event(GdkEvent *event) {
        return _event_signal.emit(event); // Default just emit event.
    }

    // Boost linked list member hook, speeds deletion.
    boost::intrusive::list_member_hook<> member_hook;

protected:

    // Structure
    CanvasItemGroup *_parent = nullptr;
    Inkscape::UI::Widget::Canvas *_canvas = nullptr;
    SPItem *_item;  // The object this canvas item is linked to in some sense. Can be nullptr.

    // Geometry
    Geom::Rect _bounds;
    Geom::Affine _affine;
    bool _need_update = true; // Need update after creation!

    // Display
    bool _visible = true;
    bool _align_to_drawing = false; // Rotate if drawing is rotated. TODO: Implement!

    // Selection
    bool _pickable = false; // Most items are just for display and are not pickable!

    // Properties
    guint32 _fill    = CANVAS_ITEM_COLORS[CANVAS_ITEM_SECONDARY];
    guint32 _stroke  = CANVAS_ITEM_COLORS[CANVAS_ITEM_PRIMARY];
    std::string _name; // For debugging

    // Events
    sigc::signal<bool, GdkEvent*> _event_signal;
};


} // namespace Inkscape

/** Type for linked list storing CanvasItem's.
 *
 * Used to speed deletion when a group contains a large number of item's (as in nodes for a
 * complex path).
 */
typedef boost::intrusive::list<
    Inkscape::CanvasItem,
    boost::intrusive::member_hook<Inkscape::CanvasItem, boost::intrusive::list_member_hook<>,
                                  &Inkscape::CanvasItem::member_hook> > CanvasItemList;

// Recursively print CanvasItem tree.
void canvas_item_print_tree(Inkscape::CanvasItem *item);

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