1 // SPDX-License-Identifier: GPL-2.0-or-later
2 #ifndef SEEN_CANVAS_ITEM_H
3 #define SEEN_CANVAS_ITEM_H
4 
5 /**
6  * Abstract base class for on-canvas control items.
7  */
8 
9 /*
10  * Author:
11  *   Tavmjong Bah
12  *
13  * Copyright (C) 2020 Tavmjong Bah
14  *
15  * Rewrite of SPCanvasItem
16  *
17  * Released under GNU GPL v2+, read the file 'COPYING' for more information.
18  *
19  * A note about coordinates:
20  *
21  *   1. Canvas items are constructed using document (SVG) coordinates.
22  *   2. Calculations are made in canvas units, which is equivalent of SVG units multiplied by zoom factor.
23  *      This is true for bounds and closest distance calculations.
24  *   3  Drawing is done in screen units which is the same as canvas units but translated.
25  *   The document and canvas origins overlap.
26  *   The affine contains only scaling and rotating components.
27  */
28 
29 //#define CANVAS_ITEM_DEBUG
30 
31 #include <gdk/gdk.h>  // GdkEvent
32 #include <gdkmm/device.h> // Gdk::EventMask
33 #include <glib.h>     // guint32
34 #include <sigc++/sigc++.h>
35 
36 #include <2geom/rect.h>
37 
38 #include <boost/intrusive/list.hpp>
39 
40 #include "canvas-item-buffer.h"
41 #include "canvas-item-enums.h"
42 
43 class SPItem;
44 
45 namespace Inkscape {
46 
47 static guint32 CANVAS_ITEM_COLORS[] = { 0x0000ff7f, 0xff00007f, 0xffff007f };
48 
49 namespace UI::Widget {
50 class Canvas;
51 }
52 
53 class CanvasItemGroup; // A canvas control that contains other canvas controls.
54 
55 class CanvasItem {
56 
57 public:
58     CanvasItem(CanvasItemGroup* group);
59     virtual ~CanvasItem();
60 
61     // Structure
set_canvas(UI::Widget::Canvas * canvas)62     void set_canvas(UI::Widget::Canvas *canvas) { _canvas = canvas; }
get_canvas()63     UI::Widget::Canvas* get_canvas() { return _canvas; }
64 
set_parent(CanvasItemGroup * parent)65     void set_parent(CanvasItemGroup *parent) { _parent = parent; }
get_parent()66     CanvasItemGroup* get_parent() { return _parent; }
67 
set_item(SPItem * item)68     void set_item(SPItem *item) { _item = item; }
get_item()69     SPItem* get_item() { return _item; }
70 
71     // Z Position
72     bool is_descendant_of(CanvasItem *ancestor);
73     void set_z_position(unsigned int n);
74     int  get_z_position();    // z position in group.
75     // void raise_by(unsigned int n);
76     void raise_to_top();    // Move to top of group (last entry).
77     // void lower_by(unsigned int n);
78     void lower_to_bottom(); // Move to bottom of group (first entry).
79 
80     // Geometry
81     void request_update();
82     virtual void update(Geom::Affine const &affine) = 0;
get_affine()83     Geom::Affine get_affine() { return _affine; }
get_bounds()84     Geom::Rect get_bounds() { return _bounds; }
85 
86     // Selection
87     virtual bool contains(Geom::Point const &p, double tolerance = 0) { return _bounds.interiorContains(p); }
88     int grab(Gdk::EventMask event_mask, GdkCursor *cursor = nullptr);
89     void ungrab();
90 
91     // Display
92     virtual void render(Inkscape::CanvasItemBuffer *buf) = 0;
is_visible()93     bool is_visible() { return _visible; }
94     virtual void hide();
95     virtual void show();
96 
97     // Properties
98     virtual void set_fill(guint32 rgba);
set_fill(CanvasItemColor color)99     void set_fill(CanvasItemColor color) { set_fill(CANVAS_ITEM_COLORS[color]); }
100     virtual void set_stroke(guint32 rgba);
set_stroke(CanvasItemColor color)101     void set_stroke(CanvasItemColor color) { set_stroke(CANVAS_ITEM_COLORS[color]); }
set_name(std::string const & name)102     void set_name(std::string const &name) { _name = name; }
get_name()103     std::string get_name() { return _name; }
104 
105     // Events
set_pickable(bool pickable)106     void set_pickable(bool pickable) { _pickable = pickable; }
is_pickable()107     bool is_pickable() { return _pickable; }
connect_event(sigc::slot<bool,GdkEvent * > slot)108     sigc::connection connect_event(sigc::slot<bool, GdkEvent*> slot) {
109         return _event_signal.connect(slot);
110     }
handle_event(GdkEvent * event)111     virtual bool handle_event(GdkEvent *event) {
112         return _event_signal.emit(event); // Default just emit event.
113     }
114 
115     // Boost linked list member hook, speeds deletion.
116     boost::intrusive::list_member_hook<> member_hook;
117 
118 protected:
119 
120     // Structure
121     CanvasItemGroup *_parent = nullptr;
122     Inkscape::UI::Widget::Canvas *_canvas = nullptr;
123     SPItem *_item;  // The object this canvas item is linked to in some sense. Can be nullptr.
124 
125     // Geometry
126     Geom::Rect _bounds;
127     Geom::Affine _affine;
128     bool _need_update = true; // Need update after creation!
129 
130     // Display
131     bool _visible = true;
132     bool _align_to_drawing = false; // Rotate if drawing is rotated. TODO: Implement!
133 
134     // Selection
135     bool _pickable = false; // Most items are just for display and are not pickable!
136 
137     // Properties
138     guint32 _fill    = CANVAS_ITEM_COLORS[CANVAS_ITEM_SECONDARY];
139     guint32 _stroke  = CANVAS_ITEM_COLORS[CANVAS_ITEM_PRIMARY];
140     std::string _name; // For debugging
141 
142     // Events
143     sigc::signal<bool, GdkEvent*> _event_signal;
144 };
145 
146 
147 } // namespace Inkscape
148 
149 /** Type for linked list storing CanvasItem's.
150  *
151  * Used to speed deletion when a group containes a large number of item's (as in nodes for a
152  * complex path).
153  */
154 typedef boost::intrusive::list<
155     Inkscape::CanvasItem,
156     boost::intrusive::member_hook<Inkscape::CanvasItem, boost::intrusive::list_member_hook<>,
157                                   &Inkscape::CanvasItem::member_hook> > CanvasItemList;
158 
159 // Recursively print CanvasItem tree.
160 void canvas_item_print_tree(Inkscape::CanvasItem *item);
161 
162 #endif // SEEN_CANVAS_ITEM_H
163 
164 /*
165   Local Variables:
166   mode:c++
167   c-file-style:"stroustrup"
168   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
169   indent-tabs-mode:nil
170   fill-column:99
171   End:
172 */
173 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
174