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 = boost::none;
79 _bounding_box_dirty = false;
83 add_child_bounding_boxes (!collapse_on_hide);
86 Rect r = _bounding_box.get();
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);
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.get());
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);
178 cerr << "max row = " << max_row << " max_col " << max_col << endl;
179 cerr << "with items = " << _items.size() << " coords " << coords_by_item.size()<< endl;
184 /* Now compute the width of the widest child for each column, and the
185 * height of the tallest child for each row.
188 vector<double> row_dimens;
189 vector<double> col_dimens;
191 row_dimens.assign (max_row, 0);
192 col_dimens.assign (max_col, 0);
194 for (std::list<Item*>::iterator i = _items.begin(); ++i != _items.end(); ++i) {
195 boost::optional<Rect> bb = (*i)->bounding_box();
198 cerr << "no bounding box\n";
202 CoordsByItem::const_iterator c = coords_by_item.find (*i);
204 cerr << "item BB = " << bb.get() << endl;
206 row_dimens[c->second.y] = max (row_dimens[c->second.y], bb.get().height());
207 col_dimens[c->second.x] = max (col_dimens[c->second.x] , bb.get().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 prev = row_dimens[0];
219 for (uint32_t n = 1; n < max_row; ++n) {
220 row_dimens[n] = row_dimens[n-1] + prev;
221 cerr << "B: row[" << n << "] @ " << row_dimens[n] << endl;
222 prev = row_dimens[n];
225 prev = col_dimens[0];
228 for (uint32_t n = 1; n < max_col; ++n) {
229 col_dimens[n] = col_dimens[n-1] + prev;
230 cerr << "B: col[" << n << "] @ " << col_dimens[n] << endl;
231 prev = col_dimens[n];
234 /* position each item at the upper left of its (row, col) coordinate,
235 * given the width of all rows or columns before it.
238 for (std::list<Item*>::iterator i = _items.begin(); ++i != _items.end(); ++i) {
239 CoordsByItem::const_iterator c = coords_by_item.find (*i);
241 if (c == coords_by_item.end()) {
242 cerr << "item not found\n";
246 cerr << " place item at " << Duple (col_dimens[c->second.x], row_dimens[c->second.y]) << endl;
247 (*i)->set_position (Duple (col_dimens[c->second.x], row_dimens[c->second.y]));
250 _bounding_box_dirty = true;
259 Grid::place (Item* i, Duple at)
262 coords_by_item.insert (std::make_pair (i, at));
263 reposition_children ();
267 Grid::child_changed ()
269 cerr << "Child changed!\n";
270 /* catch visibility and size changes */
272 Item::child_changed ();
273 reposition_children ();
277 Grid::set_collapse_on_hide (bool yn)
279 if (collapse_on_hide != yn) {
280 collapse_on_hide = yn;
281 reposition_children ();