2 Copyright (C) 2011-2013 Paul Davis
3 Original Author: Carl Hetherington <cth@carlh.net>
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.
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.
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.
20 #ifndef __CANVAS_ITEM_H__
21 #define __CANVAS_ITEM_H__
27 #include <cairomm/context.h>
29 #include "pbd/signals.h"
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"
37 namespace ArdourCanvas
44 /** The parent class for anything that goes on the canvas.
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).
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.
55 class LIBCANVAS_API Item : public Fill, public Outline
60 Item (Item *, Duple const& p);
65 /** Render this item to a Cairo context.
66 * @param area Area to draw, in **window** coordinates
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
76 virtual void render (Rect const & area, Cairo::RefPtr<Cairo::Context>) const = 0;
78 /** Item has changed will be rendered in next render pass so give item a
79 * chance to perhaps schedule work in another thread etc.
81 * @param area Area to draw, in **window** coordinates
83 virtual void prepare_for_render (Rect const & area) const { }
85 /** Adds one or more items to the vector @param items based on their
86 * covering @param point which is in **window** coordinates
88 * Note that Item::add_items_at_window_point() is only intended to be
89 * called on items already looked up in a LookupTable (i.e. by a
90 * parent) and thus known to cover @param point already.
92 * Derived classes may add more items than themselves (e.g. containers).
94 virtual void add_items_at_point (Duple /*point*/, std::vector<Item const *>& items) const;
96 /** Return true if the item covers @param point, false otherwise.
98 * The point is in window coordinates
100 virtual bool covers (Duple const &) const;
102 /** Update _bounding_box and _bounding_box_dirty */
103 virtual void compute_bounding_box () const = 0;
109 void reparent (Item *, bool already_added = false);
111 /** @return Parent group, or 0 if this is the root group */
112 Item* parent () const {
116 uint32_t depth() const;
117 const Item* closest_ancestor_with (const Item& other) const;
118 bool common_ancestor_within (uint32_t, const Item& other) const;
120 /** returns true if this item is an ancestor of @param candidate,
121 * and false otherwise.
123 bool is_ancestor_of (const Item& candidate) const {
124 return candidate.is_descendant_of (*this);
126 /** returns true if this Item is a descendant of @param candidate,
127 * and false otherwise.
129 bool is_descendant_of (const Item& candidate) const;
131 void set_position (Duple);
132 void set_x_position (Coord);
133 void set_y_position (Coord);
136 /** @return Position of this item in the parent's coordinates */
137 Duple position () const {
141 Duple window_origin() const;
142 Duple canvas_origin() const;
144 ScrollGroup* scroll_parent() const { return _scroll_parent; }
146 /* item implementations can override this if they need to */
147 virtual Rect size_request() const { return bounding_box (true); }
148 virtual void size_allocate (Rect const&);
150 /** bounding box is the public API to get the size of the item.
151 If @param for_own_purposes is false, then it will return the
152 allocated bounding box (if there is one) in preference to the
153 one that would naturally be computed by the item.
155 Rect bounding_box (bool for_own_purposes = false) const;
156 Rect allocation() const { return _allocation; }
158 Coord height() const;
161 Duple item_to_parent (Duple const &) const;
162 Rect item_to_parent (Rect const &) const;
163 Duple parent_to_item (Duple const &) const;
164 Rect parent_to_item (Rect const &) const;
166 /* XXX: it's a pity these two aren't the same form as item_to_parent etc.,
167 but it makes a bit of a mess in the rest of the code if they are not.
169 void canvas_to_item (Coord &, Coord &) const;
170 void item_to_canvas (Coord &, Coord &) const;
172 Duple canvas_to_item (Duple const&) const;
173 Rect item_to_canvas (Rect const&) const;
174 Duple item_to_canvas (Duple const&) const;
175 Rect canvas_to_item (Rect const&) const;
177 Duple item_to_window (Duple const&, bool rounded = true) const;
178 Duple window_to_item (Duple const&) const;
179 Rect item_to_window (Rect const&, bool rounded = true) const;
180 Rect window_to_item (Rect const&) const;
182 void raise_to_top ();
184 void lower_to_bottom ();
186 virtual void hide ();
187 virtual void show ();
189 /** @return true if this item is visible (ie it will be rendered),
192 bool self_visible () const {
196 bool visible () const;
198 /** @return Our canvas, or 0 if we are not attached to one */
199 Canvas* canvas () const {
203 void set_ignore_events (bool);
204 bool ignore_events () const {
205 return _ignore_events;
208 void set_data (std::string const &, void *);
209 void* get_data (std::string const &) const;
211 /* nested item ("grouping") API */
213 void add_front (Item *);
214 void remove (Item *);
215 void clear (bool with_delete = false);
216 std::list<Item*> const & items () const {
219 void raise_child_to_top (Item *);
220 void raise_child (Item *, int);
221 void lower_child_to_bottom (Item *);
222 virtual void child_changed ();
224 static int default_items_per_cell;
227 /* This is a sigc++ signal because it is solely
228 concerned with GUI stuff and is thus single-threaded
232 struct EventAccumulator {
233 typedef T result_type;
235 result_type operator () (U first, U last) {
236 while (first != last) {
246 sigc::signal1<bool, GdkEvent*, EventAccumulator<bool> > Event;
252 #ifdef CANVAS_COMPATIBILITY
256 const std::string& tooltip () const { return _tooltip; }
257 void set_tooltip (const std::string&);
259 void start_tooltip_timeout ();
260 void stop_tooltip_timeout ();
262 virtual void dump (std::ostream&) const;
263 std::string whatami() const;
267 friend class Outline;
269 /** To be called at the beginning of any property change that
270 * may alter the bounding box of this item
272 void begin_change ();
273 /** To be called at the endof any property change that
274 * may alter the bounding box of this item
277 /** To be called at the beginning of any property change that
278 * does NOT alter the bounding box of this item
280 void begin_visual_change ();
281 /** To be called at the endof any property change that
282 * does NOT alter the bounding box of this item
284 void end_visual_change ();
287 /** parent group; may be 0 if we are the root group or if we have been unparent()ed */
289 /** scroll parent group; may be 0 if we are the root group or if we have been unparent()ed */
290 ScrollGroup* _scroll_parent;
291 /** position of this item in parent coordinates */
293 /** true if this item is visible (ie to be drawn), otherwise false */
295 /** our bounding box before any change that is currently in progress */
296 Rect _pre_change_bounding_box;
298 /** our bounding box; may be out of date if _bounding_box_dirty is true */
299 mutable Rect _bounding_box;
300 /** true if _bounding_box might be out of date, false if its definitely not */
301 mutable bool _bounding_box_dirty;
304 /* XXX: this is a bit grubby */
305 std::map<std::string, void *> _data;
307 /* nesting ("grouping") API */
309 void invalidate_lut () const;
310 void clear_items (bool with_delete);
312 void ensure_lut () const;
313 mutable LookupTable* _lut;
314 /* our items, from lowest to highest in the stack */
315 std::list<Item*> _items;
317 void add_child_bounding_boxes (bool include_hidden = false) const;
318 void render_children (Rect const & area, Cairo::RefPtr<Cairo::Context> context) const;
319 void prepare_for_render_children (Rect const & area) const;
321 Duple scroll_offset() const;
322 Duple position_offset() const;
327 std::string _tooltip;
330 void find_scroll_parent ();
331 void propagate_show_hide ();
334 extern LIBCANVAS_API std::ostream& operator<< (std::ostream&, const ArdourCanvas::Item&);