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