Skip to main content

ribir_widgets/layout/
expanded.rs

1use ribir_core::prelude::*;
2
3use super::ConstrainedBox;
4
5/// A widget that expanded a child of `Flex`, so that the child fills the
6/// available space. If multiple children are expanded, the available space is
7/// divided among them according to the flex factor.
8#[derive(Clone, PartialEq, Query, Declare)]
9pub struct Expanded {
10  #[declare(default = 1.)]
11  pub flex: f32,
12}
13
14impl ComposeChild for Expanded {
15  type Child = Widget;
16  #[inline]
17  fn compose_child(this: impl StateWriter<Value = Self>, child: Self::Child) -> impl WidgetBuilder {
18    fn_widget! {
19      @ConstrainedBox {
20        clamp: BoxClamp {
21          min: Size::new(0., 0.),
22          max: Size::new(f32::INFINITY, f32::INFINITY)
23        },
24        @{ child }
25      }
26      .attach_state_data(this, ctx!())
27    }
28  }
29}
30
31#[cfg(test)]
32mod tests {
33  use ribir_core::test_helper::*;
34  use ribir_dev_helper::*;
35
36  use super::*;
37  use crate::prelude::*;
38
39  fn expand_child_size_zero() -> impl WidgetBuilder {
40    let size = Size::new(100., 50.);
41    fn_widget! {
42      @Row {
43        @Expanded {
44          flex: 1.,
45          @SizedBox { size }
46        }
47        @SizedBox { size }
48        @Expanded {
49          flex: 2.,
50          @SizedBox { size: Size::new(0., 50.) }
51        }
52      }
53    }
54  }
55  widget_layout_test!(
56    expand_child_size_zero,
57    wnd_size = Size::new(500., 500.),
58    { path = [0, 0], width == 400., height == 50.,}
59    { path = [0, 2], width == 0., height == 50.,}
60  );
61
62  fn one_line_expanded() -> impl WidgetBuilder {
63    let size = Size::new(100., 50.);
64    fn_widget! {
65      @Row {
66        @Expanded {
67          flex: 1.,
68          @SizedBox { size }
69        }
70        @SizedBox { size }
71        @SizedBox { size }
72        @Expanded {
73          flex: 2.,
74          @SizedBox { size }
75        }
76      }
77    }
78  }
79  widget_layout_test!(
80    one_line_expanded,
81    wnd_size = Size::new(500., 500.),
82    { path = [0], width == 500., height == 50.,}
83    { path = [0, 0], width == 100., height == 50., }
84    { path = [0, 1], rect == ribir_geom::rect(100., 0., 100., 50.),}
85    { path = [0, 2], rect == ribir_geom::rect(200., 0., 100., 50.),}
86    { path = [0, 3], rect == ribir_geom::rect(300., 0., 200., 50.),}
87  );
88
89  fn wrap_expanded() -> impl WidgetBuilder {
90    let size = Size::new(100., 50.);
91    fn_widget! {
92      @Row {
93        wrap: true,
94        @Expanded {
95          flex: 1. ,
96          @SizedBox { size }
97        }
98        @SizedBox { size }
99        @SizedBox { size }
100        @SizedBox { size }
101        @SizedBox { size }
102        @Expanded {
103          flex: 1. ,
104          @SizedBox { size, }
105        }
106        @Expanded {
107          flex: 4.,
108          @SizedBox { size, }
109        }
110      }
111    }
112  }
113  widget_layout_test!(
114    wrap_expanded,
115    wnd_size = Size::new(350., 500.),
116    { path = [0], rect == ribir_geom::rect(0., 0., 350., 100.),}
117    { path = [0, 0], rect == ribir_geom::rect(0., 0., 50., 50.),}
118    { path = [0, 1], rect == ribir_geom::rect(50., 0., 100., 50.),}
119    { path = [0, 2], rect == ribir_geom::rect(150., 0., 100., 50.),}
120    { path = [0, 3], rect == ribir_geom::rect(250., 0., 100., 50.),}
121    { path = [0, 4], rect == ribir_geom::rect(0., 50., 100., 50.),}
122    { path = [0, 5], rect == ribir_geom::rect(100., 50., 50., 50.),}
123    { path = [0, 6], rect == ribir_geom::rect(150., 50., 200., 50.),}
124  );
125}