Skip to main content

fission_core/ui/widgets/
positioned.rs

1use crate::lowering::{LoweringContext, NodeBuilder};
2use crate::ui::traits::Lower;
3use crate::ui::Node;
4use fission_ir::{
5    op::{LayoutOp, Op},
6    NodeId,
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(Box::new(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<NodeId>,
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<Box<Node>>,
45}
46
47impl Positioned {
48    pub fn into_node(self) -> Node {
49        Node::Positioned(self)
50    }
51}
52
53impl Lower for Positioned {
54    fn lower(&self, cx: &mut LoweringContext) -> NodeId {
55        let id = self.id.unwrap_or_else(|| cx.next_node_id());
56        cx.push_scope(id);
57
58        let child_id = if let Some(child) = &self.child {
59            Some(child.lower(cx))
60        } else {
61            None
62        };
63
64        let mut builder = NodeBuilder::new(
65            id,
66            Op::Layout(LayoutOp::Positioned {
67                left: self.left,
68                top: self.top,
69                right: self.right,
70                bottom: self.bottom,
71                width: self.width,
72                height: self.height,
73            }),
74        );
75
76        if let Some(cid) = child_id {
77            builder.add_child(cid);
78        }
79
80        cx.pop_scope();
81        builder.build(cx)
82    }
83}