2 Copyright (C) 2018 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "canvas/grid.h"
23 #include "canvas/rectangle.h"
25 using namespace ArdourCanvas;
31 Grid::Grid (Canvas* canvas)
34 , top_padding (0), right_padding (0), bottom_padding (0), left_padding (0)
35 , top_margin (0), right_margin (0), bottom_margin (0), left_margin (0)
38 self = new Rectangle (this);
39 self->set_outline (false);
40 self->set_fill (false);
43 Grid::Grid (Item* parent)
46 , top_padding (0), right_padding (0), bottom_padding (0), left_padding (0)
47 , top_margin (0), right_margin (0), bottom_margin (0), left_margin (0)
50 self = new Rectangle (this);
51 self->set_outline (false);
52 self->set_fill (false);
55 Grid::Grid (Item* parent, Duple const & p)
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)
62 self = new Rectangle (this);
63 self->set_outline (false);
64 self->set_fill (false);
68 Grid::set_homogenous (bool yn)
74 Grid::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context) const
76 Item::render_children (area, context);
80 Grid::compute_bounding_box () const
82 _bounding_box = Rect();
85 _bounding_box_dirty = false;
89 add_child_bounding_boxes (!collapse_on_hide);
92 Rect r = _bounding_box;
94 _bounding_box = r.expand (outline_width() + top_margin,
95 outline_width() + right_margin,
96 outline_width() + bottom_margin,
97 outline_width() + left_margin);
100 _bounding_box_dirty = false;
104 Grid::set_spacing (double s)
110 Grid::set_padding (double t, double r, double b, double l)
119 right_padding = last;
123 bottom_padding = last;
131 Grid::set_margin (double t, double r, double b, double l)
142 bottom_margin = last;
152 if (_bounding_box_dirty) {
153 compute_bounding_box ();
156 if (!_bounding_box) {
161 Rect r (_bounding_box);
163 /* XXX need to shrink by margin */
169 Grid::reposition_children ()
171 uint32_t max_row = 0;
172 uint32_t max_col = 0;
174 /* since we encourage dynamic and essentially random placement of
175 * children, begin by determining the maximum row and column given
176 * our current set of children and placements.
179 for (CoordsByItem::const_iterator c = coords_by_item.begin(); c != coords_by_item.end(); ++c) {
180 max_col = max (max_col, (uint32_t) c->second.x);
181 max_row = max (max_row, (uint32_t) c->second.y);
187 /* Now compute the width of the widest child for each column, and the
188 * height of the tallest child for each row.
191 vector<double> row_dimens;
192 vector<double> col_dimens;
194 row_dimens.assign (max_row, 0);
195 col_dimens.assign (max_col, 0);
200 for (std::list<Item*>::iterator i = _items.begin(); i != _items.end(); ++i) {
206 Rect bb = (*i)->bounding_box();
211 cerr << "\tbb for " << (*i)->whatami() << " is " << bb << endl;
212 uniform_size.y1 = max (uniform_size.y1, bb.height());
213 uniform_size.x1 = max (uniform_size.x1, bb.width());
216 cerr << "Uniform size will be " << uniform_size << endl;
218 for (std::list<Item*>::iterator i = _items.begin(); i != _items.end(); ++i) {
220 /* self-rect is not a normal child */
223 (*i)->size_allocate (uniform_size);
224 for (uint32_t n = 0; n < max_col; ++n) {
225 col_dimens[n] = uniform_size.width();
227 for (uint32_t n = 0; n < max_row; ++n) {
228 row_dimens[n] = uniform_size.height();
232 for (std::list<Item*>::iterator i = _items.begin(); i != _items.end(); ++i) {
235 /* self-rect is not a normal child */
239 Rect bb = (*i)->bounding_box();
245 CoordsByItem::const_iterator c = coords_by_item.find (*i);
247 row_dimens[c->second.y] = max (row_dimens[c->second.y], bb.height());
248 col_dimens[c->second.x] = max (col_dimens[c->second.x] , bb.width());
252 /* now sum the row and column widths, so that row_dimens is transformed
253 * into the y coordinate of the upper left of each row, and col_dimens
254 * is transformed into the x coordinate of the left edge of each
258 double current_top_edge = top_margin;
260 for (uint32_t n = 0; n < max_row; ++n) {
262 /* height defined for this row */
263 const double h = row_dimens[n]; /* save height */
264 row_dimens[n] = current_top_edge;
265 cerr << "row[" << n << "] @ " << row_dimens[n] << endl;
266 current_top_edge = current_top_edge + h + top_padding + bottom_padding;
270 double current_right_edge = left_margin;
272 for (uint32_t n = 0; n < max_col; ++n) {
274 /* a width was defined for this column */
275 const double w = col_dimens[n]; /* save width of this column */
276 col_dimens[n] = current_right_edge;
277 cerr << "col[" << n << "] @ " << col_dimens[n] << endl;
278 current_right_edge = current_right_edge + w + left_padding + right_padding;
282 /* position each item at the upper left of its (row, col) coordinate,
283 * given the width of all rows or columns before it.
286 for (std::list<Item*>::iterator i = _items.begin(); i != _items.end(); ++i) {
287 CoordsByItem::const_iterator c = coords_by_item.find (*i);
289 if (c == coords_by_item.end()) {
293 (*i)->set_position (Duple (col_dimens[c->second.x], row_dimens[c->second.y]));
294 cerr << "place " << (*i)->whatami() << " @ " << c->second.x << ", " << c->second.y << " at "
295 << Duple (col_dimens[c->second.x], row_dimens[c->second.y])
299 _bounding_box_dirty = true;
304 Grid::place (Item* i, Duple at)
307 coords_by_item.insert (std::make_pair (i, at));
308 reposition_children ();
312 Grid::child_changed ()
314 /* catch visibility and size changes */
316 Item::child_changed ();
317 reposition_children ();
321 Grid::set_collapse_on_hide (bool yn)
323 if (collapse_on_hide != yn) {
324 collapse_on_hide = yn;
325 reposition_children ();