2d28fcdf2af4f593b54f9b3321bfae2fe595e58e
[ardour.git] / libs / canvas / canvas / item.h
1 /*
2     Copyright (C) 2011-2013 Paul Davis
3     Original Author: Carl Hetherington <cth@carlh.net>
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #ifndef __CANVAS_ITEM_H__
21 #define __CANVAS_ITEM_H__
22
23 #include <stdint.h>
24
25 #include <gdk/gdk.h>
26
27 #include <cairomm/context.h>
28
29 #include "pbd/signals.h"
30
31 #include "canvas/visibility.h"
32 #include "canvas/types.h"
33 #include "canvas/fill.h"
34 #include "canvas/outline.h"
35 #include "canvas/lookup_table.h"
36
37 namespace ArdourCanvas
38 {
39 struct Rect;
40
41 class Canvas;
42 class ScrollGroup;
43
44 /** The parent class for anything that goes on the canvas.
45  *
46  *  Items have a position, which is expressed in the coordinates of the parent.
47  *  They also have a bounding box, which describes the area in which they have
48  *  drawable content, which is expressed in their own coordinates (whose origin
49  *  is at the item position).
50  *
51  *  Any item that is being displayed on a canvas has a pointer to that canvas,
52  *  and all except the `root group' have a pointer to their parent group.
53  */
54
55 class LIBCANVAS_API Item : public Fill, public Outline
56 {
57 public:
58         Item (Canvas *);
59         Item (Item *);
60         Item (Item *, Duple const& p);
61         virtual ~Item ();
62
63         void redraw () const;
64
65         /** Render this item to a Cairo context.
66          *  @param area Area to draw, in **window** coordinates
67          *
68          *  Items must convert their own coordinates into window coordinates
69          *  because Cairo is limited to a fixed point coordinate space that
70          *  does not extend as far as the Ardour timeline. All rendering must
71          *  be done using coordinates that do not exceed the (rough) limits
72          *  of the canvas' window, to avoid odd errors within Cairo as it
73          *  converts doubles into its fixed point format and then tesselates
74          *  the results.
75          */
76         virtual void render (Rect const & area, Cairo::RefPtr<Cairo::Context>) const = 0;
77
78         /** Adds one or more items to the vector @param items based on their
79          * covering @param point which is in **window** coordinates
80          *
81          * Note that Item::add_items_at_window_point() is only intended to be
82          * called on items already looked up in a LookupTable (i.e. by a
83          * parent) and thus known to cover @param point already.
84          *
85          * Derived classes may add more items than themselves (e.g. containers).
86          */
87         virtual void add_items_at_point (Duple /*point*/, std::vector<Item const *>& items) const;
88
89         /** Return true if the item covers @param point, false otherwise.
90          *
91          * The point is in window coordinates
92          */
93         virtual bool covers (Duple const &) const;
94
95         /** Update _bounding_box and _bounding_box_dirty */
96         virtual void compute_bounding_box () const = 0;
97
98         void grab ();
99         void ungrab ();
100
101         void unparent ();
102         void reparent (Item *);
103
104         /** @return Parent group, or 0 if this is the root group */
105         Item* parent () const {
106                 return _parent;
107         }
108
109         uint32_t depth() const;
110         const Item* closest_ancestor_with (const Item& other) const;
111         bool common_ancestor_within (uint32_t, const Item& other) const;
112
113         /** returns true if this item is an ancestor of @param candidate,
114          * and false otherwise.
115          */
116         bool is_ancestor_of (const Item& candidate) const {
117                 return candidate.is_descendant_of (*this);
118         }
119         /** returns true if this Item is a descendant of @param candidate,
120          * and false otherwise.
121          */
122         bool is_descendant_of (const Item& candidate) const;
123
124         void set_position (Duple);
125         void set_x_position (Coord);
126         void set_y_position (Coord);
127         void move (Duple);
128
129         /** @return Position of this item in the parent's coordinates */
130         Duple position () const {
131                 return _position;
132         }
133
134         Duple window_origin() const;
135         Duple canvas_origin() const;
136
137         ScrollGroup* scroll_parent() const { return _scroll_parent; }
138
139         boost::optional<Rect> bounding_box () const;
140         Coord height() const;
141         Coord width() const;
142
143         Duple item_to_parent (Duple const &) const;
144         Rect item_to_parent (Rect const &) const;
145         Duple parent_to_item (Duple const &) const;
146         Rect parent_to_item (Rect const &) const;
147
148         /* XXX: it's a pity these two aren't the same form as item_to_parent etc.,
149            but it makes a bit of a mess in the rest of the code if they are not.
150         */
151         void canvas_to_item (Coord &, Coord &) const;
152         void item_to_canvas (Coord &, Coord &) const;
153
154         Duple canvas_to_item (Duple const&) const;
155         Rect item_to_canvas (Rect const&) const;
156         Duple item_to_canvas (Duple const&) const;
157         Rect canvas_to_item (Rect const&) const;
158
159         Duple item_to_window (Duple const&, bool rounded = true) const;
160         Duple window_to_item (Duple const&) const;
161         Rect item_to_window (Rect const&, bool rounded = true) const;
162         Rect window_to_item (Rect const&) const;
163
164         void raise_to_top ();
165         void raise (int);
166         void lower_to_bottom ();
167
168         virtual void hide ();
169         virtual void show ();
170
171         /** @return true if this item is visible (ie it will be rendered),
172          *  otherwise false
173          */
174         bool self_visible () const {
175                 return _visible;
176         }
177
178         bool visible () const;
179
180         /** @return Our canvas, or 0 if we are not attached to one */
181         Canvas* canvas () const {
182                 return _canvas;
183         }
184
185         void set_ignore_events (bool);
186         bool ignore_events () const {
187                 return _ignore_events;
188         }
189
190         void set_data (std::string const &, void *);
191         void* get_data (std::string const &) const;
192
193         /* nested item ("grouping") API */
194         void add (Item *);
195         void add_front (Item *);
196         void remove (Item *);
197         void clear (bool with_delete = false);
198         std::list<Item*> const & items () const {
199                 return _items;
200         }
201         void raise_child_to_top (Item *);
202         void raise_child (Item *, int);
203         void lower_child_to_bottom (Item *);
204         virtual void child_changed ();
205
206         static int default_items_per_cell;
207
208
209         /* This is a sigc++ signal because it is solely
210            concerned with GUI stuff and is thus single-threaded
211         */
212
213         template <class T>
214         struct EventAccumulator {
215                 typedef T result_type;
216                 template <class U>
217                 result_type operator () (U first, U last) {
218                         while (first != last) {
219                                 if (*first) {
220                                         return true;
221                                 }
222                                 ++first;
223                         }
224                         return false;
225                 }
226         };
227
228         sigc::signal1<bool, GdkEvent*, EventAccumulator<bool> > Event;
229
230 #ifdef CANVAS_DEBUG
231         std::string name;
232 #endif
233
234 #ifdef CANVAS_COMPATIBILITY
235         void grab_focus ();
236 #endif
237
238         const std::string& tooltip () const { return _tooltip; }
239         void set_tooltip (const std::string&);
240
241         void start_tooltip_timeout ();
242         void stop_tooltip_timeout ();
243
244         virtual void dump (std::ostream&) const;
245         std::string whatami() const;
246
247 protected:
248         friend class Fill;
249         friend class Outline;
250
251         /** To be called at the beginning of any property change that
252          *  may alter the bounding box of this item
253          */
254         void begin_change ();
255         /** To be called at the endof any property change that
256          *  may alter the bounding box of this item
257          */
258         void end_change ();
259         /** To be called at the beginning of any property change that
260          *  does NOT alter the bounding box of this item
261          */
262         void begin_visual_change ();
263         /** To be called at the endof any property change that
264          *  does NOT alter the bounding box of this item
265          */
266         void end_visual_change ();
267
268         Canvas* _canvas;
269         /** parent group; may be 0 if we are the root group or if we have been unparent()ed */
270         Item* _parent;
271         /** scroll parent group; may be 0 if we are the root group or if we have been unparent()ed */
272         ScrollGroup* _scroll_parent;
273         /** position of this item in parent coordinates */
274         Duple _position;
275         /** true if this item is visible (ie to be drawn), otherwise false */
276         bool _visible;
277         /** our bounding box before any change that is currently in progress */
278         boost::optional<Rect> _pre_change_bounding_box;
279
280         /** our bounding box; may be out of date if _bounding_box_dirty is true */
281         mutable boost::optional<Rect> _bounding_box;
282         /** true if _bounding_box might be out of date, false if its definitely not */
283         mutable bool _bounding_box_dirty;
284
285         /* XXX: this is a bit grubby */
286         std::map<std::string, void *> _data;
287
288         /* nesting ("grouping") API */
289
290         void invalidate_lut () const;
291         void clear_items (bool with_delete);
292
293         void ensure_lut () const;
294         mutable LookupTable* _lut;
295         /* our items, from lowest to highest in the stack */
296         std::list<Item*> _items;
297
298         void add_child_bounding_boxes() const;
299         void render_children (Rect const & area, Cairo::RefPtr<Cairo::Context> context) const;
300
301         Duple scroll_offset() const;
302         Duple position_offset() const;
303
304 private:
305         void init ();
306
307         std::string _tooltip;
308         bool _ignore_events;
309
310         void find_scroll_parent ();
311         void propagate_show_hide ();
312 };
313
314 extern LIBCANVAS_API std::ostream& operator<< (std::ostream&, const ArdourCanvas::Item&);
315
316 }
317
318
319 #endif