Skip to main content

fission_core/ui/widgets/
focus_scope.rs

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