#include #include namespace psemek::ui { element::children_range grid_layout::children() const { return children_range{children_range_.data(), children_range_.data() + children_range_.size()}; } bool grid_layout::add_child(std::shared_ptr c) { for (std::size_t i = 0; i < row_count(); ++i) { for (std::size_t j = 0; j < column_count(); ++j) { if (!get(i, j)) { set(i, j, std::move(c)); return true; } } } return false; } bool grid_layout::has_child(element * c) const { for (std::size_t i = 0; i < row_count(); ++i) for (std::size_t j = 0; j < column_count(); ++j) if (get(i, j) == c) return true; return false; } std::shared_ptr grid_layout::remove_child(element * c) { for (std::size_t i = 0; i < row_count(); ++i) { for (std::size_t j = 0; j < column_count(); ++j) { if (get(i, j) == c) { return remove(i, j); } } } return nullptr; } void grid_layout::set_row_count(std::size_t count) { set_size(count, column_count()); } void grid_layout::set_column_count(std::size_t count) { set_size(row_count(), count); } void grid_layout::set_size(std::size_t rows, std::size_t columns) { std::size_t const old_row_count = row_count(); std::size_t const old_column_count = column_count(); children_.resize({rows, columns}); children_range_.resize(rows * columns); for (std::size_t i = 0; i < rows; ++i) { for (std::size_t j = 0; j < columns; ++j) { children_range_[i * columns + j] = children_(i, j).get(); } } row_weight_.resize(rows); for (std::size_t i = old_row_count; i < rows; ++i) row_weight_[i] = 1.f; column_weight_.resize(columns); for (std::size_t i = old_column_count; i < columns; ++i) column_weight_[i] = 1.f; post_reshape(); } void grid_layout::set_row_weight(std::size_t i, float w) { row_weight_.at(i) = w; post_reshape(); } void grid_layout::set_column_weight(std::size_t i, float w) { column_weight_.at(i) = w; post_reshape(); } element * grid_layout::get(std::size_t i, std::size_t j) const { return children_(i, j).get(); } std::shared_ptr grid_layout::set(std::size_t i, std::size_t j, std::shared_ptr c) { auto old = std::move(children_(i, j)); if (old) old->set_parent(nullptr); if (c) c->set_parent(this); children_range_[i * column_count() + j] = c.get(); children_(i, j) = std::move(c); post_reshape(); return old; } std::shared_ptr grid_layout::remove(std::size_t i, std::size_t j) { return set(i, j, nullptr); } geom::box grid_layout::size_constraints() const { auto st = style(); if (!st) return element::size_constraints(); static float const inf = std::numeric_limits::infinity(); std::vector> row_size(row_count(), {0.f, inf}); std::vector> column_size(column_count(), {0.f, inf}); for (std::size_t i = 0; i < row_count(); ++i) { for (std::size_t j = 0; j < column_count(); ++j) { if (!get(i, j)) continue; auto sc = get(i, j)->size_constraints(); row_size[i] &= sc[1]; column_size[j] &= sc[0]; } } geom::box result{{{0.f, 0.f}, {0.f, 0.f}}}; for (std::size_t i = 0; i < row_count(); ++i) { result[1].min += row_size[i].min; result[1].max += row_size[i].max; } for (std::size_t i = 0; i < column_count(); ++i) { result[0].min += column_size[i].min; result[0].max += column_size[i].max; } result[1] += (row_count() + 1) * st->outer_margin; result[0] += (column_count() + 1) * st->outer_margin; return result; } void grid_layout::reshape(geom::box const & bbox) { auto st = style(); if (!st) return; float const margin = st->outer_margin; float const available_width = std::max(0.f, bbox[0].length() - margin * (1 + column_count())); float const available_height = std::max(0.f, bbox[1].length() - margin * (1 + row_count())); float const row_weight_sum = std::accumulate(row_weight_.begin(), row_weight_.end(), 0.f); float const column_weight_sum = std::accumulate(column_weight_.begin(), column_weight_.end(), 0.f); std::vector> row_shape(row_count()); std::vector> column_shape(column_count()); for (std::size_t i = 0; i < row_count(); ++i) { float const row_height = available_height * row_weight_[i] / row_weight_sum; row_shape[i] = {margin, margin + row_height}; if (i == 0) row_shape[i] += bbox[1].min; else row_shape[i] += row_shape[i - 1].max; } for (std::size_t i = 0; i < column_count(); ++i) { float const column_width = available_width * column_weight_[i] / column_weight_sum; column_shape[i] = {margin, margin + column_width}; if (i == 0) column_shape[i] += bbox[0].min; else column_shape[i] += column_shape[i - 1].max; } for (std::size_t i = 0; i < row_count(); ++i) { for (std::size_t j = 0; j < column_count(); ++j) { if (!get(i, j)) continue; get(i, j)->reshape({{column_shape[j], row_shape[i]}}); } } } }