Give a slot to the children a container places, and nothing else
A widget's region is now held in the coordinates of the slot it draws in rather than the window's, and `Painter::place` is how a container asks for a slot: it draws a child it decides the box of and may decide again. Everything under that slot is a fraction of its box, so placing the child a second time is one entry to write whether it moved or changed length. A child drawn any other way has no slot and shares its nearest ancestor's. That is what keeps the chain short. `chain_cost` measured depth as the cost -- free to 8, +42.6% at 16 -- and a slot per widget put a transcript's glyphs past that for nothing, since almost every slot was zero. `Span`, `Aligned` and `Scroll` are the containers that re-place a child after drawing it, and `tests/layout.rs` pins that four widgets between a span and a leaf leave the leaf's chain one deep. `UiRegion::stretch`, `UiRegion::stretchable` and `UiScalar::stretch` are gone. Nothing is inverted any more: a box that changed length is written to its slot, and the descendants recompose against it in the shader. That also retires the case the guard existed for, where a fixed length has no fraction to recover -- `tests/layout.rs` now stretches a 40-tall row on its other axis, which `stretchable` refused outright. What still walks the CPU is deciding who must draw again, which no chain can answer: `mark_resized` descends from the widget whose box changed and marks anything whose own box changed length and whose drawing reads it. A part of a box with no relative extent on an axis is a fixed length, and composing into it leaves none either, so the walk stops where a length did not change -- an 80-wide child in a widened row is not redrawn though it says `Redraw`. `Span`, `Pad`, `Stack`, `Offset`, `Aligned`, `SetSize` and `LayerOffset` say `Scale`: each places in fractions and offsets of its own box and none reads the box's pixel length. `Scroll` and `MaxSize` do read pixels and stay `Redraw`. 45 tests pass, five of them new. Render verification comes after the CPU side, per the owner. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
1f9dc48b80
commit
d98969158f
18 files changed
+332
-181
No files matched your search
+31
-8
@@ -13,6 +13,7 @@ pub struct Painter<'a> {
|
||||
pub(super) state: &'a mut UiRenderState,
|
||||
pub(super) rsc: &'a mut dyn UiRsc,
|
||||
|
||||
/// This widget's box, in the coordinates of `move_idx`.
|
||||
pub(super) region: UiRegion,
|
||||
pub(super) mask: MaskIdx,
|
||||
pub(super) textures: Vec<TextureHandle>,
|
||||
@@ -21,7 +22,8 @@ pub struct Painter<'a> {
|
||||
/// The children whose size this widget read while drawing.
|
||||
pub(super) size_deps: Vec<WidgetId>,
|
||||
pub(super) reads_output: bool,
|
||||
/// The move slot this widget's primitives are positioned through.
|
||||
/// The slot this widget's primitives are positioned through: its own if
|
||||
/// its parent placed it, otherwise the nearest ancestor that has one.
|
||||
pub(super) move_idx: MoveIdx,
|
||||
pub layer: usize,
|
||||
pub(super) id: WidgetId,
|
||||
@@ -78,24 +80,39 @@ impl<'a> Painter<'a> {
|
||||
|
||||
/// Draws a widget within this widget's region.
|
||||
pub fn widget<'s, W: ?Sized>(&'s mut self, id: &'s StrongWidget<W>) -> DrawResult<'s, 'a, W> {
|
||||
self.widget_at(id, self.region)
|
||||
self.widget_at(id, self.region, false)
|
||||
}
|
||||
|
||||
/// Draws a widget somewhere within this one. Drawing one a second time
|
||||
/// gives it a new box, keeping the drawing it already has where it can.
|
||||
/// Draws a widget somewhere within this one.
|
||||
pub fn widget_within<'s, W: ?Sized>(
|
||||
&'s mut self,
|
||||
id: &'s StrongWidget<W>,
|
||||
region: UiRegion,
|
||||
) -> DrawResult<'s, 'a, W> {
|
||||
let region = region.within(&self.region);
|
||||
self.widget_at(id, region)
|
||||
self.widget_at(id, region, false)
|
||||
}
|
||||
|
||||
/// Draws a child this widget decides the box of, and may decide again
|
||||
/// once it knows what the child came to. The child gets a slot of its
|
||||
/// own, so placing it a second time writes one entry however much it
|
||||
/// drew -- moved or resized alike, since everything under the slot is
|
||||
/// held as a fraction of its box. A child drawn any other way has no slot
|
||||
/// and can only be given a different box by drawing again.
|
||||
pub fn place<'s, W: ?Sized>(
|
||||
&'s mut self,
|
||||
id: &'s StrongWidget<W>,
|
||||
region: UiRegion,
|
||||
) -> DrawResult<'s, 'a, W> {
|
||||
let region = region.within(&self.region);
|
||||
self.widget_at(id, region, true)
|
||||
}
|
||||
|
||||
fn widget_at<'s, W: ?Sized>(
|
||||
&'s mut self,
|
||||
id: &'s StrongWidget<W>,
|
||||
region: UiRegion,
|
||||
slotted: bool,
|
||||
) -> DrawResult<'s, 'a, W> {
|
||||
// A child listed twice would be moved twice.
|
||||
if !self.children.contains(&id.id()) {
|
||||
@@ -106,6 +123,8 @@ impl<'a> Painter<'a> {
|
||||
id.id(),
|
||||
region,
|
||||
Some(self.id),
|
||||
self.move_idx,
|
||||
slotted,
|
||||
self.mask,
|
||||
None,
|
||||
self.rsc,
|
||||
@@ -165,6 +184,8 @@ impl<'a> Painter<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// This widget's box, in the coordinates its own primitives are written
|
||||
/// in -- so a region composed `within` it may be drawn directly.
|
||||
pub fn region(&self) -> UiRegion {
|
||||
self.region
|
||||
}
|
||||
@@ -176,11 +197,13 @@ impl<'a> Painter<'a> {
|
||||
self.state.output_size
|
||||
}
|
||||
|
||||
/// This widget's box in pixels. Resolved against the output's size, so a
|
||||
/// widget that reads it draws again when the output changes.
|
||||
/// This widget's box in pixels. Resolved against the output's size and
|
||||
/// the boxes it sits within, so a widget that reads it draws again when
|
||||
/// the output changes.
|
||||
pub fn px_size(&mut self) -> Vec2 {
|
||||
self.reads_output = true;
|
||||
self.region.size().to_abs(self.state.output_size)
|
||||
let region = self.state.moves.resolve(self.move_idx, self.region);
|
||||
region.size().to_abs(self.state.output_size)
|
||||
}
|
||||
|
||||
pub fn text_data(&mut self) -> &mut TextData {
|
||||
|
||||
Reference in new issue
Block a user