Record why a move recomposes, and settle alignment's ownership
The measurement is the part worth keeping: adding an offset to a moved subtree's stored regions drifts linearly and without bound, so the fraction path is there for accuracy, not generality. `tests/drift.rs` on the Iris branch pins it. Built-in alignment and size moves onto #18 rather than waiting for it, with ownership agreed -- properties on the `region_node` mechanism, a declared length winning per axis, and a size rule that carries min/max/clamp so a clamp is resolved where the box is decided instead of by a widget reading its own pixels.
This commit is contained in:
1 parent
8db0969d9d
commit
cf7b33da39
1 file changed
+57
-11
+57
-11
@@ -8,7 +8,7 @@ log.
|
||||
|
||||
Canonical Iris `main` is **`ca2b4b2`** (#17, the headless rig). **#18
|
||||
`split/18-position-chain`** is open in `/home/bob/repos/iris-pr18`; its local
|
||||
head is **`71c9c39`**, forty-seven commits, pushed to the fork. No PR reviews
|
||||
head is **`0283c9d`**, forty-eight commits, pushed to the fork. No PR reviews
|
||||
were present when checked on 2026-09-15; the verification summary is posted on
|
||||
the PR.
|
||||
|
||||
@@ -70,11 +70,11 @@ rewrite:
|
||||
`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.
|
||||
|
||||
## Verification at `71c9c39`
|
||||
## Verification at `0283c9d`
|
||||
|
||||
- `cargo fmt --all --check`
|
||||
- `cargo clippy --workspace --all-targets --all-features -- -D warnings`
|
||||
- `cargo test --workspace --all-features`: 84 passed, 10 ignored
|
||||
- `cargo test --workspace --all-features`: 85 passed, 10 ignored
|
||||
- `cargo test --release --test generated -- --ignored
|
||||
a_long_run_of_seeds_agrees --exact`: 100 seeds passed in 64.77 s
|
||||
- The `tabs` reference at 900x1200 remained byte-identical to `f437495`: zero
|
||||
@@ -158,6 +158,19 @@ tighter figures.
|
||||
- `Scroll` reports its content's first measured size. Its drawing can survive
|
||||
container-length changes only over the interval in which clamping and its
|
||||
current offset do not change.
|
||||
- **A move must re-express each part as the same fraction of its new box, not
|
||||
add an offset to the last answer.** A subtree's stored regions are the only
|
||||
record of where it is, so an offset integrates its own rounding and nothing
|
||||
recomputes it. Measured 2026-09-15 on `tests/drift.rs`: offsetting both ends
|
||||
of a span shortens that fixture's row by 0.071 over 20,000 moves and 0.712
|
||||
over 200,000, growing with the count; placing the far end from the near one
|
||||
leaves 0.069, because the length is re-derived from the endpoints either
|
||||
way. 20,000 moves is five minutes of scrolling at 60Hz, which is when it
|
||||
passes the 0.05 physical pixels layout treats as the same place. The
|
||||
fraction path is exact at 200,000. So `RegionRemap` is load-bearing for
|
||||
accuracy rather than for generality, and its multiplies are not what is
|
||||
being paid for. The generated oracle compares within 0.05 and `unsettled.rs`
|
||||
runs too few frames to reach it, which is why `tests/drift.rs` exists.
|
||||
|
||||
## Rigs and reproduction
|
||||
|
||||
@@ -213,15 +226,48 @@ instruction totals.
|
||||
|
||||
## Next
|
||||
|
||||
Let PR #18 review. The next small LAYOUT.md §2 item is `LazySpan`. Region nodes
|
||||
now cover the independently movable-subtree use case; do not restore a
|
||||
separate child-placement API.
|
||||
The next small LAYOUT.md §2 item is `LazySpan`. Region nodes now cover the
|
||||
independently movable-subtree use case; do not restore a separate
|
||||
child-placement API. `docs/LAYOUT.md` §2 is stale: it still describes
|
||||
`Painter::place`, which `71c9c39` replaced.
|
||||
|
||||
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
|
||||
truth, and alignment can disappear behind a wrapper. Agree their ownership
|
||||
before implementing it. Do not restore `OnResize::Translate`; retained
|
||||
translation is now expressed by the same `Holds` contract and box chain.
|
||||
**Built-in alignment and size is next, and goes on #18 rather than after it**
|
||||
(Bryan, 2026-09-15: #18 is unreviewed and already large enough that most lines
|
||||
get read anyway). Ownership is agreed:
|
||||
|
||||
- Declared size and alignment become **widget properties on the same mechanism
|
||||
as `region_node`**, read by `Painter::widget_at`. `SetSize`, `MaxSize` and
|
||||
`Aligned` are deleted, and `.width()`, `.sized()`, `.max_width()`, `.align()`
|
||||
and `.center()` stop building widgets. `Painter` then owns measure-then-place,
|
||||
which `Span`, `Aligned` and `Scroll` each implement separately today.
|
||||
- A **declared length wins per axis**; the `Size` returned by `draw` answers
|
||||
only the axes with no declaration. The rule becomes an enum per axis --
|
||||
`Exact`, `Min`, `Max`, `Clamp` -- so a clamp is resolved where the box is
|
||||
decided instead of by a wrapper. `MaxSize::draw` currently calls
|
||||
`px_size()`, which pins its interval to one exact box on both axes and
|
||||
redraws its whole subtree on any resize; the parent resolving the clamp
|
||||
reads px itself and can declare the interval over which the answer holds.
|
||||
- The clamp boundary is a **hard layout decision, not a tolerance**, the same
|
||||
shape as `Span`'s leftover split. Its `Holds` range must be exact and split
|
||||
at the crossover; generated seed 16 is what a tolerant endpoint costs.
|
||||
- Two things to settle while implementing. `max_width` today does not
|
||||
constrain anything -- `MaxSize` draws its child in its full box and only
|
||||
caps the `Size` it reports upward -- so resolving the rule in the box is a
|
||||
behaviour change. And `declared_len` derives from `size_hint`, so one
|
||||
channel carries both "my size, for a span to divide around" and "resolve my
|
||||
box to this length"; those separate.
|
||||
|
||||
Why it comes before anything else that touches layout: a widget's `region`
|
||||
becomes **its reported size placed by its alignment inside the offer**, rather
|
||||
than the offer itself. A span's measure-then-place then moves a child between
|
||||
boxes of the same length, so it is a translation by construction, and the
|
||||
measuring draw disappears wherever the size is knowable without one. That
|
||||
changes what `.background()` sits behind, so the reference renders stop being
|
||||
byte-identical to `ca2b4b2` and the generated cold-layout oracle becomes the
|
||||
verification.
|
||||
|
||||
Do not restore `OnResize::Translate`; retained translation is now expressed by
|
||||
the same `Holds` contract and box chain.
|
||||
|
||||
Other queued work, in dependency order:
|
||||
|
||||
|
||||
Reference in new issue
Block a user