Open
Description
While using layout library in my project I've come across somewhat unexpected layouting behaviour.
Minimal reproducible example follows:
- Create root item of arbitrary size, without any additional configuration it acts as layout container
- In that root insert row container with unfixed size
- In that row container insert item with fixed size, and margin from the bottom
Equivalent code:
lay_id root = lay_item(ctx);
lay_set_size_xy(ctx, root, 1, 100);
lay_id row = lay_item(ctx);
lay_set_contain(ctx, row, LAY_ROW);
lay_insert(ctx, root, row);
lay_id child = lay_item(ctx);
lay_set_size_xy(ctx, child, 1, 50);
lay_set_margins_ltrb(ctx, child, 0, 0, 0, 10);
lay_insert(ctx, row, child);
In a case like that I would expect the following
- row's height becomes 60, since item's height is 50 + item's bottom margin is 10
- item is placed at the begginng of the row (row pos = [0, 20], item pos = [0,20])
It can be validated by a test:
lay_run_context(ctx);
lay_vec4 root_rect = lay_get_rect(ctx, root);
lay_vec4 row_rect = lay_get_rect(ctx, row);
lay_vec4 child_rect = lay_get_rect(ctx, child);
LTEST_VEC4EQ(root_rect, 0, 0, 1, 100);
LTEST_VEC4EQ(row_rect, 0, 20, 1, 60);
LTEST_VEC4EQ(child_rect, 0, 20, 1, 50);
It is consistent with like other layout engines implement margins (like yoga layout or flexboxes in basically all modern browsers).
However, in current version of the library:
- row's height indeed calculated as 60
- but item is placed above the row, at position [0,15]
From my understanding, the culprit is the lay_arrange_overlay_squeezed_range
function, specifically line 1104:
// in LAY_HCENTER case
rect[dim] += (space - rect[2 + dim]) / 2 - margins[wdim];
The following change seems to be fixing the problem, and doesn't break any of the tests
--- a/layout.h
+++ b/layout.h
@@ -1101,7 +1101,7 @@ void lay_arrange_overlay_squeezed_range(
switch (b_flags & LAY_HFILL) {
case LAY_HCENTER:
rect[2 + dim] = lay_scalar_min(rect[2 + dim], min_size);
- rect[dim] += (space - rect[2 + dim]) / 2 - margins[wdim];
+ rect[dim] += (space - rect[2 + dim] - margins[wdim]) / 2;
break;
case LAY_RIGHT:
rect[2 + dim] = lay_scalar_min(rect[2 + dim], min_size);
Before submitting an actual pull request I would like to ask:
- Whether or not there is any actual reason this function implemented the way it is, or nobody just ever tried such use case
- If you can spot any other side effects of the suggested chang which are not covered by tests, but may turn out to be a breaking change
Metadata
Metadata
Assignees
Labels
No labels