Redesign span layout around retained placement

This commit is contained in:
iris committed 2026-09-09 15:11:57 -04:00
1 parent 4b69f3cc6b
commit 992482414f
23 files changed
+426 -1005

No files matched your search

+5 -49
View File
@@ -11,59 +11,15 @@ pub struct ActiveData {
pub textures: Vec<TextureHandle>,
pub primitives: Vec<PrimitiveHandle>,
pub children: Vec<WidgetId>,
/// The mask this widget was drawn **under** (its parent's), not the
/// one it set for itself -- see `own_mask` for that.
/// The inherited mask, not `own_mask`.
pub mask: MaskIdx,
/// The mask slot this widget allocated for *itself* with
/// `Painter::set_mask`, or `MaskIdx::NONE`. Kept across redraws and
/// rewritten in place, the way `move_slot` is: a `Masked` that pushed
/// a fresh slot each draw left every already-drawn descendant --
/// which `draw_inner`'s unchanged-region fast path does not revisit --
/// clipping to the *old* slot's region, so a composer whose bar had
/// since been placed at the bottom of the screen was still being
/// clipped to a box at the top of it and drew nothing (measured
/// 2026-09-06: four mask entries live, none of them the widget's
/// current region). Its path out is the `undraw` branch of
/// `UiRenderState::remove`, which drops the self-ownership ref taken
/// when the slot was allocated.
/// The widget's retained mask slot, or `MaskIdx::NONE`.
pub own_mask: MaskIdx,
pub layer: LayerId,
/// What `Widget::draw` returned the last time this widget was actually
/// drawn -- read by a parent placing this widget again without
/// redrawing it, replacing `Cache.size`'s old role. See LAYOUT.md
/// section 5.
/// The last `Widget::draw` result.
pub size: Size,
/// This widget's slot in `UiData::move_offsets`, assigned on its first
/// draw and kept for the rest of its life (redraws reuse it in place
/// so a retained child's `parent` link never goes stale). See
/// LAYOUT.md section 2.
/// Retained so descendants' parent links stay valid across redraws.
pub move_slot: MoveIdx,
/// How much of this widget's own `move_slot` delta is already folded
/// into `region` above, in window pixels. The two mechanisms that
/// write that slot disagree about this and cannot be told apart from
/// the slot alone: `UiRenderState::mov` shifts `region` and the delta
/// together (the *offered* region genuinely moved), while
/// `Painter::reposition` writes only the delta (`region` stays the
/// offered box and the delta says where inside it the content was
/// placed). So anything that wants the widget's real position --
/// `resolved_region`, and through it every hit test -- must subtract
/// this from the chain sum. Without it a panned widget's own hit box
/// sits at twice the pan while its descendants' are correct, which is
/// how it went unnoticed: the composer's field became untappable
/// after a finger pan (2026-09-06). Reset to zero whenever the widget
/// is really redrawn, since `draw_inner` zeroes the slot then too.
/// The part of this widget's move delta already folded into `region`.
pub move_applied: Vec2,
/// The offset the last `Painter::reposition` placed this widget's
/// content at *within* `region`, in window pixels. The move slot has
/// exactly one owner and one meaning:
/// `move_offsets[move_slot] == move_applied + repositioned`. `mov`
/// adds to the first, `reposition` overwrites the second (it
/// recomputes `from` afresh every call, so repeating it must land on
/// the same answer rather than drifting), and both then rewrite the
/// slot from the sum -- which is what lets a parent both move a child
/// with its own layout and place it inside that moved region in one
/// frame. `LazySpan::place`'s Bottom-known branch does exactly that once a
/// row's blocks wrap. Reset to zero on a real redraw, with
/// `move_applied` and the slot itself.
pub repositioned: Vec2,
}