Skip to main content

tui_lipan/widgets/center_pin/
mod.rs

1mod layout;
2mod node;
3mod reconcile;
4
5pub(crate) use self::layout::measure_center_pin;
6pub use self::node::CenterPinNode;
7pub(crate) use self::reconcile::reconcile_center_pin;
8
9use crate::core::element::{Element, ElementKind};
10use crate::style::{LayoutConstraints, Length, Style};
11
12/// A layout container that pins one child to the true center of the available
13/// area, giving the remaining space above and below to `top` and `bottom`
14/// children respectively.
15///
16/// Unlike a `ZStack` + `Center` combination, the top and bottom zones are
17/// collision-aware: they receive only the space that remains after the centered
18/// child is placed, so they will never overlap it regardless of how their
19/// content grows or shrinks.
20///
21/// ```rust,ignore
22/// CenterPin::new()
23///     .top(VStack::new().child(header).child(nav))
24///     .center(dialog)
25///     .bottom(status_bar)
26/// ```
27///
28/// The container defaults to `Flex(1)` on both axes so it expands to fill its
29/// parent (typically the whole screen).
30#[derive(Clone, Default)]
31pub struct CenterPin {
32    pub(crate) top: Option<Box<Element>>,
33    pub(crate) center: Option<Box<Element>>,
34    pub(crate) bottom: Option<Box<Element>>,
35    pub(crate) style: Style,
36}
37
38impl CenterPin {
39    /// Create an empty CenterPin.
40    pub fn new() -> Self {
41        Self::default()
42    }
43
44    /// Set the element displayed in the zone above the centered child.
45    pub fn top(mut self, top: impl Into<Element>) -> Self {
46        self.top = Some(Box::new(top.into()));
47        self
48    }
49
50    /// Set the element that is always pinned to the center of the container.
51    pub fn center(mut self, center: impl Into<Element>) -> Self {
52        self.center = Some(Box::new(center.into()));
53        self
54    }
55
56    /// Set the element displayed in the zone below the centered child.
57    pub fn bottom(mut self, bottom: impl Into<Element>) -> Self {
58        self.bottom = Some(Box::new(bottom.into()));
59        self
60    }
61
62    /// Set base style (e.g. background color).
63    pub fn style(mut self, style: Style) -> Self {
64        self.style = style;
65        self
66    }
67}
68
69impl From<CenterPin> for Element {
70    fn from(value: CenterPin) -> Self {
71        let (min_w, min_h) = measure_center_pin(&value, None, None);
72        Element::new(ElementKind::CenterPin(value)).with_layout(
73            LayoutConstraints::default()
74                .min_width(Length::Px(min_w))
75                .min_height(Length::Px(min_h)),
76        )
77    }
78}