A ninth sweep, over the part no earlier round named -- the widget vocabulary and the builder methods, `Widgets`, the examples, the `util` additions and the manifests -- and once more over `77ed7a2`, the eighth sweep's own commit and so itself unreviewed. A hint overrode a rule. `declared_lens` asked `rules[axis].declared()` first and fell through to the widget's own `size_hint` whenever that answered `None` -- which it does for a share, since a share is not a declaration. So a widget carrying `width(leftover(1))` and hinting a pixel length of its own was handed a box of the hint, against the rule and against the comment inside the function: "a hint still narrows the box where no rule does". `Painter::size_hint` spells the same rule-else-hint step three hundred lines up and gets it right, with the reason written on it; both read `Widgets::exact_len` now, and `declared_lens` is the part of its answer that needs nobody to divide it. `Image` is the only widget here whose hint is a declared length, and neither the tests nor the generator builds one, so nothing in this repository could reach the difference -- which is why the dump is unchanged and why the test builds a widget of its own. It records the box it was asked in: 400 with the rule and 50 without, and 50 either way before this. Marking a widget for redraw had no name. Twenty-one sites under `tests/` said it as `widgets_mut().get_dyn_mut(id);` with the widget thrown away, five with a `let _ =` in front, one with a comment explaining what the line was for, and one wrapped in a local function called `mark`. `Widgets::mark_for_redraw` says it. `revision_cost.rs` keeps the long spelling and now says why in place: it is deliberately in the API subset an old worktree also has. `assert_same_regions` could not see the defect the eighth sweep had just fixed. It zips the warm and cold id lists, so a list naming one widget twice -- which is what `width`, `sized` and `align` giving back their own argument produces -- compares fewer boxes than it lists and says nothing about it. It now rejects a repeated id and two lists of different lengths, which also checks the nine fixtures that round left alone: all eighteen cases pass. Bare pairs where the framework has named ones. `random.rs`'s `Lens` and `Aligns` were `[Option<LayoutLen>; 2]` and `[Option<AxisAlign>; 2]`, read as `[0]`/`[1]` and zipped against a hand-written `[Axis::X, Axis::Y]`. They are `SizeRules` and `Align`; `Align` took the `Index<Axis>` every other per-axis pair on this branch has, and `RegionAlign::from` does the "an axis left out is centred" step two rigs were spelling per axis. The three sites that wrote the axis pair out say `Axis::BOTH`, which is what the rest of the layout code says. `BothAxis<T>`, `AxisT`, `XAxis` and `YAxis` -- 45 lines with a const trait, two marker types and three accessors -- have no user anywhere in the workspace. They are the mechanism `impl_axis_index!` replaced, in the file this branch took `Vec2::axis`/`axis_mut` out of. Deleted, which is a drive-by in a block the branch was already rewriting; drop it if the scope matters more. Smaller things, each in its own place: `Wrapper` arrived beside core's `WidgetWrapper`, one word for a widget that wraps a child and for a dynamic borrow guard, so the alias is gone and its two uses name `DynBorrower` -- which is what they are. `Wrapper::new`, `Wrapper::empty` and its `Default` were three names for one value, two of them unused. `Arena::get_mut` was the only `pub(crate)` among `pub` siblings on a public type. `Selector` rounded the pointer onto the pixel grid to do arithmetic on two values already there, losing the precision the platform gave it for nothing; the step between the regions is taken on the grid instead. And the two `debug` profile settings carry their reason where the next reader looks rather than only in the commit that made them, one of which was about renaming `rest`. Format, clippy with and without layout-diagnostics, and the suite (132 + 19 + 13 + 4) are clean. The cold dump over 400 depth-5 trees is byte-identical to `77ed7a2` across all 34,488 boxes, and all three seed scans pass: 400 at depth 5 in 63.27s, 1,000 at depth 6 in 160.45s, 2,000 at depth 4 in 302.52s. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
127 lines
4.0 KiB
Rust
127 lines
4.0 KiB
Rust
//! Traces the four-widget trees in `unsettled.rs`, to see what box their text
|
|
//! is actually drawn in on a first frame against a settled one.
|
|
|
|
#![cfg(feature = "layout-diagnostics")]
|
|
|
|
use iris::core::layout_diagnostics::{self as diag, TraceEvent};
|
|
use iris::harness::Harness;
|
|
use iris::prelude::*;
|
|
|
|
fn plant(h: &mut Harness) -> Vec<WidgetId> {
|
|
let plain = wtext("Wrapping").size(16).wrap(false).add(&mut h.rsc);
|
|
let wrapped = wtext("Wrapping shapes")
|
|
.size(16)
|
|
.wrap(true)
|
|
.width(76)
|
|
.add(&mut h.rsc);
|
|
h.rsc
|
|
.widgets_mut()
|
|
.set_alignment(wrapped, Axis::X, AxisAlign::POS);
|
|
h.rsc
|
|
.widgets_mut()
|
|
.set_alignment(wrapped, Axis::Y, AxisAlign::POS);
|
|
let stack = Stack {
|
|
children: vec![plain.add_strong(&mut h.rsc), wrapped.add_strong(&mut h.rsc)],
|
|
size: StackSize::Child(0),
|
|
}
|
|
.add(&mut h.rsc);
|
|
let root = (stack,).span(Dir::RIGHT).add(&mut h.rsc);
|
|
h.state.root = Some(root.add_strong(&mut h.rsc));
|
|
vec![plain.id(), wrapped.id(), stack.id(), root.id()]
|
|
}
|
|
|
|
fn dump(label: &str, report: &diag::Report, text: WidgetId) {
|
|
println!("--- {label} ---");
|
|
for event in report.traces() {
|
|
match event {
|
|
TraceEvent::DrawRequest {
|
|
id,
|
|
region,
|
|
region_px,
|
|
..
|
|
} if *id == text => {
|
|
println!(
|
|
" draw in {:.2}x{:.2} region {region:?}",
|
|
region_px.x, region_px.y
|
|
)
|
|
}
|
|
TraceEvent::SizeReported { id, size } if *id == text => {
|
|
println!(" reported {size}")
|
|
}
|
|
TraceEvent::SizeRead { id, reader, size } if *id == text => {
|
|
println!(" size read by {reader:?}: {size}")
|
|
}
|
|
TraceEvent::RegionNode { id, parent, region } if *id == text => {
|
|
println!(" region node under {parent:?} at {region:?}")
|
|
}
|
|
TraceEvent::Reuse { id, outcome } if *id == text => println!(" reuse: {outcome:?}"),
|
|
_ => {}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
#[ignore = "a diagnostic, not a check"]
|
|
fn what_box_the_text_is_drawn_in() {
|
|
diag::clear_traced_widgets();
|
|
let _ = diag::take();
|
|
let mut h = Harness::new((640, 900));
|
|
let ids = plant(&mut h);
|
|
let text = ids[1];
|
|
diag::trace_widget(text);
|
|
let _ = diag::take();
|
|
|
|
h.frame();
|
|
dump("first frame", &diag::take(), text);
|
|
|
|
for _ in 0..2 {
|
|
for &id in &ids {
|
|
h.rsc.widgets_mut().mark_for_redraw(id);
|
|
}
|
|
let _ = diag::take();
|
|
h.frame();
|
|
dump("repaint", &diag::take(), text);
|
|
}
|
|
diag::clear_traced_widgets();
|
|
}
|
|
|
|
fn plant_fixed(h: &mut Harness) -> Vec<WidgetId> {
|
|
let words = "Wrapping shapes one source into as many lines as the box leaves";
|
|
let text = wtext(words).size(16).wrap(true).add(&mut h.rsc);
|
|
h.rsc
|
|
.widgets_mut()
|
|
.set_alignment(text, Axis::X, AxisAlign::NEG);
|
|
let inner = (text,).span(Dir::RIGHT).sized((189, 176)).add(&mut h.rsc);
|
|
let filler = rect(Color::RED).add(&mut h.rsc);
|
|
let root = (filler, inner).span(Dir::RIGHT).add(&mut h.rsc);
|
|
h.state.root = Some(root.add_strong(&mut h.rsc));
|
|
vec![text.id(), inner.id(), filler.id(), root.id()]
|
|
}
|
|
|
|
#[test]
|
|
#[ignore = "a diagnostic, not a check"]
|
|
fn what_box_the_fixed_text_is_drawn_in() {
|
|
diag::clear_traced_widgets();
|
|
let _ = diag::take();
|
|
let mut h = Harness::new((1920, 1200));
|
|
let ids = plant_fixed(&mut h);
|
|
let text = ids[0];
|
|
diag::trace_widget(text);
|
|
let _ = diag::take();
|
|
|
|
h.frame();
|
|
dump("first frame at 1920", &diag::take(), text);
|
|
h.resize((640, 900));
|
|
h.frame();
|
|
dump("after resize to 640", &diag::take(), text);
|
|
|
|
let mut cold = Harness::new((640, 900));
|
|
let cids = plant_fixed(&mut cold);
|
|
diag::clear_traced_widgets();
|
|
diag::trace_widget(cids[0]);
|
|
let _ = diag::take();
|
|
cold.frame();
|
|
dump("cold at 640", &diag::take(), cids[0]);
|
|
diag::clear_traced_widgets();
|
|
}
|