Files
eepp/docs/articles/ui_layout_reference.md
T
Martín Lucas Golini ccb03a3b8e Add inherited RTL direction and logical UI layout support
- Cache effective direction and skip unchanged subtree propagation.
- Add logical alignment, box edges, and relative positioning.
- Mirror layouts and controls while preserving logical node order.
- Apply inherited base direction to UI text and editing.
- Keep logical-edge storage lazy and compact.
- Add regression tests, an isolated WebView demo, and RTL documentation.
- Document RichText bidi limitations and plan paragraph-level support.
2026-10-11 12:29:16 -03:00

1629 lines
31 KiB
Markdown

# Native UI Layout Reference
This document is the authoritative reference for eepp's **native application UI layout system**.
It describes the behavior of the layout primitives used by normal eepp applications such as ecode,
eterm, eproc, dialogs, settings panels, forms, workspaces, toolbars, and application-specific tools.
For the recommended high-level authoring model and conventions, read
[`ui_authoring.md`](ui_authoring.md) first.
This document intentionally describes **current eepp behavior**, not Android, browser, Qt, or other
framework behavior that may look similar.
HTML formatting contexts such as block, inline, Flexbox, CSS Grid, table layout, floats, and
positioned HTML are a separate system primarily used by `UIWebView`, `UIMarkdownView`, and the HTML
compatibility layer. They are not covered here except where a distinction is important.
---
## 1. Native layout model
The normal eepp layout model consists of:
```text
UIWidget
size policy
margins
padding
layout gravity
min/max constraints
optional layout weight
optional relative-position relationship
UILayout
owns or participates in positioning/sizing children
specific layouts
UILinearLayout
UIRelativeLayout
UIGridLayout
UIFlowLayout
UISplitter
```
The most important idea is:
> **The parent layout controls the final allocation and position of its children.**
A child supplies a sizing/placement contract through properties such as:
```text
layout_width
layout_height
layout_weight
layout_gravity
margin
min-width
max-width
min-height
max-height
```
The exact meaning of those properties depends on the parent layout.
---
## 2. XML and CSS spelling
eepp accepts aliases, but normal project style distinguishes XML attributes from CSS properties.
Preferred XML spelling:
```xml
<TextInput
layout_width="0dp"
layout_height="wrap_content"
layout_weight="1"
layout_gravity="center_vertical" />
```
Preferred CSS spelling:
```css
.form-input {
layout-width: 0dp;
layout-height: wrap_content;
layout-weight: 1;
layout-gravity: center_vertical;
}
```
Common compact aliases:
```text
layout_width -> lw
layout_height -> lh
layout_weight -> lw8
layout_gravity -> lg
match_parent -> mp
wrap_content -> wc
```
Both full and compact forms are common in production eepp code.
---
## 3. Default widget layout state
A newly constructed `UIWidget` starts with:
```text
layout weight = 0
layout gravity = start|top (horizontal start resolves to left in LTR, right in RTL)
width policy = WrapContent
height policy = WrapContent
position policy = None
```
Specific widgets may override their own defaults. Horizontal alignment and layout gravity accept
logical `start`/`end` in addition to physical `left`/`right`; see
[UI direction and RTL](ui_rtl.md).
Do not assume every widget behaves identically under `wrap_content`; intrinsic sizing is
widget-specific.
---
## 4. Size policies
The native size-policy enum is:
```cpp
enum class SizePolicy {
Fixed,
MatchParent,
WrapContent
};
```
These policies are applied independently to width and height.
### 4.1 `wrap_content`
XML:
```xml
layout_width="wrap_content"
layout_height="wrap_content"
```
Compact:
```xml
lw="wc"
lh="wc"
```
A `WrapContent` axis asks the widget to derive its size from its intrinsic/content size.
The exact intrinsic size is widget-specific.
Examples:
- text widgets derive size from their text and font metrics;
- image widgets derive size from the drawable;
- buttons derive size from their internal content/theme;
- native layouts may derive their wrapped axis from their visible children.
Padding contributes to normal content sizing where the widget implementation defines it.
`wrap_content` is the default native size policy for a plain `UIWidget`.
### 4.2 `match_parent`
XML:
```xml
layout_width="match_parent"
layout_height="match_parent"
```
Compact:
```xml
lw="mp"
lh="mp"
```
`MatchParent` requests the available parent content size on that axis.
The generic match-parent calculation is:
```text
parent size
- parent content offsets
- non-auto child margins
```
Parent content offsets include padding and, where applicable, borders.
`max-width` / `max-height` can cap the resulting match-parent size.
Conceptually:
```text
child match-parent width =
parent width
- parent left/right content offsets
- child left/right margins
```
The exact layout can perform additional sizing rules around this value.
Do not treat `match_parent` as a synonym for CSS `width: 100%`. They may often produce similar
geometry, but they belong to different layout systems.
### 4.3 Fixed size
Any explicit dimension normally selects `Fixed` sizing on that axis:
```xml
layout_width="240dp"
layout_height="32dp"
```
The value is resolved and stored as the widget size.
The literal value:
```text
fixed
```
can also select the fixed policy without supplying a new dimension.
Use explicit sizes where the dimension itself is meaningful. Do not use arbitrary fixed dimensions
to compensate for a parent-layout mistake.
### 4.4 Zero size and weighted LinearLayout children
There is one important special case.
Inside a `UILinearLayout`, the canonical weighted-child pattern intentionally uses zero on the
weighted axis:
Horizontal parent:
```xml
<TextInput
layout_width="0dp"
layout_weight="1" />
```
Vertical parent:
```xml
<ListView
layout_height="0dp"
layout_weight="1" />
```
When eepp parses a zero layout dimension for a weighted child whose parent is a `UILinearLayout`, it
does not immediately force the stored size in the normal fixed-size path. The linear layout assigns
the weighted size during packing.
---
## 5. Minimum and maximum constraints
Widgets support:
```text
min-width
max-width
min-height
max-height
```
These can constrain native layout results.
For example, generic `match_parent` width calculation applies a `max-width` cap when one exists.
Some native layout algorithms also explicitly fit wrapped container sizes against min/max
constraints.
Do not assume min/max handling is identical to browser intrinsic-sizing rules. This document
describes the native layout system; HTML layout has additional rules.
---
## 6. Margin and padding
### Margin
Margins belong to the child and participate in parent layout allocation/positioning.
Example:
```xml
<PushButton margin-left="8dp" />
```
Margins affect:
- linear packing;
- match-parent available size;
- relative positioning;
- flow wrapping;
- grid placement;
- splitter/container alignment where relevant.
### Padding
Padding belongs to the container/widget.
Example:
```xml
<vbox padding="12dp">
...
</vbox>
```
Native layouts generally place children inside the padded content area.
Conceptually:
```text
container border box
padding
child layout area
```
---
## 7. `gravity` and `layout_gravity`
These are different properties.
### `gravity`
`gravity` controls the widget's own content or, for layouts that explicitly use it, the layout's
internal arrangement.
Examples include:
```text
left
right
center_horizontal
top
bottom
center_vertical
center
```
Widget behavior varies because different widget types own different content.
### `layout_gravity`
`layout_gravity` describes how the widget should be placed by its parent layout when that layout
supports gravity.
XML:
```xml
layout_gravity="right|center_vertical"
```
CSS:
```css
layout-gravity: right|center_vertical;
```
The distinction is:
```text
gravity
content/layout behavior inside this widget
layout_gravity
placement of this widget by its parent
```
This distinction is especially important in `UILinearLayout`.
---
## 8. `gravity-owner`
Layouts normally respect the positioning policy of their parent.
Some parent widgets advertise that they own child positioning with `UI_OWNS_CHILDREN_POSITION`.
A layout can set:
```text
gravity-owner: true
```
to force its own `layout_gravity` alignment against the parent even when the parent normally owns
child positions.
This is an advanced escape hatch and should not be a default solution to layout problems.
---
## 9. Layout invalidation and update behavior
Native layouts are invalidated when relevant state changes, including:
- child count changes;
- layout-affecting child attributes;
- layout size changes;
- padding changes;
- parent-size changes.
A dirty layout is normally scheduled through the owning `UISceneNode`.
During an active layout pass, some updates can occur synchronously to avoid waiting for another
frame.
Calling `UILayout::getSize()` on a dirty layout forces that layout to update before returning its
size.
Nested layouts are tracked by their parent `UILayout` and participate in layout-tree updates.
This matters mainly when implementing custom layout widgets. Ordinary application code should set
properties and allow the scene to perform layout.
---
## 10. Visibility and native layouts
Native layouts generally operate on **visible widget children**.
Examples:
- `UILinearLayout` ignores invisible children while packing;
- `UIFlowLayout` ignores invisible children while creating rows;
- `UIGridLayout` ignores invisible children;
- invisible native layouts may collapse their own layout size to zero during their update path.
Do not use invisible children as spacers.
---
## 11. `UILinearLayout`
`UILinearLayout` is the primary sequential application layout.
XML aliases:
```xml
<vbox>
<hbox>
```
C++:
```cpp
UILinearLayout::NewVertical();
UILinearLayout::NewHorizontal();
```
Default orientation:
```text
vertical
```
### 11.1 Vertical linear layout
A vertical layout packs visible children from top to bottom.
Each child's vertical margins contribute to the consumed main-axis space.
The child's `layout_gravity` controls **horizontal** placement inside the layout:
```text
left
center_horizontal
right
```
Example:
```xml
<vbox
layout_width="match_parent"
layout_height="match_parent"
padding="12dp">
<TextView
text="Left"
layout_gravity="left" />
<PushButton
text="Centered"
layout_gravity="center_horizontal" />
<PushButton
text="Right"
layout_gravity="right" />
</vbox>
```
### 11.2 Horizontal linear layout
A horizontal layout packs visible children from left to right.
Each child's horizontal margins contribute to consumed main-axis space.
The child's `layout_gravity` controls **vertical** placement:
```text
top
center_vertical
bottom
```
Example:
```xml
<hbox
layout_width="match_parent"
layout_height="40dp">
<TextView
text="Name"
layout_gravity="center_vertical" />
<TextInput
layout_width="0dp"
layout_weight="1"
layout_gravity="center_vertical" />
</hbox>
```
---
## 12. LinearLayout size-policy behavior
Before packing, the layout applies child policies on the cross axis.
### Vertical layout
For child width:
- `WrapContent`: child auto-sizing is enabled;
- `MatchParent`: width becomes the layout's content width minus child horizontal margins;
- `Fixed`: existing width remains.
A child with `layout_height="match_parent"` and zero weight can also be resized to the parent's
available height.
### Horizontal layout
For child height:
- `WrapContent`: child auto-sizing is enabled;
- `MatchParent`: height becomes the layout's content height minus child vertical margins;
- `Fixed`: existing height remains.
A child with `layout_width="match_parent"` and zero weight can also be resized to the parent's
available width.
---
## 13. LinearLayout weights
`layout_weight` distributes remaining space along the layout orientation.
Canonical horizontal use:
```xml
<hbox lw="mp" lh="wc">
<TextView text="Project" min-width="90dp" lg="center_vertical" />
<TextInput lw="0dp" lw8="1" />
</hbox>
```
Canonical vertical use:
```xml
<vbox lw="mp" lh="mp">
<TextView text="Header" />
<ListView lw="mp" lh="0dp" lw8="1" />
<hbox lw="mp" lh="wc">
<!-- footer -->
</hbox>
</vbox>
```
### 13.1 Weight calculation
The implementation treats positive weights as **relative weights**.
For all visible children:
```text
totalWeight = sum(max(childWeight, 0))
```
The layout first calculates the main-axis space already consumed by:
- visible non-weighted fixed/wrapped children;
- visible child margins.
Then each positively weighted child gets:
```text
remainingSpace * childWeight / totalWeight
```
Therefore these are equivalent ratios:
```text
1, 1
0.5, 0.5
50, 50
```
and:
```text
1, 3
25, 75
```
produce equivalent proportions.
> Current implementation does **not** require weights to be normalized to `0..1` or sum to `1`.
Older documentation that describes weights as normalized should be considered overly restrictive.
### 13.2 Example calculation
Container:
```text
horizontal content width = 600dp
```
Children:
```text
A = fixed 100dp
B = weight 1
C = weight 3
```
Ignoring margins:
```text
remaining = 600 - 100 = 500
totalWeight = 4
B = 125
C = 375
```
---
## 14. LinearLayout wrap-content behavior
A vertical `UILinearLayout` with `layout_height="wrap_content"` grows to the visible child heights,
vertical margins, and padding.
A horizontal `UILinearLayout` with `layout_width="wrap_content"` similarly grows from visible child
widths, margins, and padding.
The cross-axis wrapped size is based on the maximum visible non-match-parent child extent plus
container padding, with min/max constraints considered.
A wrapped linear layout can repack after its cross-axis size changes because that size may affect
child alignment or nested layout.
---
## 15. LinearLayout properties
Layout-specific:
```text
orientation
gravity-owner
```
`orientation` values:
```text
vertical
horizontal
```
Default:
```text
vertical
```
Child properties commonly used with a linear layout:
```text
layout_width
layout_height
layout_weight
layout_gravity
margin
min-width
max-width
min-height
max-height
```
---
## 16. `UIRelativeLayout`
`UIRelativeLayout` is a native layout for:
- alignment against the parent;
- positioning one child relative to a sibling.
It owns child positioning.
Use it when sibling relationships are more natural than a nested `vbox`/`hbox` hierarchy.
Do not choose it merely because it permits more arbitrary positioning.
---
## 17. RelativeLayout child sizing
For each widget child:
Width:
```text
WrapContent -> enable auto-sizing
MatchParent -> layout width - child horizontal margins - layout horizontal padding
Fixed -> keep existing width
```
Height:
```text
WrapContent -> enable auto-sizing
MatchParent -> layout height - child vertical margins - layout vertical padding
Fixed -> keep existing height
```
---
## 18. RelativeLayout parent alignment
When a child has no sibling-relative position policy, `layout_gravity` positions it against the
`UIRelativeLayout`.
Horizontal:
```text
left
center_horizontal
right
```
Vertical:
```text
top
center_vertical
bottom
```
Example:
```xml
<RelativeLayout
layout_width="match_parent"
layout_height="match_parent"
padding="8dp">
<PushButton
text="Bottom right"
layout_gravity="right|bottom" />
</RelativeLayout>
```
---
## 19. RelativeLayout sibling relationships
Supported relationships are:
```text
layout_to_left_of
layout_to_right_of
layout_to_top_of
layout_to_bottom_of
```
The value is the target sibling ID.
Example:
```xml
<RelativeLayout
layout_width="match_parent"
layout_height="match_parent">
<Widget
id="sidebar"
layout_width="220dp"
layout_height="match_parent" />
<Widget
id="content"
layout_width="match_parent"
layout_height="match_parent"
layout_to_right_of="sidebar" />
</RelativeLayout>
```
The relationship is resolved by finding the referenced node and storing the target widget.
It is used only when target and positioned widget share the same parent.
Only one stored `PositionPolicy` is active at a time.
This is not a general constraint solver.
---
## 20. RelativeLayout wrap-content caveat
`UIRelativeLayout::updateLayout()` applies its own size policy and lays out children, but it does
**not** compute a new bounding rectangle from all positioned children.
For application containers, prefer a defined or `match_parent` size when using `UIRelativeLayout`.
Do not assume `wrap_content` behaves like a general constraint-layout "measure descendants and fit"
pass.
---
## 21. `UIGridLayout`
`UIGridLayout` is eepp's **native repeated-cell grid**.
It is not CSS Grid.
Use it for normal application UI when children should occupy repeated cells with a common row/column
size policy.
Do not infer CSS track sizing behavior from this class.
---
## 22. GridLayout sizing model
Grid cells use one column mode and one row mode.
```text
column-mode:
size
weight
row-mode:
size
weight
```
Defaults:
```text
column-mode = weight
row-mode = weight
column-weight = 0.25
row-weight = 0.25
column-width = 0
row-height = 0
column-margin = 0
row-margin = 0
```
When `column-mode=size`, cell width is `column-width`.
When `column-mode=weight`, cell width is approximately:
```text
available grid width * column-weight
```
When `row-mode=size`, cell height is `row-height`.
When `row-mode=weight`, cell height is approximately:
```text
available grid height * row-weight
```
---
## 23. GridLayout placement
Visible widget children are processed sequentially.
For each child:
1. determine target cell size;
2. set child size policy to `Fixed, Fixed`;
3. resize child to target size;
4. place child at current grid position;
5. advance by cell width plus column margin;
6. wrap to the next row when the next cell no longer fits.
This is a repeated-cell wrapping grid, not a named-track CSS grid.
---
## 24. GridLayout child weight override
`UIGridLayout` has a special behavior:
If a child has non-zero `layout_weight`, that child's target **width** becomes:
```text
child layout weight
* grid content width
```
This is not `UILinearLayout`'s remaining-space distribution algorithm.
Do not assume `layout_weight` means the same algorithm in every layout type.
For straightforward grids, prefer the layout-level row/column sizing properties unless this
per-child width override is intentionally needed.
---
## 25. GridLayout alignment
The grid's own horizontal `gravity` affects row placement:
```text
left
center
right
```
This is container `gravity`, not child `layout_gravity`.
---
## 26. GridLayout wrap-content behavior
With:
```text
layout_height="wrap_content"
```
the layout derives its height from generated rows plus vertical padding.
A match-parent grid width/height is resolved from the parent before cell placement.
Children are converted to fixed cell sizes during grid layout.
---
## 27. GridLayout properties
```text
column-mode
column-weight
column-width
column-margin
row-mode
row-weight
row-height
row-margin
```
Container `gravity` also affects horizontal grid alignment.
---
## 28. `UIFlowLayout`
`UIFlowLayout` is eepp's native horizontal wrapping flow layout.
Conceptually:
```text
A B C D
E F G
H I
```
Children are consumed in order from left to right.
When the next visible child no longer fits the current row, a new row is created.
---
## 29. FlowLayout width behavior
A notable design choice:
When the flow layout itself uses:
```text
layout_width="wrap_content"
```
it initially uses the available match-parent width as its wrapping width.
After layout, if all visible children effectively fit on one row and use less than the available
width, the layout can shrink its wrapped width to the used width.
So `wrap_content` for `UIFlowLayout` is not simply "sum all child widths without a constraint."
Available parent width participates in wrapping first.
---
## 30. FlowLayout row creation
For each visible child:
1. apply the child's size policy;
2. test whether the child would exceed the current row;
3. if necessary, create a new row;
4. place the child;
5. include child margins in row consumption;
6. track the row's maximum height.
The implementation can also create a new row after placement when the resulting cursor exceeds the
layout width.
---
## 31. FlowLayout child size policies
Before rows are built:
```text
WrapContent width/height
enable child auto-sizing
MatchParent width
available match-parent width
MatchParent height
available match-parent height
Fixed
retain explicit size
```
After row heights are known, a child with:
```text
layout_height="match_parent"
```
is resized to that row's maximum height.
---
## 32. FlowLayout alignment
The flow layout's own `gravity` controls row-group placement.
Horizontal gravity:
```text
left
center
right
```
controls each row's horizontal displacement.
Vertical gravity:
```text
top
center_vertical
bottom
```
can shift the complete row group inside a container taller than the total flow content.
Within each row, `row-valign` controls child vertical alignment.
---
## 33. `row-valign`
Values:
```text
top
center
bottom
```
Default:
```text
bottom
```
Meaning:
```text
top
child aligns near row top, respecting top margin
center
child is centered in row maximum height
bottom
child aligns near row bottom, respecting bottom margin
```
This is separate from the container's vertical `gravity`.
---
## 34. FlowLayout wrap-content height
With:
```text
layout_height="wrap_content"
```
height becomes:
```text
top padding
+ sum(row maximum heights)
+ bottom padding
```
with child vertical margins contributing to row heights.
---
## 35. FlowLayout properties
Layout-specific:
```text
row-valign
gravity-owner
```
Important general properties:
```text
gravity
layout_width
layout_height
padding
margin
```
`UIFlowLayout` does not use child `layout_weight` as a remaining-space distribution mechanism.
---
## 36. `UISplitter`
`UISplitter` is a two-pane resizable layout.
Default orientation:
```text
horizontal
```
Horizontal:
```text
[first pane] | [second pane]
```
Vertical:
```text
[first pane]
-------------
[second pane]
```
The separator is an internal draggable widget.
---
## 37. Splitter child model
`UISplitter` supports at most two external widget children.
Internally it also owns its separator widget.
The first external child becomes the first pane; the second becomes the last pane.
Additional external children are rejected/closed.
Children placed into the splitter are forced to:
```text
Fixed, Fixed
```
because the splitter owns their exact geometry.
---
## 38. Splitter with one child
If only one pane exists:
- the separator is hidden and disabled;
- the first child fills the splitter's padded content area.
---
## 39. Split partition
Property:
```text
splitter-partition
```
Default:
```text
50%
```
Meaning:
> Desired space occupied by the first pane along the splitter axis.
The separator's own size is removed from available split space when visible.
Conceptually:
```text
totalSpace =
splitter content axis size
- visible separator size
first = resolve(splitter-partition, totalSpace)
second = totalSpace - first
```
---
## 40. Splitter minimum sizes
The first pane's minimum size constrains the initial partition.
During dragging, both pane minimum sizes constrain separator movement.
A requested partition may therefore not be achievable when it violates minimum sizes.
Do not assume `0%` always produces a physically zero-sized first pane if its minimum size is non-zero.
---
## 41. Splitter visibility properties
```text
splitter-always-show
```
Default:
```text
true
```
When true, the divider remains visible whenever two panes exist.
```text
splitter-hide-on-edge
```
Default:
```text
false
```
When enabled and `splitter-always-show` is false, percentage partitions exactly at `0%` or `100%`
can hide the divider so one pane consumes the full splitter.
---
## 42. Splitter dragging
Horizontal orientation:
```text
separator drags along x
cursor = horizontal resize
```
Vertical orientation:
```text
separator drags along y
cursor = vertical resize
```
Dragging immediately resizes both children.
After a drag, the stored split partition is recalculated as a percentage of available split space.
---
## 43. Splitter properties
```text
orientation
splitter-partition
splitter-always-show
splitter-hide-on-edge
```
Orientation values:
```text
horizontal
vertical
```
---
## 44. Choosing the correct native layout
| Need | Native layout |
| --- | --- |
| Vertical sequence | `UILinearLayout` / `<vbox>` |
| Horizontal sequence | `UILinearLayout` / `<hbox>` |
| Flexible remaining space in a row/column | `UILinearLayout` + `layout_weight` |
| Child positioned relative to a sibling | `UIRelativeLayout` |
| Repeated equal/weighted cells | `UIGridLayout` |
| Horizontal items that wrap into rows | `UIFlowLayout` |
| Two user-resizable panes | `UISplitter` |
| Tabs | `UITabWidget` |
| Split/tab editor workspace | `UITabWidgetSplitter` |
| Web/document formatting | HTML compatibility layout |
`UITabWidget` and `UITabWidgetSplitter` are higher-level containers rather than low-level generic
layout algorithms and belong in the widget/application references.
---
## 45. Production patterns
### Flexible form row
```xml
<hbox
layout_width="match_parent"
layout_height="wrap_content"
margin-bottom="8dp">
<TextView
text="Project"
min-width="90dp"
layout_gravity="center_vertical" />
<TextInput
id="project"
layout_width="0dp"
layout_weight="1" />
</hbox>
```
### Header + flexible content + footer
```xml
<vbox
layout_width="match_parent"
layout_height="match_parent">
<hbox
layout_width="match_parent"
layout_height="wrap_content">
<!-- toolbar -->
</hbox>
<SomeContent
layout_width="match_parent"
layout_height="0dp"
layout_weight="1" />
<hbox
layout_width="match_parent"
layout_height="wrap_content">
<!-- footer -->
</hbox>
</vbox>
```
### Wrapping option group
```xml
<FlowLayout
layout_width="match_parent"
layout_height="wrap_content"
row-valign="center">
<CheckBox text="Linux" margin-right="8dp" />
<CheckBox text="macOS" margin-right="8dp" />
<CheckBox text="Windows" margin-right="8dp" />
<CheckBox text="FreeBSD" margin-right="8dp" />
</FlowLayout>
```
### Two-pane workspace
```xml
<Splitter
layout_width="match_parent"
layout_height="match_parent"
orientation="horizontal"
splitter-partition="30%">
<TreeView />
<CodeEditor />
</Splitter>
```
---
## 46. Important differences from browser layout
Do not import these as semantic equivalences:
```text
match_parent == width:100%
layout_weight == flex-grow
UIGridLayout == CSS Grid
UIFlowLayout == display:flex + flex-wrap
layout_gravity == justify-content / align-items
```
They can be useful analogies, but native eepp layouts are separate algorithms.
---
## 47. Important differences from Android intuition
eepp deliberately borrows several Android-style concepts, especially:
```text
LinearLayout
layout_width
layout_height
match_parent
wrap_content
layout_weight
layout_gravity
RelativeLayout-style sibling relations
dp
```
Android documentation is not authoritative for eepp.
Notable example:
> Current eepp `UILinearLayout` weights are arbitrary relative positive values; they do not need to
> be normalized or sum to `1`.
Always prefer eepp behavior over external analogy.
---
## 48. Inspecting native layout at runtime
Use the **Runtime UI Inspector & Automation Protocol** rather than guessing geometry.
Typical process:
```text
ui.contexts
↓
ui.query target
↓
ui.inspect target geometry/layout properties
↓
inspect parent
↓
inspect relevant siblings
↓
screenshot if useful
```
Stable debugging questions:
```text
What parent layout owns this child?
What are its width/height policies?
What are its actual bounds?
Does it have weight?
What are its margins?
What is the parent's padding?
What gravity is active?
What min/max constraints exist?
```
For weighted linear layouts, inspect all siblings participating in the same axis.
---
## 49. Layout debugging checklist
When size is wrong:
```text
1. identify parent layout type
2. inspect layout_width / layout_height
3. determine Fixed / MatchParent / WrapContent
4. check layout_weight
5. check margins
6. check parent padding/content offsets
7. check min/max constraints
8. check sibling sizes/weights
9. check visibility
10. only then consider an explicit fixed size
```
When position is wrong:
```text
1. identify parent layout
2. check layout_gravity
3. distinguish layout_gravity from gravity
4. check margins
5. check RelativeLayout position relationship
6. check parent gravity where Grid/Flow uses it
7. check gravity-owner only if parent positioning ownership matters
```
---
## 50. Implementation-oriented notes
These details matter mainly when implementing custom layouts.
### Layout dirtiness
`UILayout` maintains dirty state and participates in the scene's layout invalidation queue.
### Reentrancy guard
Layouts use `mPacking` to prevent recursive packing.
### Nested layouts
A `UILayout` tracks direct child layouts and updates the layout tree recursively.
### Auto-size children
A layout can request `onAutoSize()` for ordinary children or temporarily update a child layout as
wrapping content.
### Parent notifications
When a layout's wrapped size changes, implementations notify the parent so enclosing layouts can
repack.
Custom layout implementations should preserve these lifecycle expectations.
---
## 51. Scope boundaries
This document intentionally does not specify:
- HTML Flexbox;
- HTML CSS Grid;
- block/inline formatting;
- HTML table layout;
- floats;
- sticky/fixed/absolute HTML positioning;
- HTML intrinsic min-content/max-content behavior.
See [`ui_html_compatibility.md`](ui_html_compatibility.md) for HTML/web layout semantics.
For related topics:
- [`ui_introduction.md`](ui_introduction.md) — introduction to eepp's UI system.
- [`ui_authoring.md`](ui_authoring.md) — recommended application UI mental model and authoring conventions.
- [`ui_css_for_applications.md`](ui_css_for_applications.md) — CSS behavior and conventions for normal application widgets.
- [`ui_inspector.md`](ui_inspector.md) — runtime UI inspection and automation protocol.
- [`ui_databinding.md`](ui_databinding.md) — UI data binding.
- [`ui_charts.md`](ui_charts.md) — charting widgets and chart-specific behavior.
---
## 52. Source of truth
When uncertain about native layout behavior, use this order:
1. current eepp implementation
2. current eepp unit/integration tests
3. production eepp/ecode/eterm/eproc usage
4. this reference
5. [`css_specification.md`](css_specification.md) and other general docs
6. Android/browser/other-framework analogy
If a documented rule and the current implementation disagree, treat the implementation as
authoritative and update the documentation.