1use std::sync::LazyLock;
20
21use crate::prelude::*;
22
23pub use self::builder::ButtonBuilder as Builder;
24
25pub type Button <'element> =
26 Widget <'element, Switch, model::Component, view::Component>;
27
28pub static CONTROLS : LazyLock <Controls> = LazyLock::new (||
33 controls::Builder::new()
34 .buttons (vec![
35 controls::button::Builtin::ButtonPush,
36 controls::button::Builtin::ButtonRelease
37 ].into_iter().map (Into::into).collect::<Vec <_>>().into())
38 .build()
39);
40
41pub fn push (
43 release : &controls::button::Release,
44 elements : &Tree <Element>,
45 frame_id : &NodeId,
46 action_buffer : &mut Vec <(NodeId, Action)>
47) {
48 log::trace!("push...");
49 let frame = elements.get_element (frame_id);
50 let mut frame_children = elements.children_ids (frame_id).unwrap();
51 let button_id = frame_children.next().unwrap();
52 let label_id = frame_children
53 .find (|node_id| Textbox::try_get (elements, node_id).is_ok());
54 let Widget (switch, _, _) = Button::try_get (elements, button_id).unwrap();
55 let toggle = switch.toggle;
56 if toggle && switch.state == switch::State::On {
57 return self::release (&None, elements, frame_id, action_buffer)
58 }
59 let mut switch = switch.clone();
60 let (exit, (enter, appearances, label)) = switch.on();
61 let update_switch = Box::new (
65 |controller : &mut Controller| controller.component = switch.into());
66 action_buffer
67 .push ((button_id.clone(), Action::ModifyController (update_switch)));
68 let appearance = Appearance {
70 sound: None, .. appearances.get (frame.controller.state.clone()).clone()
71 };
72 let update_controller = Box::new (
73 |controller : &mut Controller| controller.appearances = appearances);
74 let update_view = Box::new (
75 |view : &mut View| view.appearance = appearance);
76 action_buffer
77 .push ((frame_id.clone(), Action::ModifyController (update_controller)));
78 action_buffer
79 .push ((frame_id.clone(), Action::ModifyView (update_view)));
80 if let Some (trigger) = exit {
82 let target = trigger.target.as_ref().unwrap_or (button_id);
83 trigger.control_fun.0 (release, elements, target, action_buffer)
84 }
85 if let Some (textbox_id) = label_id {
87 action_buffer.push ((textbox_id.clone(), Action::Destroy))
88 }
89 if let Some (label) = label {
91 let textbox =
92 textbox::WithFrameBuilder::<application::Default>::new (elements, frame_id)
93 .text (label)
94 .build_element();
95 action_buffer.push ((frame_id.clone(),
96 Action::create_singleton (textbox, CreateOrder::Append)))
97 }
98 if let Some (trigger) = enter {
100 let target = trigger.target.as_ref().unwrap_or (button_id);
101 trigger.control_fun.0 (release, elements, target, action_buffer)
102 }
103 if !toggle {
104 if let Some (release) = release {
106 release.borrow_mut().push (
107 (controls::button::Builtin::ButtonRelease.into(), frame_id.clone()));
108 }
109 }
110 log::trace!("...push");
111}
112
113pub fn release (
115 _ : &controls::button::Release,
116 elements : &Tree <Element>,
117 frame_id : &NodeId,
118 action_buffer : &mut Vec <(NodeId, Action)>
119) {
120 log::trace!("release...");
121 let frame = elements.get_element (frame_id);
122 let mut frame_children = elements.children_ids (frame_id).unwrap();
123 let button_id = frame_children.next().unwrap();
124 let label_id = frame_children
125 .find (|node_id| Textbox::try_get (elements, node_id).is_ok());
126 let Widget (switch, _, _) = Button::try_get (elements, button_id).unwrap();
127 let mut switch = switch.clone();
128 let (exit, (enter, appearances, label)) = switch.off();
129 if let Some (trigger) = exit {
131 let target = trigger.target.as_ref().unwrap_or (button_id);
132 trigger.control_fun.0 (&None, elements, target, action_buffer)
133 }
134 if let Some (textbox_id) = label_id {
136 action_buffer.push ((textbox_id.clone(), Action::Destroy))
137 }
138 if let Some (label) = label {
140 let textbox =
141 textbox::WithFrameBuilder::<application::Default>::new (elements, frame_id)
142 .text (label)
143 .build_element();
144 action_buffer.push ((frame_id.clone(),
145 Action::create_singleton (textbox, CreateOrder::Append)))
146 }
147 if let Some (trigger) = enter {
149 let target = trigger.target.as_ref().unwrap_or (button_id);
150 trigger.control_fun.0 (&None, elements, target, action_buffer)
151 }
152 let update_switch = Box::new (
154 |controller : &mut Controller| controller.component = switch.into());
155 action_buffer
156 .push ((button_id.clone(), Action::ModifyController (update_switch)));
157 let appearance = Appearance {
159 sound: None,
160 .. appearances.get (frame.controller.state.clone()).clone()
161 };
162 let update_controller = Box::new (
163 |controller : &mut Controller| controller.appearances = appearances);
164 let update_view = Box::new (
165 |view : &mut View| view.appearance = appearance);
166 action_buffer
167 .push ((frame_id.clone(), Action::ModifyController (update_controller)));
168 action_buffer
169 .push ((frame_id.clone(), Action::ModifyView (update_view)));
170 log::trace!("...release");
171}
172
173mod builder {
178 use derive_builder::Builder;
179 use crate::prelude::*;
180
181 #[derive(Builder)]
182 #[builder(public, pattern="owned", build_fn(private), setter(strip_option))]
183 struct Button <'a, A : Application> {
184 elements : &'a Tree <Element>,
185 parent_id : &'a NodeId,
186 #[builder(default)]
187 bindings : Option <&'a Bindings <A>>,
188 #[builder(default)]
189 callback_id : Option <application::CallbackId>,
190 #[builder(default)]
191 controls : Option <Controls>,
192 #[builder(default)]
193 frame_layout : Layout,
194 #[builder(default)]
195 frame_border : Option <Border>,
196 #[builder(default)]
197 model_data : Option <model::Component>,
198 #[builder(default)]
199 name : Option <String>,
200 #[builder(default)]
201 switch : Switch
202 }
203
204 impl <'a, A : Application> ButtonBuilder <'a, A> {
205 pub const fn new (elements : &'a Tree <Element>, parent_id : &'a NodeId) -> Self {
206 ButtonBuilder {
207 elements: Some (elements),
208 parent_id: Some (parent_id),
209 bindings: None,
210 callback_id: None,
211 controls: None,
212 frame_border: None,
213 frame_layout: None,
214 model_data: None,
215 name: None,
216 switch: None
217 }
218 }
219 }
220
221 impl <A : Application> BuildActions for ButtonBuilder <'_, A> {
222 fn build_actions (self) -> Vec<(NodeId, Action)> {
227 use std::convert::TryInto;
228 use crate::tree::InsertBehavior;
229 log::trace!("build actions...");
230 let Button {
231 elements, parent_id, bindings, callback_id, controls, frame_border,
232 frame_layout, model_data, name, switch
233 } = self.build()
234 .map_err(|err| log::error!("button builder error: {err:?}")).unwrap();
235 let bindings_empty = Bindings::empty();
236 let bindings = bindings.unwrap_or (&bindings_empty);
237 let mut out = vec![];
238 let (mut subtree, order) = {
239 let mut actions = {
240 let mut frame = frame::Builder::new (elements, parent_id)
241 .appearances (switch.appearances().clone())
242 .bindings (bindings)
243 .layout (frame_layout);
244 set_option!(frame, border, frame_border);
245 frame.build_actions()
246 };
247 out.extend (actions.drain (1..));
248 debug_assert_eq!(actions.len(), 1);
249 actions.pop().unwrap().1.try_into().unwrap()
250 };
251 let frame_id = subtree.root_node_id().unwrap().clone();
252 subtree.get_mut (&frame_id).unwrap().data_mut().controller.add_bindings (
253 &bindings.get_bindings (controls.as_ref().unwrap_or (&super::CONTROLS))
254 );
255 let label = switch.label().clone();
256 let button = {
257 let controller = Controller {
258 component: switch.into(),
259 focus_top: false,
260 .. Controller::default()
261 };
262 let model = {
263 let component = model_data.unwrap_or_else (Default::default);
264 Model { callback_id, component }
265 };
266 let name = name.unwrap_or ("Button".to_string());
267 Element::new (name, controller, model, View::default())
268 };
269 let _ = subtree
270 .insert (Node::new (button), InsertBehavior::UnderNode (&frame_id))
271 .unwrap();
272 if let Some (label) = label {
273 let textbox = textbox::WithFrameBuilder::<A>::new (&subtree, &frame_id)
274 .text (label)
275 .build_element();
276 let _ = subtree
277 .insert (Node::new (textbox), InsertBehavior::UnderNode (&frame_id))
278 .unwrap();
279 }
280 out.push ((parent_id.clone(), Action::Create (subtree, order)));
281 log::trace!("...build actions");
282 out
283 }
284 }
285}