1use super::Button;
2use crate::event;
3use crate::ffi::{FlexDirection, KeyEventType, SemanticRole};
4use crate::node::{flex_box, FlexBox, Node, NodeRef, ThemeBindable};
5use std::any::Any;
6use std::cell::{Cell, RefCell};
7use std::rc::Rc;
8
9#[derive(Clone)]
10pub struct Form {
11 shared: Rc<FormShared>,
12}
13
14struct FormShared {
15 root: FlexBox,
16 default_button: RefCell<Option<Button>>,
17 cancel_button: RefCell<Option<Button>>,
18 key_filter_token: Cell<u32>,
19 armed_key: RefCell<Option<String>>,
20 armed_button: RefCell<Option<Button>>,
21}
22
23impl Default for Form {
24 fn default() -> Self {
25 Self::new()
26 }
27}
28
29impl Form {
30 pub fn new() -> Self {
31 let root = flex_box();
32 root.flex_direction(FlexDirection::Column)
33 .semantic_role(SemanticRole::Form);
34 let form = Self {
35 shared: Rc::new(FormShared {
36 root,
37 default_button: RefCell::new(None),
38 cancel_button: RefCell::new(None),
39 key_filter_token: Cell::new(0),
40 armed_key: RefCell::new(None),
41 armed_button: RefCell::new(None),
42 }),
43 };
44 form.bind_events();
45 form
46 }
47
48 pub fn default_btn(&self, button: &Button) -> &Self {
49 self.shared
50 .default_button
51 .borrow_mut()
52 .replace(button.clone());
53 self
54 }
55
56 pub fn cancel_btn(&self, button: &Button) -> &Self {
57 self.shared
58 .cancel_button
59 .borrow_mut()
60 .replace(button.clone());
61 self
62 }
63
64 pub fn activate(&self) {
65 if self.shared.key_filter_token.get() != 0
66 || (self.shared.default_button.borrow().is_none()
67 && self.shared.cancel_button.borrow().is_none())
68 {
69 return;
70 }
71 let weak = Rc::downgrade(&self.shared);
72 let token = event::push_key_filter(move |event_type, key, modifiers| {
73 let Some(shared) = weak.upgrade() else {
74 return false;
75 };
76 shared.handle_global_key_event(event_type, key, modifiers)
77 });
78 self.shared.key_filter_token.set(token);
79 }
80
81 pub fn deactivate(&self) {
82 self.shared.deactivate();
83 }
84
85 fn bind_events(&self) {
86 let weak = Rc::downgrade(&self.shared);
87 self.shared.root.on_key_down(move |event| {
88 let Some(shared) = weak.upgrade() else {
89 return;
90 };
91 if shared.handle_global_key_event(
92 KeyEventType::Down,
93 event.key.as_str(),
94 event.modifiers,
95 ) {
96 event.handled = true;
97 }
98 });
99 let weak = Rc::downgrade(&self.shared);
100 self.shared.root.on_key_up(move |event| {
101 let Some(shared) = weak.upgrade() else {
102 return;
103 };
104 if shared.handle_global_key_event(KeyEventType::Up, event.key.as_str(), event.modifiers)
105 {
106 event.handled = true;
107 }
108 });
109 }
110}
111
112impl Drop for Form {
113 fn drop(&mut self) {
114 if Rc::strong_count(&self.shared) == 1 {
115 self.shared.deactivate();
116 }
117 }
118}
119
120impl FormShared {
121 fn deactivate(&self) {
122 self.cancel_armed_button();
123 let token = self.key_filter_token.replace(0);
124 if token != 0 {
125 event::remove_key_filter(token);
126 }
127 }
128
129 fn handle_global_key_event(&self, event_type: KeyEventType, key: &str, modifiers: u32) -> bool {
130 if key == "Enter" && self.should_defer_enter_to_focused_button(modifiers) {
131 return false;
132 }
133 match event_type {
134 KeyEventType::Down => self.handle_key_down(key),
135 KeyEventType::Up => self.handle_key_up(key),
136 }
137 }
138
139 fn handle_key_down(&self, key: &str) -> bool {
140 let Some(button) = self.resolve_button_for_key(key) else {
141 return false;
142 };
143 if let Some(armed_key) = self.armed_key.borrow().as_ref() {
144 return armed_key == key;
145 }
146 self.armed_key.borrow_mut().replace(key.to_string());
147 self.armed_button.borrow_mut().replace(button.clone());
148 button.begin_press();
149 true
150 }
151
152 fn handle_key_up(&self, key: &str) -> bool {
153 let armed_matches = self
154 .armed_key
155 .borrow()
156 .as_ref()
157 .is_some_and(|armed_key| armed_key == key);
158 if !armed_matches {
159 return false;
160 }
161 let button = self.armed_button.borrow_mut().take();
162 self.armed_key.borrow_mut().take();
163 if let Some(button) = button {
164 button.end_press(true);
165 }
166 true
167 }
168
169 fn cancel_armed_button(&self) {
170 let button = self.armed_button.borrow_mut().take();
171 self.armed_key.borrow_mut().take();
172 if let Some(button) = button {
173 button.cancel_press();
174 }
175 }
176
177 fn resolve_button_for_key(&self, key: &str) -> Option<Button> {
178 match key {
179 "Enter" => self.default_button.borrow().clone(),
180 "Escape" => self.cancel_button.borrow().clone(),
181 _ => None,
182 }
183 }
184
185 fn should_defer_enter_to_focused_button(&self, modifiers: u32) -> bool {
186 if modifiers != 0 {
187 return false;
188 }
189 event::focused_node_is_enabled_button()
190 }
191}
192
193impl Node for Form {
194 fn retained_node_ref(&self) -> NodeRef {
195 self.shared.root.retained_node_ref()
196 }
197
198 fn retained_owner_attachment(&self) -> Option<Rc<dyn Any>> {
199 Some(self.shared.clone())
200 }
201
202 fn build_self(&self) {
203 self.shared.root.build_self();
204 }
205
206 fn dispose(&self) {
207 self.deactivate();
208 self.shared.root.dispose();
209 }
210}
211
212impl crate::node::HasFlexBoxRoot for Form {
213 fn flex_box_root(&self) -> &FlexBox {
214 &self.shared.root
215 }
216}
217
218impl ThemeBindable for Form {
219 fn theme_binding_node(&self) -> NodeRef {
220 self.shared.root.retained_node_ref()
221 }
222
223 fn weak_theme_target(&self) -> Box<dyn Fn() -> Option<Self>> {
224 let shared = Rc::downgrade(&self.shared);
225 Box::new(move || {
226 Some(Self {
227 shared: shared.upgrade()?,
228 })
229 })
230 }
231}