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::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context) const
70 Item::render_children (area, context);
74 Grid::compute_bounding_box () const
76 _bounding_box = Rect();
79 _bounding_box_dirty = false;
83 add_child_bounding_boxes (!collapse_on_hide);
86 Rect r = _bounding_box;
88 _bounding_box = r.expand (outline_width() + top_margin,
89 outline_width() + right_margin,
90 outline_width() + bottom_margin,
91 outline_width() + left_margin);
94 _bounding_box_dirty = false;
98 Grid::set_spacing (double s)
104 Grid::set_padding (double t, double r, double b, double l)
113 right_padding = last;
117 bottom_padding = last;
125 Grid::set_margin (double t, double r, double b, double l)
136 bottom_margin = last;
146 if (_bounding_box_dirty) {
147 compute_bounding_box ();
150 if (!_bounding_box) {
155 Rect r (_bounding_box);
157 /* XXX need to shrink by margin */
163 Grid::reposition_children ()
165 uint32_t max_row = 0;
166 uint32_t max_col = 0;
168 /* since we encourage dynamic and essentially random placement of
169 * children, begin by determining the maximum row and column given
170 * our current set of children and placements.
173 for (CoordsByItem::const_iterator c = coords_by_item.begin(); c != coords_by_item.end(); ++c) {
174 max_col = max (max_col, (uint32_t) c->second.x);
175 max_row = max (max_row, (uint32_t) c->second.y);
181 /* Now compute the width of the widest child for each column, and the
182 * height of the tallest child for each row.
185 vector<double> row_dimens;
186 vector<double> col_dimens;
188 row_dimens.assign (max_row, 0);
189 col_dimens.assign (max_col, 0);
191 for (std::list<Item*>::iterator i = _items.begin(); i != _items.end(); ++i) {
194 /* self-rect is not a normal child */
198 Rect bb = (*i)->bounding_box();
204 CoordsByItem::const_iterator c = coords_by_item.find (*i);
206 row_dimens[c->second.y] = max (row_dimens[c->second.y], bb.height());
207 col_dimens[c->second.x] = max (col_dimens[c->second.x] , bb.width());
210 /* now sum the row and column widths, so that row_dimens is transformed
211 * into the y coordinate of the upper left of each row, and col_dimens
212 * is transformed into the x coordinate of the left edge of each
216 double current_top_edge = top_margin;
218 for (uint32_t n = 0; n < max_row; ++n) {
220 /* height defined for this row */
221 const double h = row_dimens[n]; /* save height */
222 row_dimens[n] = current_top_edge;
223 current_top_edge = current_top_edge + h + top_padding + bottom_padding;
227 double current_right_edge = left_margin;
229 for (uint32_t n = 0; n < max_col; ++n) {
231 /* a width was defined for this column */
232 const double w = col_dimens[n]; /* save width of this column */
233 col_dimens[n] = current_right_edge;
234 current_right_edge = current_right_edge + w + left_padding + right_padding;
238 /* position each item at the upper left of its (row, col) coordinate,
239 * given the width of all rows or columns before it.
242 for (std::list<Item*>::iterator i = _items.begin(); i != _items.end(); ++i) {
243 CoordsByItem::const_iterator c = coords_by_item.find (*i);
245 if (c == coords_by_item.end()) {
249 (*i)->set_position (Duple (col_dimens[c->second.x], row_dimens[c->second.y]));
252 _bounding_box_dirty = true;
257 Grid::place (Item* i, Duple at)
260 coords_by_item.insert (std::make_pair (i, at));
261 reposition_children ();
265 Grid::child_changed ()
267 /* catch visibility and size changes */
269 Item::child_changed ();
270 reposition_children ();
274 Grid::set_collapse_on_hide (bool yn)
276 if (collapse_on_hide != yn) {
277 collapse_on_hide = yn;
278 reposition_children ();