Skip to main content

fission_core/ui/widgets/
positioned.rs

1use crate::internal::InternalLower;
2use crate::lowering::{InternalIrBuilder, InternalLoweringCx};
3use crate::ui::Widget;
4use fission_ir::{
5    op::{LayoutOp, Op},
6    WidgetId,
7};
8use serde::{Deserialize, Serialize};
9
10/// Absolutely positions a child within a [`ZStack`](super::ZStack).
11///
12/// Specify one or more edge offsets (`left`, `top`, `right`, `bottom`) and
13/// optional explicit `width`/`height`. Omitting both horizontal offsets (or
14/// both vertical offsets) leaves the child unconstrained on that axis.
15///
16/// # Example
17///
18/// ```rust,ignore
19/// // Pin a badge to the top-right corner
20/// Positioned {
21///     top: Some(8.0),
22///     right: Some(8.0),
23///     child: Some(badge_widget),
24///     ..Default::default()
25/// }
26/// ```
27#[derive(Debug, Default, Clone, Serialize, Deserialize)]
28pub struct Positioned {
29    /// Explicit node identity.
30    pub id: Option<WidgetId>,
31    /// Distance from the left edge of the parent.
32    pub left: Option<f32>,
33    /// Distance from the top edge of the parent.
34    pub top: Option<f32>,
35    /// Distance from the right edge of the parent.
36    pub right: Option<f32>,
37    /// Distance from the bottom edge of the parent.
38    pub bottom: Option<f32>,
39    /// Explicit width override.
40    pub width: Option<f32>,
41    /// Explicit height override.
42    pub height: Option<f32>,
43    /// The child widget to position.
44    pub child: Option<Widget>,
45}
46
47impl Positioned {}
48
49impl InternalLower for Positioned {
50    fn lower(&self, cx: &mut InternalLoweringCx) -> WidgetId {
51        let id = self.id.map(Into::into).unwrap_or_else(|| cx.next_node_id());
52        cx.push_scope(id);
53
54        let child_id = if let Some(child) = &self.child {
55            Some(child.lower(cx))
56        } else {
57            None
58        };
59
60        let mut builder = InternalIrBuilder::new(
61            id,
62            Op::Layout(LayoutOp::Positioned {
63                left: self.left,
64                top: self.top,
65                right: self.right,
66                bottom: self.bottom,
67                width: self.width,
68                height: self.height,
69            }),
70        );
71
72        if let Some(cid) = child_id {
73            builder.add_child(cid);
74        }
75
76        cx.pop_scope();
77        builder.build(cx)
78    }
79}