ltk/widget/flex/mod.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
// SPDX-License-Identifier: LGPL-2.1-only
// Copyright (C) 2026 Liberux Labs, S. L. <info@liberux.net>
use crate::render::Canvas;
use super::Element;
/// Wraps an [`Element`] so that a [`Row`](crate::layout::row::Row) treats it
/// like a [`Spacer`](crate::layout::spacer::Spacer) for leftover-width
/// distribution, but draws the child inside the allocated rect.
///
/// Use this to make a non-trivial child fill remaining width without resorting
/// to a hard-coded `max_width`. The row computes how much width is left after
/// the fixed-size siblings, splits it across all flex / spacer children
/// proportionally to their `weight`, and gives the flex its share. The wrapped
/// child sees that share as its layout rect — text inside it triggers its own
/// elide path on overflow, columns adjust their inner width, etc.
///
/// ```rust,no_run
/// # use ltk::{ column, flex, row, Element };
/// # #[ derive( Clone ) ] enum Msg {}
/// # fn _ex(
/// # icon: Element<Msg>,
/// # title: Element<Msg>,
/// # subtitle: Element<Msg>,
/// # ) -> Element<Msg> {
/// row()
/// .push( icon )
/// .push( flex( column().push( title ).push( subtitle ) ) )
/// .into()
/// # }
/// ```
///
/// Currently only [`Row`](crate::layout::row::Row) honours flex distribution.
/// Inside a [`Column`](crate::layout::column::Column) a flex child behaves
/// like a regular zero-width child along the main axis — vertical flex is not
/// yet implemented.
pub struct Flex<Msg: Clone>
{
pub child: Box<Element<Msg>>,
pub weight: u32,
}
impl<Msg: Clone> Flex<Msg>
{
pub fn new( child: impl Into<Element<Msg>> ) -> Self
{
Self
{
child: Box::new( child.into() ),
weight: 1,
}
}
/// Relative weight when sharing leftover width with other flex / spacer
/// children in the same row (default `1`). A flex with `weight = 2`
/// claims twice the space of a sibling with `weight = 1`.
pub fn weight( mut self, w: u32 ) -> Self
{
self.weight = w;
self
}
pub fn preferred_size( &self, max_width: f32, canvas: &Canvas ) -> ( f32, f32 )
{
// Width contribution to the parent row is zero — the actual width
// comes from the flex distribution. Height comes from the child so
// the row's row-height calculation still picks us up.
let ( _, h ) = self.child.preferred_size( max_width, canvas );
( 0.0, h )
}
pub( crate ) fn map_msg<U>( self, f: &super::MapFn<Msg, U> ) -> Flex<U>
where
U: Clone + 'static,
Msg: 'static,
{
Flex
{
child: Box::new( self.child.map_arc( f ) ),
weight: self.weight,
}
}
}
pub fn flex<Msg: Clone>( child: impl Into<Element<Msg>> ) -> Flex<Msg>
{
Flex::new( child )
}
impl<Msg: Clone + 'static> From<Flex<Msg>> for Element<Msg>
{
fn from( f: Flex<Msg> ) -> Self
{
Element::Flex( f )
}
}
#[ cfg( test ) ]
mod tests;