Skip to main content

fission_core/ui/widgets/
focus_scope.rs

1use crate::lowering::{LoweringContext, NodeBuilder, wrap_zstack_child};
2use crate::ui::traits::Lower;
3use crate::ui::Node;
4use fission_ir::{NodeId, Op, Semantics, semantics::Role};
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 = NodeBuilder::new(layout_id, Op::Layout(fission_ir::LayoutOp::ZStack));
51        for cid in wrapped_children {
52            layout_builder.add_child(cid);
53        }
54        let layout_id = layout_builder.build(cx);
55
56        let semantics = Semantics {
57            role: Role::Generic,
58            label: None,
59            value: None,
60            actions: Default::default(),
61            focusable: false,
62            multiline: false,
63            masked: false,
64            input_mask: None,
65            ime_preedit_range: None,
66            checked: None,
67            disabled: false,
68            draggable: false,
69            scrollable_x: false,
70            scrollable_y: false,
71            min_value: None,
72            max_value: None,
73            current_value: None,
74            is_focus_scope: true,
75            is_focus_barrier: self.is_barrier,
76            drag_payload: None,
77            hero_tag: None,
78            focus_index: None, capture_tab: false, auto_indent: false,
79        };
80
81        let mut node = NodeBuilder::new(id, Op::Semantics(semantics));
82        node.add_child(layout_id);
83        node.build(cx)
84    }
85}