Update region-node handoff
This commit is contained in:
1 parent
7b8b43a7d2
commit
8db0969d9d
1 file changed
+52
-25
+52
-25
@@ -8,7 +8,7 @@ log.
|
|||||||
|
|
||||||
Canonical Iris `main` is **`ca2b4b2`** (#17, the headless rig). **#18
|
Canonical Iris `main` is **`ca2b4b2`** (#17, the headless rig). **#18
|
||||||
`split/18-position-chain`** is open in `/home/bob/repos/iris-pr18`; its local
|
`split/18-position-chain`** is open in `/home/bob/repos/iris-pr18`; its local
|
||||||
head is **`f437495`**, forty-six commits, pushed to the fork. No PR reviews
|
head is **`71c9c39`**, forty-seven commits, pushed to the fork. No PR reviews
|
||||||
were present when checked on 2026-09-15; the verification summary is posted on
|
were present when checked on 2026-09-15; the verification summary is posted on
|
||||||
the PR.
|
the PR.
|
||||||
|
|
||||||
@@ -30,8 +30,18 @@ add defensive work to recover optimizations from a false declaration.
|
|||||||
the largest fixed orthogonal length is reported, while any relative or
|
the largest fixed orthogonal length is reported, while any relative or
|
||||||
`leftover` child makes the span report `leftover`. `Full` reports exactly
|
`leftover` child makes the span report `leftover`. `Full` reports exactly
|
||||||
`Len::rel(1.0)`. It does not read the children's orthogonal sizes, but their
|
`Len::rel(1.0)`. It does not read the children's orthogonal sizes, but their
|
||||||
`Holds` ranges still propagate through placement, so a resize repositions them
|
`Holds` ranges still propagate through final-box drawing, so a resize
|
||||||
without redrawing when their own contracts permit it.
|
repositions them without redrawing when their own contracts permit it.
|
||||||
|
|
||||||
|
`71c9c39` replaces the public `Painter::place` distinction with an opt-in
|
||||||
|
widget property. `.region_node()` gives a widget one independently movable
|
||||||
|
retained region; `Widgets::set_region_node` can change that choice at runtime
|
||||||
|
and causes one structural redraw. Widgets without the property remain at the
|
||||||
|
default shallow chain depth: Iris recursively remaps their retained primitive
|
||||||
|
and mask regions when they move. `.scrollable()` enables a region node on its
|
||||||
|
content once as its convenient default; raw `Scroll::new` respects the
|
||||||
|
caller's choice, and the property can be disabled later without breaking
|
||||||
|
scrolling. `Span` and `Align` do not add nodes to their children.
|
||||||
|
|
||||||
Do not change `Children` to select the pixel-longest arbitrary `Len` at the
|
Do not change `Children` to select the pixel-longest arbitrary `Len` at the
|
||||||
span's current width. A fixed child and a relative child can create multiple
|
span's current width. A fixed child and a relative child can create multiple
|
||||||
@@ -52,19 +62,23 @@ rewrite:
|
|||||||
- A widget retains the layer it was entered on, not the last child layer its
|
- A widget retains the layer it was entered on, not the last child layer its
|
||||||
painter visited. The old value drifted on local redraw and put a redrawn tab
|
painter visited. The old value drifted on local redraw and put a redrawn tab
|
||||||
background above its retained text.
|
background above its retained text.
|
||||||
|
- `Span`'s leftover/no-leftover split is a strict layout decision, not a
|
||||||
|
rounding tolerance. Its `Holds` range must use the same exact divided
|
||||||
|
boundary as drawing; a tolerant endpoint retained zero-height children at
|
||||||
|
the boundary in generated seed 16.
|
||||||
|
|
||||||
`core/src/ui/holds.rs`, the retained tests, and the generated cold-layout oracle
|
`core/src/ui/holds.rs`, the retained tests, and the generated cold-layout oracle
|
||||||
pin those rules. Seeds 10 and 86 are now in the ordinary generated set.
|
pin those rules. Seeds 10 and 86 are now in the ordinary generated set.
|
||||||
|
|
||||||
## Verification at `f437495`
|
## Verification at `71c9c39`
|
||||||
|
|
||||||
- `cargo fmt --all --check`
|
- `cargo fmt --all --check`
|
||||||
- `cargo clippy --workspace --all-targets --all-features -- -D warnings`
|
- `cargo clippy --workspace --all-targets --all-features -- -D warnings`
|
||||||
- `cargo test --workspace`: 77 passed, 8 ignored
|
- `cargo test --workspace --all-features`: 84 passed, 10 ignored
|
||||||
- `cargo test --release --test generated -- --ignored
|
- `cargo test --release --test generated -- --ignored
|
||||||
a_long_run_of_seeds_agrees`: 100 seeds passed in 66.81 s
|
a_long_run_of_seeds_agrees --exact`: 100 seeds passed in 64.77 s
|
||||||
- The `tabs` reference at 900x1200 remained byte-identical to `ca2b4b2` after
|
- The `tabs` reference at 900x1200 remained byte-identical to `f437495`: zero
|
||||||
retaining `Children` as the default.
|
differing pixels out of 1,080,000 after the region-node rewrite.
|
||||||
- At preceding head `29c7881`, reference renders against
|
- At preceding head `29c7881`, reference renders against
|
||||||
`/home/bob/repos/iris-main-cmp` at `ca2b4b2` covered:
|
`/home/bob/repos/iris-main-cmp` at `ca2b4b2` covered:
|
||||||
`tabs`, `view`, `minimal`, and `text` at 1920x1200; `tabs` cold at
|
`tabs`, `view`, `minimal`, and `text` at 1920x1200; `tabs` cold at
|
||||||
@@ -72,7 +86,10 @@ pin those rules. Seeds 10 and 86 are now in the ordinary generated set.
|
|||||||
before and after replay. Every comparison had zero differing pixels. The
|
before and after replay. Every comparison had zero differing pixels. The
|
||||||
live-resize image is also byte-identical to the cold 900x1200 image.
|
live-resize image is also byte-identical to the cold 900x1200 image.
|
||||||
|
|
||||||
The final pre-submit review was run in four passes. The earlier retained-layout
|
The final pre-submit review was run in four passes. The region-node review
|
||||||
|
caught an index-reuse hazard when removing a node; its move entry now remains
|
||||||
|
alive until every descendant has migrated. The generated oracle then exposed
|
||||||
|
the exact `Span` threshold described above. The earlier retained-layout
|
||||||
review caught the layer defect above, corrected validity-range inversion for
|
review caught the layer defect above, corrected validity-range inversion for
|
||||||
negative relative extents, and removed an impossible-state `unwrap` from
|
negative relative extents, and removed an impossible-state `unwrap` from
|
||||||
`Scroll`. The orthogonal-sizing review caught both the circular longest-child
|
`Scroll`. The orthogonal-sizing review caught both the circular longest-child
|
||||||
@@ -98,19 +115,27 @@ tighter figures.
|
|||||||
|
|
||||||
## Retained-layout invariants
|
## Retained-layout invariants
|
||||||
|
|
||||||
- A slot holds a whole `UiRegion` in the coordinates of the slot it names.
|
- A region node holds a whole `UiRegion` in its parent node's coordinates.
|
||||||
`UiRegion::FULL` is the identity. Slots are opt-in: `Painter::place` gives a
|
`UiRegion::FULL` is the identity. Widgets opt in with `.region_node()` or
|
||||||
child a slot; `widget` and `widget_within` share the nearest ancestor's.
|
`Widgets::set_region_node`; ordinary widgets share the nearest ancestor
|
||||||
- A widget's `ActiveData::region` is where it was placed in its parent's slot.
|
node. Region nodes therefore add chain depth only where moving a whole
|
||||||
A placed widget draws in `FULL`; its box lives in its slot. This keeps chains
|
subtree through one entry is useful.
|
||||||
at positioning-container depth rather than full widget-tree depth.
|
- A widget's `ActiveData::region` is its box in its parent node. A region-node
|
||||||
|
widget draws in `FULL`; its box lives in its node. Moving an ordinary
|
||||||
|
retained subtree instead remaps its primitive, mask, and active regions.
|
||||||
|
Remapping stops at a descendant region node after rewriting that one entry.
|
||||||
|
- Changing `region_node` redraws the subtree once to rebuild the coordinate
|
||||||
|
boundary. The property belongs to widget identity, which is safe because a
|
||||||
|
widget has one parent. `.scrollable()` sets it once; raw `Scroll::new` does
|
||||||
|
not, and `Scroll` never reasserts it while drawing.
|
||||||
- The first box a parent asks about is the offer. A later box chosen from the
|
- The first box a parent asks about is the offer. A later box chosen from the
|
||||||
child's answer is a placement, not another independent answer. Dirty widgets
|
child's answer is the final box, not another independent answer. Dirty
|
||||||
are re-asked at the offer and only then placed again.
|
widgets are re-asked at the offer and only then drawn in the final box.
|
||||||
- A retained drawing can be reused only when its `Holds` interval contains the
|
- A retained drawing can be reused only when its `Holds` interval contains the
|
||||||
new pixel box on both axes, its parent slot is unchanged, and the widget is
|
new pixel box on both axes, its parent node is unchanged, its region-node
|
||||||
clean. A moved unslotted widget must draw again because it has no slot to
|
choice matches the retained structure, and the widget is clean. A valid
|
||||||
rewrite.
|
ordinary subtree may move without redrawing because its regions are
|
||||||
|
recursively remapped.
|
||||||
- `Painter` records size-dependency edges only when a parent reads a child's
|
- `Painter` records size-dependency edges only when a parent reads a child's
|
||||||
size or hint. An undrawn measured child remains recorded so a later change
|
size or hint. An undrawn measured child remains recorded so a later change
|
||||||
reaches the parent that decided whether to draw it.
|
reaches the parent that decided whether to draw it.
|
||||||
@@ -126,8 +151,10 @@ tighter figures.
|
|||||||
remains valid from its longest produced line through the width at which it
|
remains valid from its longest produced line through the width at which it
|
||||||
was made, and `TextView` reports that interval through `Painter::holds`.
|
was made, and `TextView` reports that interval through `Painter::holds`.
|
||||||
- `Span`'s decision to distribute `leftover` is a pixel question. Its validity
|
- `Span`'s decision to distribute `leftover` is a pixel question. Its validity
|
||||||
interval is split at the length where fixed parts fill the box; pure
|
interval is split exactly at the length where fixed parts fill the box;
|
||||||
`leftover` children are undrawn on the no-space side.
|
pure `leftover` children are undrawn on the no-space side. Exact/open ranges
|
||||||
|
are for hard widget decisions; the ordinary tolerant ranges remain for
|
||||||
|
accumulated coordinate rounding.
|
||||||
- `Scroll` reports its content's first measured size. Its drawing can survive
|
- `Scroll` reports its content's first measured size. Its drawing can survive
|
||||||
container-length changes only over the interval in which clamping and its
|
container-length changes only over the interval in which clamping and its
|
||||||
current offset do not change.
|
current offset do not change.
|
||||||
@@ -186,9 +213,9 @@ instruction totals.
|
|||||||
|
|
||||||
## Next
|
## Next
|
||||||
|
|
||||||
Let PR #18 review. The next small LAYOUT.md §2 item is `LazySpan`;
|
Let PR #18 review. The next small LAYOUT.md §2 item is `LazySpan`. Region nodes
|
||||||
`set_child_offset` is no longer separate, because placing a child is
|
now cover the independently movable-subtree use case; do not restore a
|
||||||
`Painter::place`.
|
separate child-placement API.
|
||||||
|
|
||||||
After #18 lands, the next structural design is built-in alignment and size.
|
After #18 lands, the next structural design is built-in alignment and size.
|
||||||
Today a declared size and the `Size` returned by `draw` are two sources of
|
Today a declared size and the `Size` returned by `draw` are two sources of
|
||||||
|
|||||||
Reference in new issue
Block a user