1use std::sync::LazyLock;
20
21use crate::prelude::*;
22
23pub use self::builder::ButtonBuilder as Builder;
24
25pub type Button <'element> = Widget <'element,
26 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 (
93 elements, frame_id
94 ) .text (label)
95 .build_element();
96 action_buffer.push ((frame_id.clone(),
97 Action::create_singleton (textbox, CreateOrder::Append)))
98 }
99 if let Some (trigger) = enter {
101 let target = trigger.target.as_ref().unwrap_or (button_id);
102 trigger.control_fun.0 (release, elements, target, action_buffer)
103 }
104 if !toggle {
105 if let Some (release) = release {
107 release.borrow_mut().push (
108 (controls::button::Builtin::ButtonRelease.into(), frame_id.clone()));
109 }
110 }
111 log::trace!("...push");
112}
113
114pub fn release (
116 _ : &controls::button::Release,
117 elements : &Tree <Element>,
118 frame_id : &NodeId,
119 action_buffer : &mut Vec <(NodeId, Action)>
120) {
121 log::trace!("release...");
122 let frame = elements.get_element (frame_id);
123 let mut frame_children = elements.children_ids (frame_id).unwrap();
124 let button_id = frame_children.next().unwrap();
125 let label_id = frame_children
126 .find (|node_id| Textbox::try_get (elements, node_id).is_ok());
127 let Widget (switch, _, _) = Button::try_get (elements, button_id).unwrap();
128 let mut switch = switch.clone();
129 let (exit, (enter, appearances, label)) = switch.off();
130 if let Some (trigger) = exit {
132 let target = trigger.target.as_ref().unwrap_or (button_id);
133 trigger.control_fun.0 (&None, elements, target, action_buffer)
134 }
135 if let Some (textbox_id) = label_id {
137 action_buffer.push ((textbox_id.clone(), Action::Destroy))
138 }
139 if let Some (label) = label {
141 let textbox =
142 textbox::WithFrameBuilder::<application::Default>::new (
143 elements, frame_id
144 ) .text (label)
145 .build_element();
146 action_buffer.push ((frame_id.clone(),
147 Action::create_singleton (textbox, CreateOrder::Append)))
148 }
149 if let Some (trigger) = enter {
151 let target = trigger.target.as_ref().unwrap_or (button_id);
152 trigger.control_fun.0 (&None, elements, target, action_buffer)
153 }
154 let update_switch = Box::new (
156 |controller : &mut Controller| controller.component = switch.into());
157 action_buffer
158 .push ((button_id.clone(), Action::ModifyController (update_switch)));
159 let appearance = Appearance {
161 sound: None,
162 .. appearances.get (frame.controller.state.clone()).clone()
163 };
164 let update_controller = Box::new (
165 |controller : &mut Controller| controller.appearances = appearances);
166 let update_view = Box::new (
167 |view : &mut View| view.appearance = appearance);
168 action_buffer
169 .push ((frame_id.clone(), Action::ModifyController (update_controller)));
170 action_buffer
171 .push ((frame_id.clone(), Action::ModifyView (update_view)));
172 log::trace!("...release");
173}
174
175mod builder {
180 use derive_builder::Builder;
181 use crate::prelude::*;
182
183 #[derive(Builder)]
184 #[builder(public, pattern="owned", build_fn(private), setter(strip_option))]
185 struct Button <'a, A : Application> {
186 elements : &'a Tree <Element>,
187 parent_id : &'a NodeId,
188 #[builder(default)]
189 bindings : Option <&'a Bindings <A>>,
190 #[builder(default)]
191 callback_id : Option <application::CallbackId>,
192 #[builder(default)]
193 controls : Option <Controls>,
194 #[builder(default)]
195 frame_layout : Layout,
196 #[builder(default)]
197 frame_border : Option <Border>,
198 #[builder(default)]
199 model_data : Option <model::Component>,
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 switch: None
216 }
217 }
218 }
219
220 impl <A : Application> BuildActions for ButtonBuilder <'_, A> {
221 fn build_actions (self) -> Vec<(NodeId, Action)> {
226 use std::convert::TryInto;
227 use crate::tree::InsertBehavior;
228 log::trace!("build actions...");
229 let Button {
230 elements, parent_id, bindings, callback_id, controls, frame_border,
231 frame_layout, model_data, switch
232 } = self.build()
233 .map_err(|err| log::error!("button builder error: {err:?}")).unwrap();
234 let bindings_empty = Bindings::empty();
235 let bindings = bindings.unwrap_or (&bindings_empty);
236 let mut out = vec![];
237 let (mut subtree, order) = {
238 let mut actions = {
239 let mut frame = frame::Builder::new (elements, parent_id)
240 .appearances (switch.appearances().clone())
241 .bindings (bindings)
242 .layout (frame_layout);
243 set_option!(frame, border, frame_border);
244 frame.build_actions()
245 };
246 out.extend (actions.drain (1..));
247 debug_assert_eq!(actions.len(), 1);
248 actions.pop().unwrap().1.try_into().unwrap()
249 };
250 let frame_id = subtree.root_node_id().unwrap().clone();
251 subtree.get_mut (&frame_id).unwrap().data_mut().controller.add_bindings (
252 &bindings.get_bindings (controls.as_ref().unwrap_or (&super::CONTROLS))
253 );
254 let label = switch.label().clone();
255 let button = {
256 let controller = {
257 let mut controller = Controller::default();
258 controller.component = switch.into();
259 controller.focus_top = false;
260 controller
261 };
262 let model = {
263 let component = model_data.unwrap_or_else (Default::default);
264 Model { callback_id, component }
265 };
266 Element::new ("Button".to_string(), controller, model, View::default())
267 };
268 let _ = subtree
269 .insert (Node::new (button), InsertBehavior::UnderNode (&frame_id))
270 .unwrap();
271 if let Some (label) = label {
272 let textbox = textbox::WithFrameBuilder::<A>::new (
273 &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}