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), }; // Whichever child sizes the stack is given the stack's whole box -- // the stack is the length that child asked for, so placing that // answer inside the box it decided would apply it twice. 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, PlaceDesc::WHOLE.fills()).size() } None => Size::LEFTOVER, }; // Every other child gets the box the sizing child decided: the // stack is that length, so that is the box they are asked in, and a // fraction under them is a fraction of it. A share leaves the axis // to whoever gave the stack its box. Where a child sits in a box // bigger than itself is its own business. let place = PlaceDesc::from_axes(|axis| { let len = size[axis]; match len.leftover == Weight::ZERO { true => len.without_leftover().as_desc().fills(), false => PlaceDescAxis::WHOLE, } }); for (i, child) in self.children.iter().enumerate() { if sizing == Some(i) { continue; } painter.child_layer_at(i); painter.widget_at(child, place); } size } /// Without a sizing child a stack is whatever box it is given, which it /// can say without drawing anything. fn size_hint(&self, _: Axis) -> Option { match self.size { StackSize::Default => Some(LayoutLen::LEFTOVER), StackSize::Child(_) => None, } } } #[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 } }