1use std::convert::{TryFrom, TryInto};
15use lazy_static::lazy_static;
16
17use crate::geometry;
18use crate::prelude::*;
19
20pub use self::builder::FrameBuilder as Builder;
21
22pub mod free;
23pub mod screen;
24pub mod tiled;
25
26pub type Frame <'element> = Widget <'element, Layout, model::Component, Canvas>;
27
28lazy_static!{
33 pub static ref CONTROLS : Controls = controls::Builder::new()
34 .buttons (vec![
35 controls::button::Builtin::ActivatePointer,
36 controls::button::Builtin::FrameClose,
37 controls::button::Builtin::FrameToggleOrientation
38 ].into_iter().map (Into::into).collect::<Vec <_>>().into())
39 .build();
40}
41
42pub fn close (
48 _ : &controls::button::Release,
49 elements : &Tree <Element>,
50 node_id : &NodeId,
51 action_buffer : &mut Vec <(NodeId, Action)>
52) {
53 use controller::component::layout;
54 log::trace!("close...");
55 let Widget (layout, _, _) = Frame::try_get (elements, node_id).unwrap();
56 match layout.variant {
57 layout::Variant::Tiled (_) => for (sibling_id, coordinates) in
58 tiled::destroy_coordinates (elements, node_id)
59 {
60 set_coordinates (elements, &sibling_id, &coordinates, None,
61 action_buffer);
62 }
63 layout::Variant::Free (..) => {}
64 }
65 action_buffer.push ((node_id.clone(), Action::Destroy));
66 log::trace!("...close");
67}
68
69pub fn refresh (
74 _ : &controls::button::Release,
75 elements : &Tree <Element>,
76 node_id : &NodeId,
77 action_buffer : &mut Vec <(NodeId, Action)>
78) {
79 log::trace!("refresh...");
80 let Widget (layout, _, canvas) = Frame::try_get (elements, node_id).unwrap();
81 let coordinate_kind = Some (canvas.coordinates.kind());
82 set_layout (elements, node_id, layout.clone(), coordinate_kind, action_buffer);
83 log::trace!("...refresh");
84}
85
86pub fn toggle_orientation (
91 _ : &controls::button::Release,
92 elements : &Tree <Element>,
93 node_id : &NodeId,
94 action_buffer : &mut Vec <(NodeId, Action)>
95) {
96 log::trace!("toggle_orientation...");
97 let Widget (layout, _, canvas) = Frame::try_get (elements, node_id).unwrap();
98 let (mut orientation, area) = layout.orientation.clone();
99 orientation = orientation.toggle();
100 let layout = controller::component::Layout {
101 orientation: (orientation, area),
102 .. layout.clone()
103 };
104 let coordinate_kind = Some (canvas.coordinates.kind());
105 set_layout (elements, node_id, layout, coordinate_kind, action_buffer);
106 log::trace!("...toggle_orientation");
107}
108
109pub fn activate_pointer (
118 release : &controls::button::Release,
119 elements : &Tree <Element>,
120 node_id : &NodeId,
121 action_buffer : &mut Vec <(NodeId, Action)>
122) {
123 log::trace!("activate pointer...");
124 let pointer_position = {
125 let pointer = interface::POINTER.read().unwrap();
126 [pointer.position_horizontal, pointer.position_vertical].into()
127 };
128 let mut last = None;
129 for element_id in elements.traverse_pre_order_ids (node_id).unwrap() {
130 let element = elements.get (&element_id).unwrap().data();
131 if let Ok (Widget (_, _, canvas)) = Frame::try_from (element) {
132 let canvas_aabb = {
133 let aabb = geometry::integer::Aabb2::from (canvas.coordinates);
134 let pixel_aabb =
135 if canvas.coordinates.kind() == coordinates::Kind::Tile {
136 coordinates::tile_to_pixel_aabb (aabb)
137 } else {
138 aabb
139 };
140 geometry::Aabb2::with_minmax (
141 pixel_aabb.min().numcast().unwrap(),
142 pixel_aabb.max().numcast().unwrap())
143 };
144 if canvas_aabb.contains (&pointer_position) {
145 last = Some (element_id);
146 }
147 }
148 }
149 if let Some (element_id) = last {
150 let element = elements.get (&element_id).unwrap().data();
151 if element.controller.state == State::Enabled {
152 action_buffer.push ((element_id.clone(), Action::Focus));
153 }
154 if element.controller.state != State::Disabled {
155 if let Some (child_id) =
156 elements.children_ids (&element_id).unwrap().next()
157 {
158 let child = elements.get (&child_id).unwrap().data();
159 if let Ok (Widget (switch, _, _)) = Button::try_from (child) {
160 if switch.toggle {
161 match switch.state {
162 switch::State::On =>
163 button::release (&None, elements, &element_id, action_buffer),
164 switch::State::Off =>
165 button::push (release, elements, &element_id, action_buffer)
166 }
167 } else {
168 button::push (release, elements, &element_id, action_buffer)
169 }
170 }
171 }
172 }
173 }
174 log::trace!("...activate pointer");
175}
176
177pub fn hot_pointer (
186 pointer : &input::Pointer,
187 elements : &Tree <Element>,
188 node_id : &NodeId,
189 action_buffer : &mut Vec <(NodeId, Action)>
190) {
191 log::trace!("hot pointer...");
192 debug_assert_eq!(&*interface::POINTER.read().unwrap(), pointer);
193 let pointer_position =
194 [pointer.position_horizontal, pointer.position_vertical].into();
195 let mut last = None;
196 for element_id in elements.traverse_pre_order_ids (node_id).unwrap() {
197 let element = elements.get (&element_id).unwrap().data();
198 if let Ok (Widget (_, _, canvas)) = Frame::try_from (element) {
199 let canvas_aabb = {
200 let aabb = geometry::integer::Aabb2::from (canvas.coordinates);
201 let pixel_aabb =
202 if canvas.coordinates.kind() == coordinates::Kind::Tile {
203 coordinates::tile_to_pixel_aabb (aabb)
204 } else {
205 aabb
206 };
207 geometry::Aabb2::with_minmax (
208 pixel_aabb.min().numcast().unwrap(),
209 pixel_aabb.max().numcast().unwrap())
210 };
211 if canvas_aabb.contains (&pointer_position) {
212 last = Some (element_id);
213 }
214 }
215 }
216 if let Some (element_id) = last {
217 let element = elements.get (&element_id).unwrap().data();
218 if element.controller.state == controller::State::Enabled {
219 action_buffer.push ((element_id.clone(), Action::Focus));
220 }
221 }
222 log::trace!("...hot pointer");
223}
224
225pub (crate) fn set_layout (
232 elements : &Tree <Element>,
233 frame_id : &NodeId,
234 layout : controller::component::Layout,
235 coord_kind_override : Option <view::coordinates::Kind>,
236 action_buffer : &mut Vec <(NodeId, Action)>
237) {
238 log::trace!("set_layout...");
239 { let new_layout = layout.clone();
241 let update_layout = Box::new (move |controller : &mut Controller|
242 controller.component = new_layout.into());
243 action_buffer.push (
244 (frame_id.clone(), Action::ModifyController (update_layout)));
245 }
246 for (frame_id, coordinates) in
248 new_coordinates (elements, frame_id, &layout, coord_kind_override)
249 {
250 set_coordinates (elements, &frame_id, &coordinates,
251 Some (layout.orientation.clone()), action_buffer);
252 }
253 log::trace!("...set_layout");
254}
255
256fn new_coordinates (
276 elements : &Tree <Element>,
277 frame_id : &NodeId,
278 layout : &controller::component::Layout,
279 coord_kind_override : Option <view::coordinates::Kind>
280) -> Vec <(NodeId, view::Coordinates)> {
281 use controller::size;
282 use controller::component::layout;
283 use view::coordinates::dimensions;
284 use view::component::Canvas;
285 log::trace!("new_coordinates...");
286 let out = match layout.variant {
287 layout::Variant::Free (ref free, ref area) => {
288 let parent_canvas = if elements.root_node_id().unwrap() == frame_id {
289 let Widget (_, _, canvas) = Frame::try_get (elements, frame_id).unwrap();
291 let (width, height) = {
292 let (free, _) = layout.variant.clone().try_into().unwrap();
294 let width = match free.size.width {
295 size::Unsigned::Absolute (w) => w,
296 size::Unsigned::Relative (_) => 1
297 };
298 let height = match free.size.height {
299 size::Unsigned::Absolute (h) => h,
300 size::Unsigned::Relative (_) => 1
301 };
302 (width, height)
303 };
304 let (mut parent, dimensions) =
305 if canvas.coordinates.kind() == coordinates::Kind::Tile {
306 ( Canvas::default_tile(),
307 dimensions::Tile::new_rc (height, width).into()
308 )
309 } else {
310 debug_assert!(canvas.coordinates.kind() == coordinates::Kind::Pixel);
311 ( Canvas::default_pixel(),
312 dimensions::Pixel::new_wh (width, height).into()
313 )
314 };
315 parent.coordinates.set_dimensions (dimensions);
316 parent
317 } else {
318 let Widget (_, _, parent_canvas) =
319 Frame::try_get (elements, elements.get_parent_id (frame_id)).unwrap();
320 parent_canvas.clone()
321 };
322 vec![(
323 frame_id.clone(),
324 free::coordinates (&parent_canvas, &free, &area, coord_kind_override)
325 )]
326 }
327 layout::Variant::Tiled (ref tiled) => {
328 debug_assert!(elements.root_node_id().unwrap() != frame_id,
329 "tiled root frame is unsupported");
330 tiled::new_coordinates (&elements, frame_id, &tiled)
331 }
332 };
333 log::trace!("...new_coordinates");
334 out
335}
336
337fn set_coordinates (
340 elements : &Tree <Element>,
341 frame_id : &NodeId,
342 coordinates : &view::Coordinates,
343 orientation : Option <(controller::Orientation, controller::Area)>,
344 action_buffer : &mut Vec <(NodeId, Action)>
345) {
346 log::trace!("set_coordinates...");
347 { let new_coordinates = coordinates.clone();
349 let update_canvas = Box::new (move |view : &mut View| {
350 use view::component::{Canvas, Kind};
351 let canvas = Canvas::try_ref_mut (&mut view.component).unwrap();
352 canvas.coordinates = new_coordinates;
353 });
354 action_buffer.push ((frame_id.clone(), Action::ModifyView (update_canvas)));
355 }
356 for (child_id, coordinates) in update_children (
358 elements, frame_id, coordinates, orientation, action_buffer
359 ) {
360 set_coordinates (elements, &child_id, &coordinates, None, action_buffer);
361 }
362 log::trace!("...set_coordinates");
363}
364
365fn update_children (
369 elements : &Tree <Element>,
370 frame_id : &NodeId,
371 coordinates : &view::Coordinates,
372 orientation : Option <(controller::Orientation, controller::Area)>,
373 action_buffer : &mut Vec <(NodeId, Action)>
374) -> Vec <(NodeId, view::Coordinates)> {
375 use view::component::{Body, Canvas, Image, Kind};
376 log::trace!("update_children...");
377 let mut child_coordinates = vec![];
378 let (mut tiled_ids, mut tiled_layouts) = (vec![], vec![]);
379 let node = elements.get (frame_id).unwrap();
380 let Widget (layout, _, canvas) = Frame::try_from (node.data()).unwrap();
381 let new_canvas = {
382 let coordinates = *coordinates;
383 Canvas { coordinates, .. canvas.clone() }
384 };
385 let orientation = orientation.unwrap_or (layout.orientation.clone());
386 for child_id in node.children().iter() {
387 if let Ok (Widget (layout, _, canvas)) = Frame::try_get (elements, child_id) {
388 use controller::component::layout;
390 match layout.variant {
391 layout::Variant::Free (ref free, ref area) => {
392 let coordinate_kind = Some (canvas.coordinates.kind());
393 child_coordinates.push ((
394 child_id.clone(),
395 free::coordinates (&new_canvas, &free, &area, coordinate_kind)
396 ))
397 }
398 layout::Variant::Tiled (ref tiled) => {
399 tiled_ids.push (child_id.clone());
400 tiled_layouts.push (tiled.clone());
401 }
402 }
403 } else if let Ok (Widget (scroll, text, _)) =
404 Textbox::try_get (elements, child_id)
405 {
406 let new_body = textbox::body (&new_canvas, scroll, text);
408 let update_body = Box::new (|view : &mut View|{
409 let body = Body::try_ref_mut (&mut view.component).unwrap();
410 *body = new_body;
411 });
412 action_buffer.push ((child_id.clone(), Action::ModifyView (update_body)));
413 } else if let Ok (Widget (scroll, pixmap, _)) =
414 Picture::try_get (elements, child_id)
415 {
416 let new_image = picture::image (&new_canvas, &scroll, &pixmap);
417 let update_image = Box::new (|view : &mut View|{
418 let image = Image::try_ref_mut (&mut view.component).unwrap();
419 *image = new_image;
420 });
421 action_buffer.push ((child_id.clone(), Action::ModifyView (update_image)));
422 }
423 }
424 child_coordinates.extend (
425 tiled_ids.into_iter().zip (
426 tiled::child_coordinates (&orientation, &new_canvas, tiled_layouts)));
427 log::trace!("...update_children");
428 child_coordinates
429}
430
431mod builder {
436 use derive_builder::Builder;
437 use crate::prelude::*;
438
439 #[derive(Builder)]
440 #[builder(pattern="owned", build_fn(private), setter(strip_option))]
441 pub struct Frame <'a, A : Application> {
442 elements : &'a Tree <Element>,
443 parent_id : &'a NodeId,
444 #[builder(default)]
445 appearances : controller::Appearances,
446 #[builder(default)]
447 bindings : Option <&'a controller::Bindings <A>>,
448 #[builder(default)]
449 border : Option <view::Border>,
450 #[builder(default)]
451 clear_color : canvas::ClearColor,
452 #[builder(default)]
453 disabled : bool,
454 #[builder(default)]
455 layout : controller::component::Layout
456 }
457
458 impl <'a, A : Application> FrameBuilder <'a, A> {
459 pub fn new (elements : &'a Tree <Element>, parent_id : &'a NodeId) -> Self {
460 FrameBuilder {
461 elements: Some (elements),
462 parent_id: Some (parent_id),
463 appearances: None,
464 bindings: None,
465 border: None,
466 clear_color: None,
467 disabled: None,
468 layout: None
469 }
470 }
471 }
472
473 impl <'a, A : Application> BuildActions for FrameBuilder <'a, A> {
474 fn build_actions (self) -> Vec<(NodeId, Action)> {
477 use controller::component::layout;
478 use crate::widget::{set_option, BuildElement};
479 log::trace!("build actions...");
480 let Frame {
481 elements, parent_id, appearances, bindings, border, clear_color,
482 disabled, layout
483 } = self.build()
484 .map_err(|err| log::error!("frame builder error: {:?}", err)).unwrap();
485 let out = match layout.variant {
486 layout::Variant::Free (free, area) => {
487 let frame = {
488 let mut free = super::free::Builder::new (elements, parent_id)
489 .appearances (appearances)
490 .area (area)
491 .clear_color (clear_color)
492 .disabled (disabled)
493 .layout (free)
494 .orientation (layout.orientation);
495 set_option!(free, bindings, bindings);
496 set_option!(free, border, border);
497 free.build_element()
498 };
499 vec![(
500 parent_id.clone(),
501 Action::create_singleton (frame, CreateOrder::Append)
502 )]
503 }
504 layout::Variant::Tiled (tiled) => {
505 let mut tiled =
506 super::tiled::Builder::new (elements, parent_id)
507 .appearances (appearances)
508 .clear_color (clear_color)
509 .disabled (disabled)
510 .layout (tiled)
511 .orientation (layout.orientation);
512 set_option!(tiled, bindings, bindings);
513 set_option!(tiled, border, border);
514 tiled.build_actions()
515 }
516 };
517 log::trace!("...build actions");
518 out
519 }
520 }
521}