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;