remove all xml++.h inclusion by canvas implementations
[ardour.git] / libs / canvas / item.cc
1 #include "pbd/compose.h"
2 #include "pbd/stacktrace.h"
3 #include "pbd/convert.h"
4
5 #include "ardour/utils.h"
6
7 #include "canvas/group.h"
8 #include "canvas/item.h"
9 #include "canvas/canvas.h"
10 #include "canvas/debug.h"
11
12 using namespace std;
13 using namespace PBD;
14 using namespace ArdourCanvas;
15
16 Item::Item (Canvas* canvas)
17         : _canvas (canvas)
18         , _parent (0)
19 {
20         init ();
21 }
22
23 Item::Item (Group* parent)
24         : _canvas (parent->canvas ())
25         , _parent (parent)
26 {
27         init ();
28 }
29
30 Item::Item (Group* parent, Duple position)
31         : _canvas (parent->canvas())
32         , _parent (parent)
33         , _position (position)
34 {
35         init ();
36 }
37
38 void
39 Item::init ()
40 {
41         _visible = true;
42         _bounding_box_dirty = true;
43         _ignore_events = false;
44         
45         if (_parent) {
46                 _parent->add (this);
47         }
48
49         DEBUG_TRACE (DEBUG::CanvasItems, string_compose ("new canvas item %1\n", this));
50 }       
51
52 Item::~Item ()
53 {
54         if (_canvas) {
55                 _canvas->item_going_away (this, _bounding_box);
56         }
57         
58         if (_parent) {
59                 _parent->remove (this);
60         }
61 }
62
63 ArdourCanvas::Rect
64 Item::item_to_parent (ArdourCanvas::Rect const & r) const
65 {
66         return r.translate (_position);
67 }
68
69 ArdourCanvas::Rect
70 Item::item_to_canvas (ArdourCanvas::Rect const & r) const
71 {
72         Item const * i = this;
73         Duple offset;
74
75         while (i) {
76                 offset = offset.translate (i->position());
77                 i = i->parent();
78         }
79
80         return r.translate (offset);
81 }
82
83 ArdourCanvas::Duple
84 Item::item_to_canvas (ArdourCanvas::Duple const & d) const
85 {
86         Item const * i = this;
87         Duple offset;
88
89         while (i) {
90                 offset = offset.translate (i->position());
91                 i = i->parent();
92         }
93
94         return d.translate (offset);
95 }
96
97 ArdourCanvas::Duple
98 Item::canvas_to_item (ArdourCanvas::Duple const & d) const
99 {
100         Item const * i = this;
101         Duple offset;
102
103         while (i) {
104                 offset = offset.translate (-(i->position()));
105                 i = i->parent();
106         }
107
108         return d.translate (offset);
109 }
110
111 void
112 Item::item_to_canvas (Coord& x, Coord& y) const
113 {
114         Duple d = item_to_canvas (Duple (x, y));
115                 
116         x = d.x;
117         y = d.y;
118 }
119
120 void
121 Item::canvas_to_item (Coord& x, Coord& y) const
122 {
123         Duple d = canvas_to_item (Duple (x, y));
124
125         x = d.x;
126         y = d.y;
127 }
128
129 /** Set the position of this item in the parent's coordinates */
130 void
131 Item::set_position (Duple p)
132 {
133         boost::optional<ArdourCanvas::Rect> bbox = bounding_box ();
134         boost::optional<ArdourCanvas::Rect> pre_change_parent_bounding_box;
135
136         if (bbox) {
137                 /* see the comment in Canvas::item_moved() to understand
138                  * why we use the parent's bounding box here.
139                  */
140                 pre_change_parent_bounding_box = item_to_parent (bbox.get());
141         }
142         
143         _position = p;
144
145         _canvas->item_moved (this, pre_change_parent_bounding_box);
146
147         if (_parent) {
148                 _parent->child_changed ();
149         }
150 }
151
152 void
153 Item::set_x_position (Coord x)
154 {
155         set_position (Duple (x, _position.y));
156 }
157
158 void
159 Item::set_y_position (Coord y)
160 {
161         set_position (Duple (_position.x, y));
162 }
163
164 void
165 Item::raise_to_top ()
166 {
167         assert (_parent);
168         _parent->raise_child_to_top (this);
169 }
170
171 void
172 Item::raise (int levels)
173 {
174         assert (_parent);
175         _parent->raise_child (this, levels);
176 }
177
178 void
179 Item::lower_to_bottom ()
180 {
181         assert (_parent);
182         _parent->lower_child_to_bottom (this);
183 }
184
185 void
186 Item::hide ()
187 {
188         _visible = false;
189         _canvas->item_shown_or_hidden (this);
190 }
191
192 void
193 Item::show ()
194 {
195         _visible = true;
196         _canvas->item_shown_or_hidden (this);
197 }
198
199 Duple
200 Item::item_to_parent (Duple const & d) const
201 {
202         return d.translate (_position);
203 }
204
205 Duple
206 Item::parent_to_item (Duple const & d) const
207 {
208         return d.translate (- _position);
209 }
210
211 ArdourCanvas::Rect
212 Item::parent_to_item (ArdourCanvas::Rect const & d) const
213 {
214         return d.translate (- _position);
215 }
216
217 void
218 Item::unparent ()
219 {
220         _canvas = 0;
221         _parent = 0;
222 }
223
224 void
225 Item::reparent (Group* new_parent)
226 {
227         if (_parent) {
228                 _parent->remove (this);
229         }
230
231         assert (new_parent);
232
233         _parent = new_parent;
234         _canvas = _parent->canvas ();
235         _parent->add (this);
236 }
237
238 void
239 Item::grab_focus ()
240 {
241         /* XXX */
242 }
243
244 /** @return Bounding box in this item's coordinates */
245 boost::optional<ArdourCanvas::Rect>
246 Item::bounding_box () const
247 {
248         if (_bounding_box_dirty) {
249                 compute_bounding_box ();
250         }
251
252         assert (!_bounding_box_dirty);
253         return _bounding_box;
254 }
255
256 Coord
257 Item::height () const 
258 {
259         boost::optional<ArdourCanvas::Rect> bb  = bounding_box();
260
261         if (bb) {
262                 return bb->height ();
263         }
264         return 0;
265 }
266
267 Coord
268 Item::width () const 
269 {
270         boost::optional<ArdourCanvas::Rect> bb = bounding_box().get();
271
272         if (bb) {
273                 return bb->width ();
274         }
275
276         return 0;
277 }
278
279 /* XXX may be called even if bbox is not changing ... bit grotty */
280 void
281 Item::begin_change ()
282 {
283         _pre_change_bounding_box = bounding_box ();
284 }
285
286 void
287 Item::end_change ()
288 {
289         _canvas->item_changed (this, _pre_change_bounding_box);
290         
291         if (_parent) {
292                 _parent->child_changed ();
293         }
294 }
295
296 void
297 Item::move (Duple movement)
298 {
299         set_position (position() + movement);
300 }
301
302 void
303 Item::grab ()
304 {
305         assert (_canvas);
306         _canvas->grab (this);
307 }
308
309 void
310 Item::ungrab ()
311 {
312         assert (_canvas);
313         _canvas->ungrab ();
314 }
315
316 void
317 Item::set_data (string const & key, void* data)
318 {
319         _data[key] = data;
320 }
321
322 void *
323 Item::get_data (string const & key) const
324 {
325         map<string, void*>::const_iterator i = _data.find (key);
326         if (i == _data.end ()) {
327                 return 0;
328         }
329         
330         return i->second;
331 }
332
333 void
334 Item::set_ignore_events (bool ignore)
335 {
336         _ignore_events = ignore;
337 }
338
339 void
340 Item::dump (ostream& o) const
341 {
342         boost::optional<ArdourCanvas::Rect> bb = bounding_box();
343
344         o << _canvas->indent() << whatami() << ' ' << this;
345         o << " @ " << position();
346         
347 #ifdef CANVAS_DEBUG
348         if (!name.empty()) {
349                 o << ' ' << name;
350         }
351 #endif
352
353         if (bb) {
354                 o << endl << _canvas->indent() << "\tbbox: " << bb.get();
355                 o << endl << _canvas->indent() << "\tCANVAS bbox: " << item_to_canvas (bb.get());
356         } else {
357                 o << " bbox unset";
358         }
359
360         o << endl;
361 }
362
363 std::string
364 Item::whatami () const 
365 {
366         std::string type = demangle (typeid (*this).name());
367         return type.substr (type.find_last_of (':') + 1);
368 }
369
370 ostream&
371 ArdourCanvas::operator<< (ostream& o, const Item& i)
372 {
373         i.dump (o);
374         return o;
375 }