1use lazy_static::lazy_static;
14
15use crate::TreeHelper;
16use crate::interface::{view, Action, Element, Model, View};
17use crate::interface::controller::{self, controls, Controls};
18use crate::tree::{Tree, NodeId};
19
20use super::{Widget, Frame};
21
22pub use self::builder::NumboxBuilder as Builder;
23
24pub type Numbox <'element> = Widget <'element,
25 controller::component::Numeral, f64, view::component::Body>;
26
27lazy_static!{
32 pub static ref CONTROLS : Controls = controls::Builder::new()
33 .buttons (vec![
34 controls::button::Builtin::NumboxIncrease,
35 controls::button::Builtin::NumboxDecrease,
36 controls::button::Builtin::NumboxIncrease10x,
37 controls::button::Builtin::NumboxDecrease10x
38 ].into_iter().map (Into::into).collect::<Vec <_>>().into())
39 .build();
40}
41
42pub fn decrease (
44 _ : &controls::button::Release,
45 elements : &Tree <Element>,
46 node_id : &NodeId,
47 action_buffer : &mut Vec <(NodeId, Action)>
48) {
49 log::trace!("decrease...");
50 let Widget (numeral, value, _) = Numbox::try_get (elements, node_id).unwrap();
51 let Widget (_, _, canvas) =
52 Frame::try_get (elements, elements.get_parent_id (node_id)).unwrap();
53 let new_value = numeral.modify (*value, -1.0);
54 let new_body = body (canvas, &numeral, new_value);
55 { let update_value =
57 Box::new (move |model : &mut Model| model.component = new_value.into());
58 action_buffer.push ((node_id.clone(), Action::ModifyModel (update_value)));
59 }
60 { let update_body =
62 Box::new (|view : &mut View| view.component = new_body.into());
63 action_buffer.push ((node_id.clone(), Action::ModifyView (update_body)));
64 }
65 log::trace!("...decrease");
66}
67
68pub fn increase (
70 _ : &controls::button::Release,
71 elements : &Tree <Element>,
72 node_id : &NodeId,
73 action_buffer : &mut Vec <(NodeId, Action)>
74) {
75 log::trace!("increase...");
76 let Widget (numeral, value, _) = Numbox::try_get (elements, node_id).unwrap();
77 let Widget (_, _, canvas) =
78 Frame::try_get (elements, elements.get_parent_id (node_id)).unwrap();
79 let new_value = numeral.modify (*value, 1.0);
80 let new_body = body (canvas, &numeral, new_value);
81 { let update_value =
83 Box::new (move |model : &mut Model| model.component = new_value.into());
84 action_buffer.push ((node_id.clone(), Action::ModifyModel (update_value)));
85 }
86 { let update_body =
88 Box::new (|view : &mut View| view.component = new_body.into());
89 action_buffer.push ((node_id.clone(), Action::ModifyView (update_body)));
90 }
91 log::trace!("...increase");
92}
93
94pub fn decrease_10x (
96 _ : &controls::button::Release,
97 elements : &Tree <Element>,
98 node_id : &NodeId,
99 action_buffer : &mut Vec <(NodeId, Action)>
100) {
101 log::trace!("decrease_10x...");
102 let Widget (numeral, value, _) = Numbox::try_get (elements, node_id).unwrap();
103 let Widget (_, _, canvas) =
104 Frame::try_get (elements, elements.get_parent_id (node_id)).unwrap();
105 let new_value = numeral.modify (*value, -10.0);
106 let new_body = body (canvas, &numeral, new_value);
107 { let update_value =
109 Box::new (move |model : &mut Model| model.component = new_value.into());
110 action_buffer.push ((node_id.clone(), Action::ModifyModel (update_value)));
111 }
112 { let update_body =
114 Box::new (|view : &mut View| view.component = new_body.into());
115 action_buffer.push ((node_id.clone(), Action::ModifyView (update_body)));
116 }
117 log::trace!("...decrease_10x");
118}
119
120pub fn increase_10x (
122 _ : &controls::button::Release,
123 elements : &Tree <Element>,
124 node_id : &NodeId,
125 action_buffer : &mut Vec <(NodeId, Action)>
126) {
127 log::trace!("increase_10x...");
128 let Widget (numeral, value, _) = Numbox::try_get (elements, node_id).unwrap();
129 let Widget (_, _, canvas) =
130 Frame::try_get (elements, elements.get_parent_id (node_id)).unwrap();
131 let new_value = numeral.modify (*value, 10.0);
132 let new_body = body (canvas, &numeral, new_value);
133 { let update_value =
135 Box::new (move |model : &mut Model| model.component = new_value.into());
136 action_buffer.push ((node_id.clone(), Action::ModifyModel (update_value)));
137 }
138 { let update_body =
140 Box::new (|view : &mut View| view.component = new_body.into());
141 action_buffer.push ((node_id.clone(), Action::ModifyView (update_body)));
142 }
143 log::trace!("...increase_10x");
144}
145
146pub fn set_value (
152 elements : &Tree <Element>,
153 numbox_id : &NodeId,
154 value : f64,
155 action_buffer : &mut Vec <(NodeId, Action)>
156) {
157 let Widget (numeral, _, _) = Numbox::try_get (elements, numbox_id).unwrap();
158 let Widget (_, _, canvas) =
159 Frame::try_get (elements, elements.get_parent_id (numbox_id)).unwrap();
160 let new_body = body (canvas, &numeral, value);
161 { let update_value =
163 Box::new (move |model : &mut Model| model.component = value.into());
164 action_buffer.push ((numbox_id.clone(), Action::ModifyModel (update_value)));
165 }
166 { let update_body =
168 Box::new (|view : &mut View| view.component = new_body.into());
169 action_buffer.push ((numbox_id.clone(), Action::ModifyView (update_body)));
170 }
171}
172
173pub (crate) fn body (
178 canvas : &view::component::Canvas,
179 numeral : &controller::component::Numeral,
180 value : f64
181) -> view::component::Body {
182 use controller::alignment::Horizontal;
183 log::trace!("body...");
184 let body = {
185 let body_width = canvas.body_wh().0 as usize;
186 let mut string = numeral.format.format_number (value);
187 let digits = match numeral.alignment {
188 Horizontal::Left => {
189 string.truncate (body_width);
190 string
191 }
192 Horizontal::Right =>
193 string.split_off (string.len().saturating_sub (body_width)),
194 Horizontal::Center => if string.len() > body_width {
195 let extra = string.len() - body_width;
196 string.truncate (string.len() - extra / 2);
197 let remaining = extra - extra / 2;
198 string.split_off (remaining)
199 } else {
200 string
201 }
202 };
203 debug_assert!(digits.len() <= body_width);
204 match numeral.alignment {
205 Horizontal::Left => view::component::Body (format!("{}", digits)),
206 Horizontal::Right =>
207 view::component::Body (format!("{:>1$}", digits, body_width)),
208 Horizontal::Center =>
209 view::component::Body (format!("{:>1$}", digits,
210 body_width - (body_width - digits.len() / 2)))
211 }
212 };
213 log::trace!("...body");
214 body
215}
216
217fn canvas_size (frame_border : Option <&view::Border>, length : u32)
222 -> controller::Size
223{
224 let (border_w, border_h) = frame_border.map (view::Border::total_wh)
225 .unwrap_or ((0,0));
226 let width = (border_w as u32 + length).into();
227 let height = (border_h as u32 + 1).into();
228 controller::Size { width, height }
229}
230
231mod builder {
236 use derive_builder::Builder;
237 use crate::prelude::*;
238 use super::canvas_size;
239
240 #[derive(Builder)]
241 #[builder(pattern="owned", build_fn(private), setter(strip_option))]
242 pub struct Numbox <'a, A : Application> {
243 elements : &'a Tree <Element>,
244 parent_id : &'a NodeId,
245 #[builder(default)]
246 appearances : controller::Appearances,
247 #[builder(default)]
248 bindings : Option <&'a controller::Bindings <A>>,
249 #[builder(default)]
250 frame_anchor : controller::Alignment,
251 #[builder(default)]
252 frame_appearances : controller::Appearances,
253 #[builder(default)]
254 frame_area : controller::Area,
255 #[builder(default)]
256 frame_bindings : Option <&'a controller::Bindings <A>>,
257 #[builder(default)]
258 frame_border : Option <view::Border>,
259 #[builder(default)]
260 frame_clear_color : Option <canvas::ClearColor>,
261 #[builder(default)]
262 frame_offset : controller::Offset,
263 #[builder(default = "12")]
264 length : u32,
265 #[builder(default)]
266 numeral : controller::component::Numeral,
267 #[builder(default)]
268 value : Option <f64>
269 }
270
271 impl <'a, A : Application> NumboxBuilder <'a, A> {
272 pub fn new (elements : &'a Tree <Element>, parent_id : &'a NodeId) -> Self {
273 NumboxBuilder {
274 elements: Some (elements),
275 parent_id: Some (parent_id),
276 appearances: None,
277 bindings: None,
278 frame_anchor: None,
279 frame_appearances: None,
280 frame_area: None,
281 frame_bindings: None,
282 frame_border: None,
283 frame_clear_color: None,
284 frame_offset: None,
285 length: None,
286 numeral: None,
287 value: None
288 }
289 }
290 }
291
292 impl <'a, A : Application> BuildActions for NumboxBuilder <'a, A> {
293 fn build_actions (self) -> Vec<(NodeId, Action)> {
294 use std::convert::TryInto;
295 use crate::tree::{InsertBehavior, Node};
296 use controller::component::layout;
297 log::trace!("build actions...");
298 let Numbox {
299 elements, parent_id, appearances, bindings, frame_anchor,
300 frame_appearances, frame_area, frame_bindings, frame_border,
301 frame_clear_color, frame_offset, length, numeral, value
302 } = self.build()
303 .map_err(|err| log::error!("frame builder error: {:?}", err))
304 .unwrap();
305 let bindings_empty = Bindings::empty();
306 let bindings = bindings.unwrap_or (&bindings_empty)
307 .get_bindings (&super::CONTROLS);
308 let frame_bindings = frame_bindings.unwrap_or (&bindings_empty);
309 if length == 0 {
310 log::warn!("zero length number box field");
311 }
312 { let Widget (_, _, canvas) = Frame::try_get (elements, parent_id)
314 .unwrap();
315 assert!(canvas.coordinates.kind() == coordinates::Kind::Tile);
316 }
317 let value = value.unwrap_or (0.0);
318 let mut out = vec![];
319 let (mut subtree, order) = {
320 let layout = {
321 let anchor = frame_anchor;
322 let offset = frame_offset;
323 let size = canvas_size (frame_border.as_ref(), length);
324 layout::Variant::from (
325 (layout::Free { anchor, offset, size }, frame_area)
326 )
327 };
328 let mut actions = {
329 let mut frame = frame::Builder::new (elements, parent_id)
330 .appearances (frame_appearances)
331 .bindings (frame_bindings)
332 .layout (layout.into());
333 set_option!(frame, border, frame_border);
334 set_option!(frame, clear_color, frame_clear_color);
335 frame.build_actions()
336 };
337 out.extend (actions.drain (1..));
338 debug_assert_eq!(actions.len(), 1);
339 actions.pop().unwrap().1.try_into().unwrap()
340 };
341 let frame_id = subtree.root_node_id().unwrap().clone();
342 let numbox = {
343 let controller = {
344 let component = numeral.clone().into();
345 let mut controller = Controller::with_bindings (&bindings);
346 controller.component = component;
347 controller.appearances = appearances;
348 controller
349 };
350 let model = Model { component: value.into(), .. Model::default() };
351 let view = {
352 let Widget (_, _, canvas) =
353 Frame::try_get (&subtree, &frame_id).unwrap();
354 view::Component::from (super::body (canvas, &numeral, value)).into()
355 };
356 Element::new ("Numbox".to_string(), controller, model, view)
357 };
358 let _ = subtree
359 .insert (Node::new (numbox), InsertBehavior::UnderNode (&frame_id))
360 .unwrap();
361 out.push ((parent_id.clone(), Action::Create (subtree, order)));
362 log::trace!("...build actions");
363 out
364 }
365 }
366}