add Item::canvas_origin() for convenience
[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
34 namespace ArdourCanvas
35 {
36
37 class Canvas;
38 class Group;
39 class Rect;     
40 class ScrollGroup;
41
42 /** The parent class for anything that goes on the canvas.
43  *
44  *  Items have a position, which is expressed in the coordinates of the parent.
45  *  They also have a bounding box, which describes the area in which they have
46  *  drawable content, which is expressed in their own coordinates (whose origin
47  *  is at the item position).
48  *
49  *  Any item that is being displayed on a canvas has a pointer to that canvas,
50  *  and all except the `root group' have a pointer to their parent group.
51  */
52         
53 class LIBCANVAS_API Item
54 {
55 public:
56         Item (Canvas *);
57         Item (Group *);
58         Item (Group *, Duple);
59         virtual ~Item ();
60
61         void redraw () const;
62
63         /** Render this item to a Cairo context.
64          *  @param area Area to draw, in **window** coordinates
65          *
66          *  Items must convert their own coordinates into window coordinates
67          *  because Cairo is limited to a fixed point coordinate space that
68          *  does not extend as far as the Ardour timeline. All rendering must
69          *  be done using coordinates that do not exceed the (rough) limits
70          *  of the canvas' window, to avoid odd errors within Cairo as it
71          *  converts doubles into its fixed point format and then tesselates
72          *  the results.
73          */
74         virtual void render (Rect const & area, Cairo::RefPtr<Cairo::Context>) const = 0;
75
76         /** Adds one or more items to the vector @param items based on their
77          * covering @param point which is in **window** coordinates
78          *
79          * Note that Item::add_items_at_window_point() is only intended to be 
80          * called on items already looked up in a LookupTable (i.e. by a
81          * parent group) and thus known to cover @param point already.
82          *
83          * Derived classes may add more items than themselves (e.g. Group).
84          */
85         virtual void add_items_at_point (Duple /*point*/, std::vector<Item const *>& items) const {
86                 items.push_back (this);
87         }
88
89         virtual bool covers (Duple const &) const;
90
91         /** Update _bounding_box and _bounding_box_dirty */
92         virtual void compute_bounding_box () const = 0;
93
94         void grab ();
95         void ungrab ();
96         
97         void unparent ();
98         void reparent (Group *);
99
100         /** @return Parent group, or 0 if this is the root group */
101         Group* parent () const {
102                 return _parent;
103         }
104     
105         uint32_t depth() const;
106         const Item* closest_ancestor_with (const Item& other) const;
107         bool common_ancestor_within (uint32_t, const Item& other) const;
108
109         /** returns true if this item is an ancestor of @param candidate,
110          * and false otherwise. 
111          */
112         bool is_ancestor_of (const Item& candidate) const {
113                 return candidate.is_descendant_of (*this);
114         }
115         /** returns true if this Item is a descendant of @param candidate,
116          * and false otherwise. 
117          */
118         bool is_descendant_of (const Item& candidate) const;
119
120         void set_position (Duple);
121         void set_x_position (Coord);
122         void set_y_position (Coord);
123         void move (Duple);
124
125         virtual void scroll_to (Duple const&) {}
126
127         /** @return Position of this item in the parent's coordinates */
128         Duple position () const {
129                 return _position;
130         }
131
132         Duple window_origin() const;
133         Duple canvas_origin() const;
134
135         ScrollGroup* scroll_parent() const { return _scroll_parent; }
136
137         boost::optional<Rect> bounding_box () const;
138         Coord height() const;
139         Coord width() const;
140
141         Duple item_to_parent (Duple const &) const;
142         Rect item_to_parent (Rect const &) const;
143         Duple parent_to_item (Duple const &) const;
144         Rect parent_to_item (Rect const &) const;
145
146         /* XXX: it's a pity these two aren't the same form as item_to_parent etc.,
147            but it makes a bit of a mess in the rest of the code if they are not.
148         */
149         void canvas_to_item (Coord &, Coord &) const;
150         void item_to_canvas (Coord &, Coord &) const;
151
152         Duple canvas_to_item (Duple const&) const;
153         Rect item_to_canvas (Rect const&) const;
154         Duple item_to_canvas (Duple const&) const;
155         Rect canvas_to_item (Rect const&) const;
156
157         Duple item_to_window (Duple const&, bool rounded = true) const;
158         Duple window_to_item (Duple const&) const;
159         Rect item_to_window (Rect const&) const;
160         Rect window_to_item (Rect const&) const;
161         
162         void raise_to_top ();
163         void raise (int);
164         void lower_to_bottom ();
165
166         void hide ();
167         void show ();
168
169         /** @return true if this item is visible (ie it will be rendered),
170          *  otherwise false
171          */
172         bool visible () const {
173                 return _visible;
174         }
175
176         /** @return Our canvas, or 0 if we are not attached to one */
177         Canvas* canvas () const {
178                 return _canvas;
179         }
180
181         void set_ignore_events (bool);
182         bool ignore_events () const {
183                 return _ignore_events;
184         }
185
186         void set_data (std::string const &, void *);
187         void* get_data (std::string const &) const;
188         
189         /* This is a sigc++ signal because it is solely
190            concerned with GUI stuff and is thus single-threaded
191         */
192
193         template <class T>
194         struct EventAccumulator {
195                 typedef T result_type;
196                 template <class U>
197                 result_type operator () (U first, U last) {
198                         while (first != last) {
199                                 if (*first) {
200                                         return true;
201                                 }
202                                 ++first;
203                         }
204                         return false;
205                 }
206         };
207         
208         sigc::signal1<bool, GdkEvent*, EventAccumulator<bool> > Event;
209
210 #ifdef CANVAS_DEBUG
211         std::string name;
212 #endif
213         
214 #ifdef CANVAS_COMPATIBILITY
215         void grab_focus ();
216 #endif  
217
218         virtual void dump (std::ostream&) const;
219         std::string whatami() const;
220
221 protected:
222
223         /** To be called at the beginning of any property change that
224          *  may alter the bounding box of this item
225          */
226         void begin_change ();
227         /** To be called at the endof any property change that
228          *  may alter the bounding box of this item
229          */
230         void end_change ();
231         /** To be called at the beginning of any property change that
232          *  does NOT alter the bounding box of this item
233          */
234         void begin_visual_change ();
235         /** To be called at the endof any property change that
236          *  does NOT alter the bounding box of this item
237          */
238         void end_visual_change ();
239
240         Canvas* _canvas;
241         /** parent group; may be 0 if we are the root group or if we have been unparent()ed */
242         Group* _parent;
243         /** scroll parent group; may be 0 if we are the root group or if we have been unparent()ed */
244         ScrollGroup* _scroll_parent;
245         /** position of this item in parent coordinates */
246         Duple _position;
247         /** true if this item is visible (ie to be drawn), otherwise false */
248         bool _visible;
249         /** our bounding box before any change that is currently in progress */
250         boost::optional<Rect> _pre_change_bounding_box;
251
252         /** our bounding box; may be out of date if _bounding_box_dirty is true */
253         mutable boost::optional<Rect> _bounding_box;
254         /** true if _bounding_box might be out of date, false if its definitely not */
255         mutable bool _bounding_box_dirty;
256
257         /* XXX: this is a bit grubby */
258         std::map<std::string, void *> _data;
259
260 private:
261         void init ();
262
263         bool _ignore_events;
264
265         Duple scroll_offset() const;
266         Duple position_offset() const;
267
268         void find_scroll_parent ();
269 };
270
271 extern LIBCANVAS_API std::ostream& operator<< (std::ostream&, const ArdourCanvas::Item&);
272
273 }
274
275
276 #endif