layout/stack: opt-in Stack::fit_content() so a wrapping container can adopt the stack's intrinsic size
`Stack::preferred_size` unconditionally reported `(max_width, max_h)` — every stack claimed the full width its parent offered, regardless of what its children actually needed. That is the right default for a FrameLayout-style overlay (the existing callers all rely on it) but it makes the natural "pin a stack to a fixed-size child (e.g. a spacer of `card_w × card_h`) and centre other children on top of it" pattern impossible: a container wrapping such a stack always inherited the full parent width and ignored the spacer's footprint. The new `Stack::fit_content()` builder mirrors the `Column::fit_content` flag — when set, `preferred_size` returns the max of children's intrinsic widths and heights instead of claiming the parent's `max_width`, with the same "skip filler widgets that themselves claim `max_width`" exclusion list (`Spacer` with no `fixed_width`, `Separator`, `Scroll`, `ProgressBar`, `Slider`, `TextEdit` without `fixed_width`) so the flag is not defeated by a flexible child slipping into the stack. Default behaviour is unchanged.
This commit is contained in:
@@ -54,6 +54,7 @@ pub struct Stack<Msg: Clone>
|
|||||||
/// Children with their alignment, margin, and extra `(x, y)` translation
|
/// Children with their alignment, margin, and extra `(x, y)` translation
|
||||||
/// applied after alignment. Drawn in order — last child is on top.
|
/// applied after alignment. Drawn in order — last child is on top.
|
||||||
pub children: Vec<( Element<Msg>, HAlign, VAlign, f32, f32, f32 )>,
|
pub children: Vec<( Element<Msg>, HAlign, VAlign, f32, f32, f32 )>,
|
||||||
|
pub fit_content: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Msg: Clone> Stack<Msg>
|
impl<Msg: Clone> Stack<Msg>
|
||||||
@@ -61,7 +62,13 @@ impl<Msg: Clone> Stack<Msg>
|
|||||||
/// Create an empty stack.
|
/// Create an empty stack.
|
||||||
pub fn new() -> Self
|
pub fn new() -> Self
|
||||||
{
|
{
|
||||||
Self { children: Vec::new() }
|
Self { children: Vec::new(), fit_content: false }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fit_content( mut self ) -> Self
|
||||||
|
{
|
||||||
|
self.fit_content = true;
|
||||||
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Append a child that fills the entire Stack rect (Android FrameLayout default).
|
/// Append a child that fills the entire Stack rect (Android FrameLayout default).
|
||||||
@@ -111,9 +118,31 @@ impl<Msg: Clone> Stack<Msg>
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the preferred `(width, height)` — the maximum height among children.
|
|
||||||
pub fn preferred_size( &self, max_width: f32, canvas: &Canvas ) -> (f32, f32)
|
pub fn preferred_size( &self, max_width: f32, canvas: &Canvas ) -> (f32, f32)
|
||||||
{
|
{
|
||||||
|
if self.fit_content
|
||||||
|
{
|
||||||
|
let content_w = self.children.iter()
|
||||||
|
.map( |( c, _, _, _, _, _ )| match c
|
||||||
|
{
|
||||||
|
Element::Spacer( s ) => s.fixed_width.unwrap_or( 0.0 ),
|
||||||
|
Element::Separator( _ ) => 0.0,
|
||||||
|
Element::Scroll( _ ) => 0.0,
|
||||||
|
Element::ProgressBar( _ ) => 0.0,
|
||||||
|
Element::Slider( _ ) => 0.0,
|
||||||
|
Element::TextEdit( t ) => if t.fixed_width.is_some()
|
||||||
|
{
|
||||||
|
t.preferred_size( max_width, canvas ).0
|
||||||
|
} else { 0.0 },
|
||||||
|
other => other.preferred_size( max_width, canvas ).0,
|
||||||
|
} )
|
||||||
|
.fold( 0.0_f32, f32::max );
|
||||||
|
let max_h = self.children.iter()
|
||||||
|
.map( |( c, _, _, _, _, _ )| c.preferred_size( max_width, canvas ).1 )
|
||||||
|
.fold( 0.0_f32, f32::max );
|
||||||
|
return ( content_w.min( max_width ), max_h );
|
||||||
|
}
|
||||||
|
|
||||||
let max_h = self.children.iter()
|
let max_h = self.children.iter()
|
||||||
.map( |( c, _, _, _, _, _ )| c.preferred_size( max_width, canvas ).1 )
|
.map( |( c, _, _, _, _, _ )| c.preferred_size( max_width, canvas ).1 )
|
||||||
.fold( 0.0_f32, f32::max );
|
.fold( 0.0_f32, f32::max );
|
||||||
@@ -163,6 +192,7 @@ impl<Msg: Clone> Stack<Msg>
|
|||||||
.map( |( child, ha, va, margin, ox, oy )|
|
.map( |( child, ha, va, margin, ox, oy )|
|
||||||
( child.map_arc( f ), ha, va, margin, ox, oy ) )
|
( child.map_arc( f ), ha, va, margin, ox, oy ) )
|
||||||
.collect(),
|
.collect(),
|
||||||
|
fit_content: self.fit_content,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user