Skip to main content

fission_core/ui/widgets/
focus_scope.rs

1use crate::lowering::{wrap_zstack_child, LoweringContext, NodeBuilder};
2use crate::ui::traits::Lower;
3use crate::ui::Node;
4use fission_ir::{semantics::Role, NodeId, Op, Semantics};
5use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct FocusScope {
9    pub id: Option<NodeId>,
10    pub children: Vec<Node>,
11    pub is_barrier: bool,
12}
13
14impl Default for FocusScope {
15    fn default() -> Self {
16        Self {
17            id: None,
18            children: Vec::new(),
19            is_barrier: false,
20        }
21    }
22}
23
24impl FocusScope {
25    pub fn into_node(self) -> Node {
26        Node::FocusScope(self)
27    }
28}
29
30impl Lower for FocusScope {
31    fn lower(&self, cx: &mut LoweringContext) -> NodeId {
32        let id = self.id.unwrap_or_else(|| cx.next_node_id());
33
34        cx.push_scope(id);
35        let mut child_ids = Vec::new();
36        for child in &self.children {
37            child_ids.push(child.lower(cx));
38        }
39        cx.pop_scope();
40
41        // Wrap children in a ZStack layout node
42        let layout_id = cx.next_node_id();
43        cx.push_scope(layout_id);
44        let mut wrapped_children = Vec::with_capacity(child_ids.len());
45        for cid in child_ids {
46            wrapped_children.push(wrap_zstack_child(cx, cid));
47        }
48        cx.pop_scope();
49
50        let mut layout_builder =
51            NodeBuilder::new(layout_id, Op::Layout(fission_ir::LayoutOp::ZStack));
52        for cid in wrapped_children {
53            layout_builder.add_child(cid);
54        }
55        let layout_id = layout_builder.build(cx);
56
57        let semantics = Semantics {
58            role: Role::Generic,
59            label: None,
60            identifier: None,
61            value: None,
62            actions: Default::default(),
63            action_scope_id: None,
64            focusable: false,
65            multiline: false,
66            masked: false,
67            input_mask: None,
68            ime_preedit_range: None,
69            checked: None,
70            disabled: false,
71            read_only: false,
72            autofocus: false,
73            draggable: false,
74            scrollable_x: false,
75            scrollable_y: false,
76            min_value: None,
77            max_value: None,
78            current_value: None,
79            is_focus_scope: true,
80            is_focus_barrier: self.is_barrier,
81            drag_payload: None,
82            hero_tag: None,
83            focus_index: None,
84            text_input_type: fission_ir::semantics::TextInputType::Text,
85            text_input_action: fission_ir::semantics::TextInputAction::Done,
86            text_capitalization: fission_ir::semantics::TextCapitalization::None,
87            max_length: None,
88            max_length_enforcement: fission_ir::semantics::MaxLengthEnforcement::Enforced,
89            input_formatters: Vec::new(),
90            autocorrect: true,
91            enable_suggestions: true,
92            spell_check: true,
93            smart_dashes: true,
94            smart_quotes: true,
95            autofill_hints: Vec::new(),
96            scroll_padding: None,
97            capture_tab: false,
98            auto_indent: false,
99        };
100
101        let mut node = NodeBuilder::new(id, Op::Semantics(semantics));
102        node.add_child(layout_id);
103        node.build(cx)
104    }
105}