Remove LocaleGuards from SVAModifier and HSV classes
[ardour.git] / libs / canvas / box.cc
1 /*
2     Copyright (C) 2011-2014 Paul Davis
3     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 #include <algorithm>
21
22 #include "canvas/box.h"
23 #include "canvas/rectangle.h"
24
25 using namespace ArdourCanvas;
26
27 Box::Box (Canvas* canvas, Orientation o)
28         : Item (canvas)
29         , orientation (o)
30         , spacing (0)
31         , top_padding (0), right_padding (0), bottom_padding (0), left_padding (0)
32         , top_margin (0), right_margin (0), bottom_margin (0), left_margin (0)
33         , homogenous (false)
34 {
35         self = new Rectangle (this);
36         self->set_outline (false);
37         self->set_fill (false);
38 }
39
40 Box::Box (Item* parent, Orientation o)
41         : Item (parent)
42         , orientation (o)
43         , spacing (0)
44         , top_padding (0), right_padding (0), bottom_padding (0), left_padding (0)
45         , top_margin (0), right_margin (0), bottom_margin (0), left_margin (0)
46         , homogenous (false)
47 {
48         self = new Rectangle (this);
49         self->set_outline (false);
50         self->set_fill (false);
51 }
52
53
54 Box::Box (Item* parent, Duple const & p, Orientation o)
55         : Item (parent, p)
56         , orientation (o)
57         , spacing (0)
58         , top_padding (0), right_padding (0), bottom_padding (0), left_padding (0)
59         , top_margin (0), right_margin (0), bottom_margin (0), left_margin (0)
60         , homogenous (false)
61 {
62         self = new Rectangle (this);
63         self->set_outline (false);
64         self->set_fill (false);
65 }
66
67 void
68 Box::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context) const
69 {
70         Item::render_children (area, context);
71 }
72
73 void
74 Box::compute_bounding_box () const
75 {
76         _bounding_box = Rect();
77
78         if (_items.empty()) {
79                 _bounding_box_dirty = false;
80                 return;
81         }
82
83         add_child_bounding_boxes (!collapse_on_hide);
84
85         if (_bounding_box) {
86                 Rect r = _bounding_box;
87
88                 _bounding_box = r.expand (top_padding + outline_width() + top_margin,
89                                           right_padding + outline_width() + right_margin,
90                                           bottom_padding + outline_width() + bottom_margin,
91                                           left_padding + outline_width() + left_margin);
92         }
93
94         _bounding_box_dirty = false;
95 }
96
97 void
98 Box::set_spacing (double s)
99 {
100         spacing = s;
101 }
102
103 void
104 Box::set_padding (double t, double r, double b, double l)
105 {
106         double last = t;
107
108         top_padding = t;
109
110         if (r >= 0) {
111                 last = r;
112         }
113         right_padding = last;
114         if (b >= 0) {
115                 last = b;
116         }
117         bottom_padding = last;
118         if (l >= 0) {
119                 last = l;
120         }
121         left_padding = last;
122 }
123
124 void
125 Box::set_margin (double t, double r, double b, double l)
126 {
127         double last = t;
128         top_margin = t;
129         if (r >= 0) {
130                 last = r;
131         }
132         right_margin = last;
133         if (b >= 0) {
134                 last = b;
135         }
136         bottom_margin = last;
137         if (l >= 0) {
138                 last = l;
139         }
140         left_margin = last;
141 }
142
143 void
144 Box::reset_self ()
145 {
146         if (_bounding_box_dirty) {
147                 compute_bounding_box ();
148         }
149
150         if (!_bounding_box) {
151                 self->hide ();
152                 return;
153         }
154
155         Rect r (_bounding_box);
156
157         /* XXX need to shrink by margin */
158
159         self->set (r);
160 }
161
162 void
163 Box::reposition_children ()
164 {
165         Duple previous_edge (0, 0);
166         Distance largest_width = 0;
167         Distance largest_height = 0;
168         Rect uniform_size;
169
170         if (homogenous) {
171
172                 for (std::list<Item*>::iterator i = _items.begin(); ++i != _items.end(); ++i) {
173                         Rect bb = (*i)->bounding_box();
174                         if (bb) {
175                                 largest_height = std::max (largest_height, bb.height());
176                                 largest_width = std::max (largest_width, bb.width());
177                         }
178                 }
179
180                 uniform_size = Rect (0, 0, largest_width, largest_height);
181         }
182
183         for (std::list<Item*>::iterator i = _items.begin(); ++i != _items.end(); ++i) {
184
185                 (*i)->set_position (previous_edge);
186
187                 if (homogenous) {
188                         (*i)->size_allocate (uniform_size);
189                 }
190
191                 if (orientation == Vertical) {
192
193                         Distance shift = 0;
194
195                         Rect bb = (*i)->bounding_box();
196
197                         if (!(*i)->visible()) {
198                                 /* invisible child */
199                                 if (!collapse_on_hide) {
200                                         /* still add in its size */
201                                         if (bb) {
202                                                 shift += bb.height();
203                                                 }
204                                 }
205                         } else {
206                                 if (bb) {
207                                         shift += bb.height();
208                                 }
209                         }
210
211                         previous_edge = previous_edge.translate (Duple (0, spacing + shift));
212
213                 } else {
214
215                         Distance shift = 0;
216                         Rect bb = (*i)->bounding_box();
217
218                         if (!(*i)->visible()) {
219                                 if (!collapse_on_hide) {
220                                         if (bb) {
221                                                 shift += bb.width();
222                                         }
223                                 }
224                         } else {
225                                 if (bb) {
226                                         shift += bb.width();
227                                 }
228                         }
229
230                         previous_edge = previous_edge.translate (Duple (spacing + shift, 0));
231                 }
232         }
233
234         _bounding_box_dirty = true;
235         reset_self ();
236 }
237
238 void
239 Box::pack_end (Item* i, double extra_padding)
240 {
241         if (!i) {
242                 return;
243         }
244
245         /* prepend new child */
246         Item::add_front (i);
247         reposition_children ();
248 }
249 void
250 Box::pack_start (Item* i, double extra_padding)
251 {
252         if (!i) {
253                 return;
254         }
255
256         /* append new child */
257         Item::add (i);
258         reposition_children ();
259 }
260
261 void
262 Box::add (Item* i)
263 {
264         pack_start (i);
265 }
266
267 void
268 Box::child_changed ()
269 {
270         /* catch visibility and size changes */
271
272         Item::child_changed ();
273         reposition_children ();
274 }
275
276 void
277 Box::set_collapse_on_hide (bool yn)
278 {
279         if (collapse_on_hide != yn) {
280                 collapse_on_hide = yn;
281                 reposition_children ();
282         }
283 }
284
285 /*----*/
286
287 VBox::VBox (Canvas* c)
288         : Box (c, Vertical)
289 {
290 }
291 VBox::VBox (Item* i)
292         : Box (i, Vertical)
293 {
294 }
295 VBox::VBox (Item* i, Duple const & position)
296         : Box (i, position, Vertical)
297 {
298 }
299
300 HBox::HBox (Canvas* c)
301         : Box (c, Horizontal)
302 {
303 }
304 HBox::HBox (Item* i)
305         : Box (i, Horizontal)
306 {
307 }
308 HBox::HBox (Item* i, Duple const & position)
309         : Box (i, position, Horizontal)
310 {
311 }