Grid layout changes: support minimized rows/columns + support skipping outer outline
This commit is contained in:
parent
4ba85c9e79
commit
bf9e279952
2 changed files with 107 additions and 29 deletions
|
|
@ -32,6 +32,9 @@ namespace psemek::ui
|
|||
virtual std::shared_ptr<element> set(std::size_t i, std::size_t j, std::shared_ptr<element> c);
|
||||
virtual std::shared_ptr<element> remove(std::size_t i, std::size_t j);
|
||||
|
||||
virtual void set_outer_margin(bool value);
|
||||
virtual bool outer_margin() const { return outer_margin_; }
|
||||
|
||||
geom::box<float, 2> size_constraints() const override;
|
||||
|
||||
struct shape const & shape() const override { return shape_; }
|
||||
|
|
@ -46,6 +49,8 @@ namespace psemek::ui
|
|||
std::vector<float> row_weight_;
|
||||
std::vector<float> column_weight_;
|
||||
|
||||
bool outer_margin_ = true;
|
||||
|
||||
box_shape shape_;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@
|
|||
namespace psemek::ui
|
||||
{
|
||||
|
||||
static float const inf = std::numeric_limits<float>::infinity();
|
||||
|
||||
element::children_range grid_layout::children() const
|
||||
{
|
||||
return children_range{children_range_.data(), children_range_.data() + children_range_.size()};
|
||||
|
|
@ -119,44 +121,65 @@ namespace psemek::ui
|
|||
return set(i, j, nullptr);
|
||||
}
|
||||
|
||||
geom::box<float, 2> grid_layout::size_constraints() const
|
||||
void grid_layout::set_outer_margin(bool value)
|
||||
{
|
||||
auto st = merged_style();
|
||||
if (!st) return element::size_constraints();
|
||||
outer_margin_ = value;
|
||||
post_reshape();
|
||||
}
|
||||
|
||||
static float const inf = std::numeric_limits<float>::infinity();
|
||||
static std::pair<std::vector<geom::interval<float>>, std::vector<geom::interval<float>>> row_column_sizes(util::array<std::shared_ptr<element>, 2> const & children)
|
||||
{
|
||||
std::vector<geom::interval<float>> row_size(children.width(), {0.f, inf});
|
||||
std::vector<geom::interval<float>> column_size(children.height(), {0.f, inf});
|
||||
|
||||
std::vector<geom::interval<float>> row_size(row_count(), {0.f, inf});
|
||||
std::vector<geom::interval<float>> column_size(column_count(), {0.f, inf});
|
||||
|
||||
for (std::size_t i = 0; i < row_count(); ++i)
|
||||
for (std::size_t i = 0; i < children.width(); ++i)
|
||||
{
|
||||
for (std::size_t j = 0; j < column_count(); ++j)
|
||||
for (std::size_t j = 0; j < children.height(); ++j)
|
||||
{
|
||||
if (!get(i, j)) continue;
|
||||
auto c = children(i, j);
|
||||
if (!c) continue;
|
||||
|
||||
auto sc = get(i, j)->size_constraints();
|
||||
auto sc = c->size_constraints();
|
||||
row_size[i] &= sc[1];
|
||||
column_size[j] &= sc[0];
|
||||
}
|
||||
}
|
||||
|
||||
return {std::move(row_size), std::move(column_size)};
|
||||
}
|
||||
|
||||
geom::box<float, 2> grid_layout::size_constraints() const
|
||||
{
|
||||
auto st = merged_style();
|
||||
if (!st) return element::size_constraints();
|
||||
|
||||
auto row_column_size = row_column_sizes(children_);
|
||||
auto const & row_size = row_column_size.first;
|
||||
auto const & column_size = row_column_size.second;
|
||||
|
||||
geom::box<float, 2> result{{{0.f, 0.f}, {0.f, 0.f}}};
|
||||
|
||||
for (std::size_t i = 0; i < row_count(); ++i)
|
||||
{
|
||||
bool const minimized = (row_weight_[i] == 0.f);
|
||||
|
||||
result[1].min += row_size[i].min;
|
||||
result[1].max += row_size[i].max;
|
||||
result[1].max += minimized ? row_size[i].min : row_size[i].max;
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < column_count(); ++i)
|
||||
{
|
||||
bool const minimized = (column_weight_[i] == 0.f);
|
||||
|
||||
result[0].min += column_size[i].min;
|
||||
result[0].max += column_size[i].max;
|
||||
result[0].max += minimized ? column_size[i].min : column_size[i].max;
|
||||
}
|
||||
|
||||
result[1] += (row_count() + 1) * (*st->outer_margin);
|
||||
result[0] += (column_count() + 1) * (*st->outer_margin);
|
||||
int const margin_row_count = (std::max<int>(1, row_count()) + (outer_margin_ ? 1 : -1));
|
||||
int const margin_column_count = (std::max<int>(1, column_count()) + (outer_margin_ ? 1 : -1));
|
||||
|
||||
result[1] += margin_row_count * (*st->outer_margin);
|
||||
result[0] += margin_column_count * (*st->outer_margin);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
@ -168,8 +191,15 @@ namespace psemek::ui
|
|||
|
||||
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()));
|
||||
auto row_column_size = row_column_sizes(children_);
|
||||
auto const & row_size = row_column_size.first;
|
||||
auto const & column_size = row_column_size.second;
|
||||
|
||||
int const margin_row_count = (std::max<int>(1, row_count()) + (outer_margin_ ? 1 : -1));
|
||||
int const margin_column_count = (std::max<int>(1, column_count()) + (outer_margin_ ? 1 : -1));
|
||||
|
||||
float available_height = std::max(0.f, bbox[1].length() - margin * margin_row_count);
|
||||
float available_width = std::max(0.f, bbox[0].length() - margin * margin_column_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);
|
||||
|
|
@ -177,26 +207,69 @@ namespace psemek::ui
|
|||
std::vector<geom::interval<float>> row_shape(row_count());
|
||||
std::vector<geom::interval<float>> column_shape(column_count());
|
||||
|
||||
// First, allocate minimized rows
|
||||
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;
|
||||
if (row_weight_[i] == 0.f)
|
||||
{
|
||||
row_shape[i] = {0.f, row_size[i].min};
|
||||
available_height -= row_size[i].min;
|
||||
}
|
||||
}
|
||||
|
||||
available_height = std::max(available_height, 0.f);
|
||||
|
||||
// Next, allocate scalable rows
|
||||
for (std::size_t i = 0; i < row_count(); ++i)
|
||||
{
|
||||
if (row_weight_[i] == 0.f)
|
||||
continue;
|
||||
|
||||
float const row_height = available_height * row_weight_[i] / row_weight_sum;
|
||||
row_shape[i] = {0.f, row_height};
|
||||
}
|
||||
|
||||
// Finally, move rows one after another
|
||||
for (std::size_t i = 0; i < row_count(); ++i)
|
||||
{
|
||||
if (i == 0)
|
||||
row_shape[i] += bbox[1].min + (outer_margin_ ? margin : 0.f);
|
||||
else
|
||||
row_shape[i] += row_shape[i - 1].max + margin;
|
||||
}
|
||||
|
||||
// First, allocate minimized columns
|
||||
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;
|
||||
if (column_weight_[i] == 0.f)
|
||||
{
|
||||
column_shape[i] = {0.f, column_size[i].min};
|
||||
available_width -= column_size[i].min;
|
||||
}
|
||||
}
|
||||
|
||||
available_width = std::max(available_width, 0.f);
|
||||
|
||||
// Next, allocate scalable columns
|
||||
for (std::size_t i = 0; i < column_count(); ++i)
|
||||
{
|
||||
if (column_weight_[i] == 0.f)
|
||||
continue;
|
||||
|
||||
float const column_width = available_width * column_weight_[i] / column_weight_sum;
|
||||
column_shape[i] = {0.f, column_width};
|
||||
}
|
||||
|
||||
// Finally, move rows one after another
|
||||
for (std::size_t i = 0; i < column_count(); ++i)
|
||||
{
|
||||
if (i == 0)
|
||||
column_shape[i] += bbox[0].min + (outer_margin_ ? margin : 0.f);
|
||||
else
|
||||
column_shape[i] += column_shape[i - 1].max + margin;
|
||||
}
|
||||
|
||||
// Apply calculated shapes
|
||||
for (std::size_t i = 0; i < row_count(); ++i)
|
||||
{
|
||||
for (std::size_t j = 0; j < column_count(); ++j)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue