use std::marker::PhantomData; use crate::prelude::*; pub struct Stack { pub children: Vec, pub size: StackSize, } impl Widget for Stack { fn draw(&mut self, painter: &mut Painter) -> Size { let sizing = match self.size { StackSize::Default => None, StackSize::Child(i) => Some(i), }; // This stack's own box, which is `FULL` until its answer is known. let placement = painter.placement(); // Whichever child sizes the stack keeps the stack's whole region as // its own -- the stack is the length that child asked for, so taking // the fraction of the stack's box again would take it twice -- and is // put where the stack itself is put. let size = match sizing.and_then(|i| self.children.get(i).map(|c| (i, c))) { // On the layer that child ends up on, so the ask below is a reuse // rather than a second drawing of it somewhere else: a retained // drawing belongs to the layer it was made on. Some((i, child)) => { painter.child_layer_at(i); painter .widget_at( child, UiRegion::FULL, [Some(placement.x), Some(placement.y)], ) .size() } None => Size::LEFTOVER, }; for (i, child) in self.children.iter().enumerate() { if sizing == Some(i) { continue; } painter.child_layer_at(i); // Every other child has the stack's own box for its region, since // the stack is what contains it, and where it sits in one bigger // than itself is its own business. painter.widget_within(child, placement); } size } } #[derive(Default, Debug)] pub enum StackSize { #[default] Default, Child(usize), } pub struct StackBuilder, Tag> { pub children: Wa, pub size: StackSize, _pd: PhantomData<(State, Tag)>, } impl, Tag> WidgetFnTrait for StackBuilder { type Widget = Stack; #[track_caller] fn run(self, rsc: &mut Rsc) -> Self::Widget { Stack { children: self.children.add(rsc).arr.into_iter().collect(), size: self.size, } } } impl, Tag> StackBuilder { pub fn new(children: Wa) -> Self { Self { children, size: StackSize::default(), _pd: PhantomData, } } pub fn size(mut self, size: StackSize) -> Self { self.size = size; self } }