gooey/widget/frame/
free.rs

1use std::convert::{TryFrom, TryInto};
2
3use lazy_static::lazy_static;
4use nsys::geometry;
5use nsys::math::Vector2;
6
7use crate::prelude::*;
8
9use super::set_layout;
10
11pub use self::builder::FreeBuilder as Builder;
12
13//
14//  controls
15//
16
17lazy_static!{
18  pub static ref CONTROLS : Controls = controls::Builder::new()
19    .buttons ({
20      let mut v : Vec <controls::Button> = vec![
21        controls::button::Builtin::FrameFreeMoveRight,
22        controls::button::Builtin::FrameFreeMoveLeft,
23        controls::button::Builtin::FrameFreeMoveUp,
24        controls::button::Builtin::FrameFreeMoveDown,
25        controls::button::Builtin::FrameFreeGrowWidth,
26        controls::button::Builtin::FrameFreeShrinkWidth,
27        controls::button::Builtin::FrameFreeGrowHeight,
28        controls::button::Builtin::FrameFreeShrinkHeight
29      ].into_iter().map (Into::into).collect();
30      v.extend (super::CONTROLS.buttons.iter().cloned());
31      v.into()
32    })
33    .build();
34}
35
36/// Builtin button control 'FrameFreeMoveRight'.
37///
38/// Frame must have free layout.
39pub fn move_right (
40  _             : &controls::button::Release,
41  elements      : &Tree <Element>,
42  node_id       : &NodeId,
43  action_buffer : &mut Vec <(NodeId, Action)>
44) {
45  log::trace!("move_right...");
46  let Widget (layout, _, canvas) = Frame::try_get (elements, node_id).unwrap();
47  let coord_kind_override = Some (canvas.coordinates.kind());
48  let layout  = {
49    use controller::component::Layout;
50    let (mut free, area) = layout.variant.clone().try_into().unwrap();
51    free.offset_move_right();
52    Layout { variant: (free, area).into(), .. layout.clone() }
53  };
54  set_layout (elements, node_id, layout, coord_kind_override, action_buffer);
55  log::trace!("...move_right");
56}
57
58/// Builtin button control 'FrameFreeMoveLeft'.
59///
60/// Frame must have free layout.
61pub fn move_left (
62  _             : &controls::button::Release,
63  elements      : &Tree <Element>,
64  node_id       : &NodeId,
65  action_buffer : &mut Vec <(NodeId, Action)>
66) {
67  log::trace!("move_left...");
68  let Widget (layout, _, canvas) = Frame::try_get (elements, node_id).unwrap();
69  let coordinate_kind = Some (canvas.coordinates.kind());
70  let layout  = {
71    use controller::component::Layout;
72    let (mut free, area) = layout.variant.clone().try_into().unwrap();
73    free.offset_move_left();
74    Layout { variant: (free, area).into(), .. layout.clone() }
75  };
76  set_layout (elements, node_id, layout, coordinate_kind, action_buffer);
77  log::trace!("...move_left");
78}
79
80/// Builtin button control 'FrameFreeMoveUp'.
81///
82/// Frame must have free layout.
83pub fn move_up (
84  _             : &controls::button::Release,
85  elements      : &Tree <Element>,
86  node_id       : &NodeId,
87  action_buffer : &mut Vec <(NodeId, Action)>
88) {
89  log::trace!("move_up...");
90  let Widget (layout, _, canvas) = Frame::try_get (elements, node_id).unwrap();
91  let coordinate_kind = Some (canvas.coordinates.kind());
92  let layout = {
93    use controller::component::Layout;
94    let (mut free, area) = layout.variant.clone().try_into().unwrap();
95    free.offset_move_up();
96    Layout { variant: (free, area).into(), .. layout.clone() }
97  };
98  set_layout (elements, node_id, layout, coordinate_kind, action_buffer);
99  log::trace!("...move_up");
100}
101
102/// Builtin button control 'FrameFreeMoveDown'.
103///
104/// Frame must have free layout.
105pub fn move_down (
106  _             : &controls::button::Release,
107  elements      : &Tree <Element>,
108  node_id       : &NodeId,
109  action_buffer : &mut Vec <(NodeId, Action)>
110) {
111  log::trace!("move_down...");
112  let Widget (layout, _, canvas) = Frame::try_get (elements, node_id).unwrap();
113  let coordinate_kind = Some (canvas.coordinates.kind());
114  let layout = {
115    use controller::component::Layout;
116    let (mut free, area) = layout.variant.clone().try_into().unwrap();
117    free.offset_move_down();
118    Layout { variant: (free, area).into(), .. layout.clone() }
119  };
120  set_layout (elements, node_id, layout, coordinate_kind, action_buffer);
121  log::trace!("...move_down");
122}
123
124/// Builtin button control 'FrameFreeGrowWidth'
125///
126/// Frame must have free layout.
127pub fn grow_width (
128  _             : &controls::button::Release,
129  elements      : &Tree <Element>,
130  node_id       : &NodeId,
131  action_buffer : &mut Vec <(NodeId, Action)>
132) {
133  log::trace!("grow_width...");
134  let Widget (layout, _, canvas) = Frame::try_get (elements, node_id).unwrap();
135  let coordinate_kind = Some (canvas.coordinates.kind());
136  let layout = {
137    use controller::component::Layout;
138    let (mut free, area) = layout.variant.clone().try_into().unwrap();
139    free.size_grow_width();
140    Layout { variant: (free, area).into(), .. layout.clone() }
141  };
142  set_layout (elements, node_id, layout, coordinate_kind, action_buffer);
143  log::trace!("...grow_width");
144}
145
146/// Builtin button control 'FrameFreeShrinkWidth'
147///
148/// Frame must have free layout with absolute size.
149pub fn shrink_width (
150  _             : &controls::button::Release,
151  elements      : &Tree <Element>,
152  node_id       : &NodeId,
153  action_buffer : &mut Vec <(NodeId, Action)>
154) {
155  log::trace!("shrink_width...");
156  let Widget (layout, _, canvas) = Frame::try_get (elements, node_id).unwrap();
157  let coordinate_kind = Some (canvas.coordinates.kind());
158  let layout = {
159    use controller::component::Layout;
160    let (mut free, area) = layout.variant.clone().try_into().unwrap();
161    free.size_shrink_width();
162    Layout { variant: (free, area).into(), .. layout.clone() }
163  };
164  set_layout (elements, node_id, layout, coordinate_kind, action_buffer);
165  log::trace!("...shrink_width");
166}
167
168/// Builtin button control 'FrameFreeGrowHeight'
169///
170/// Frame must have free layout with absolute size.
171pub fn grow_height (
172  _             : &controls::button::Release,
173  elements      : &Tree <Element>,
174  node_id       : &NodeId,
175  action_buffer : &mut Vec <(NodeId, Action)>
176) {
177  log::trace!("grow_height...");
178  let Widget (layout, _, canvas) = Frame::try_get (elements, node_id).unwrap();
179  let coordinate_kind = Some (canvas.coordinates.kind());
180  let layout = {
181    use controller::component::Layout;
182    let (mut free, area) = layout.variant.clone().try_into().unwrap();
183    free.size_grow_height();
184    Layout { variant: (free, area).into(), .. layout.clone() }
185  };
186  set_layout (elements, node_id, layout, coordinate_kind, action_buffer);
187  log::trace!("...grow_height");
188}
189
190/// Builtin button control 'FrameFreeShrinkHeight'
191///
192/// Frame must have free layout with absolute size.
193pub fn shrink_height (
194  _             : &controls::button::Release,
195  elements      : &Tree <Element>,
196  node_id       : &NodeId,
197  action_buffer : &mut Vec <(NodeId, Action)>
198) {
199  log::trace!("shrink_height...");
200  let Widget (layout, _, canvas) = Frame::try_get (elements, node_id).unwrap();
201  let coordinate_kind = Some (canvas.coordinates.kind());
202  let layout = {
203    use controller::component::Layout;
204    let (mut free, area) = layout.variant.clone().try_into().unwrap();
205    free.size_shrink_height();
206    Layout { variant: (free, area).into(), .. layout.clone() }
207  };
208  set_layout (elements, node_id, layout, coordinate_kind, action_buffer);
209  log::trace!("...shrink_height");
210}
211
212//
213//  public
214//
215
216/// Rearrange child frames with free absolute layouts
217// TODO: make this a button control ???
218pub fn rearrange_absolute (
219  elements    : &Tree <Element>,
220  parent_id   : &NodeId,
221  anchor      : controller::Alignment,
222  offset_hv   : (i32, i32),
223  orientation : controller::Orientation,
224  spacing     : u32,
225  reverse     : bool
226) -> Vec <(NodeId, Action)> {
227  use controller::{offset, size, Offset, Orientation, Size};
228  use controller::component::{layout, Layout};
229  log::trace!("rearrange_absolute...");
230  let mut out = vec![];
231  let children_ids = elements.children_ids (&parent_id).unwrap();
232  match orientation {
233    Orientation::Horizontal => {
234      let (mut horizontal, vertical) = offset_hv;
235      for child_id in children_ids {
236        if let Ok (Widget (layout, _, canvas)) =
237          Frame::try_get (elements, child_id)
238        {
239          match layout.variant {
240            layout::Variant::Free (free@layout::Free {
241              offset: Offset { horizontal: offset::Signed::Absolute (_), .. },
242              size:   Size   { width:      size::Unsigned::Absolute (_), .. },
243              ..
244            }, ref area) => {
245              let coordinate_kind = Some (canvas.coordinates.kind());
246              let layout = {
247                let offset = {
248                  let horizontal = horizontal.into();
249                  let vertical   = vertical.into();
250                  Offset { horizontal, vertical }
251                };
252                let size   = {
253                  let size = free.size.clone();
254                  let w = u32::try_from (size.width).unwrap();
255                  let next  = (w + spacing) as i32;
256                  if reverse {
257                    horizontal -= next;
258                  } else {
259                    horizontal += next;
260                  }
261                  size
262                };
263                let free = layout::Free { anchor, offset, size };
264                Layout { variant: (free, area.clone()).into(), .. layout.clone() }
265              };
266              set_layout (elements, &child_id, layout, coordinate_kind, &mut out);
267            }
268            _ => {}
269          }
270        }
271      }
272    }
273    Orientation::Vertical   => {
274      let (horizontal, mut vertical) = offset_hv;
275      for child_id in children_ids {
276        if let Ok (Widget (layout, _, canvas)) =
277          Frame::try_get (elements, child_id)
278        {
279          match layout.variant {
280            layout::Variant::Free (free@layout::Free {
281              offset: Offset { vertical: offset::Signed::Absolute (_), .. },
282              size:   Size   { height:   size::Unsigned::Absolute (_), .. },
283              ..
284            }, ref area) => {
285              let coordinate_kind = Some (canvas.coordinates.kind());
286              let layout = {
287                let offset = {
288                  let horizontal = horizontal.into();
289                  let vertical   = vertical.into();
290                  Offset { horizontal, vertical }
291                };
292                let size   = {
293                  let size = free.size.clone();
294                  let h = u32::try_from (size.height).unwrap();
295                  let next = (h + spacing) as i32;
296                  if reverse {
297                    vertical -= next;
298                  } else {
299                    vertical += next;
300                  }
301                  size
302                };
303                let free = layout::Free { anchor, offset, size };
304                Layout { variant: (free, area.clone()).into(), .. layout.clone() }
305              };
306              set_layout (elements, &child_id, layout, coordinate_kind, &mut out);
307            }
308            _ => {}
309          }
310        }
311      }
312    }
313  }
314  log::trace!("...rearrange_absolute");
315  out
316}
317
318//
319//  crate
320//
321
322/// Compute the coordinates of a frame with the given free layout and parent
323/// coordinates
324pub (crate) fn coordinates (
325  parent_canvas       : &view::component::Canvas,
326  layout              : &controller::component::layout::Free,
327  area                : &controller::Area,
328  coord_kind_override : Option <view::coordinates::Kind>
329) -> view::Coordinates {
330  log::trace!("coordinates...");
331  let controller::component::layout::Free { anchor, offset, size } = layout;
332  let parent_coordinates = match area {
333    controller::Area::Exterior => parent_canvas.coordinates,
334    controller::Area::Interior => parent_canvas.body_coordinates()
335  };
336  let dimensions = dimensions (&parent_coordinates.dimensions(), size,
337    coord_kind_override);
338  let position = position (&parent_coordinates, &dimensions, anchor, offset,
339    coord_kind_override);
340  let out = (position, dimensions).try_into().unwrap();
341  log::trace!("...coordinates");
342  out
343}
344
345//
346//  private
347//
348
349/// Compute dimensions of a free frame with the given size in relation to the
350/// given parent dimensions.
351///
352/// Returned dimensions type (tile or pixel) will match that of the given parent
353/// dimensions unless a coordinate kind override is given.
354///
355/// Enforcees a minimum dimensions of 1.
356#[inline]
357fn dimensions (
358  parent_dimensions   : &view::Dimensions,
359  size                : &controller::Size,
360  coord_kind_override : Option <view::coordinates::Kind>
361) -> view::Dimensions {
362  use controller::size;
363  use view::{coordinates, dimensions, Dimensions};
364  log::trace!("dimensions...");
365  let same_as_parent = || match parent_dimensions {
366    Dimensions::Tile  (dimensions) => {
367      let rows = match size.height {
368        size::Unsigned::Absolute (height) => height,
369        size::Unsigned::Relative (height) =>
370          std::cmp::max (1, (dimensions.rows() as f32 * *height) as u32)
371      };
372      let columns = match size.width {
373        size::Unsigned::Absolute (width) => width,
374        size::Unsigned::Relative (width) =>
375          std::cmp::max (1, (dimensions.columns() as f32 * *width)  as u32)
376      };
377      Dimensions::from (dimensions::Tile::from (Vector2::new (rows, columns)))
378    }
379    Dimensions::Pixel (dimensions) => {
380      let width = match size.width {
381        size::Unsigned::Absolute (width) => width,
382        size::Unsigned::Relative (width) =>
383          std::cmp::max (1, (dimensions.width() as f32 * *width)  as u32)
384      };
385      let height = match size.height {
386        size::Unsigned::Absolute (height) => height,
387        size::Unsigned::Relative (height) =>
388          std::cmp::max (1, (dimensions.height() as f32 * *height) as u32)
389      };
390      Dimensions::from (dimensions::Pixel::from (Vector2::new (width, height)))
391    }
392  };
393  let out = if let Some (kind) = coord_kind_override {
394    match parent_dimensions {
395      Dimensions::Tile  (_dimensions) =>
396        if kind == coordinates::Kind::Tile {
397          same_as_parent()
398        } else {
399          unimplemented!("TODO: pixel dimensions with tile dimension parent")
400        }
401      Dimensions::Pixel (dimensions) =>
402        if kind == coordinates::Kind::Pixel {
403          same_as_parent()
404        } else {
405          let [tile_width, tile_height] = *coordinates::TILE_WH;
406          let rows = match size.height {
407            size::Unsigned::Absolute (height) => height,
408            size::Unsigned::Relative (height) => {
409              let parent_rows = dimensions.height() / tile_height as u32;
410              std::cmp::max (1, (parent_rows as f32 * *height) as u32)
411            }
412          };
413          let columns = match size.width {
414            size::Unsigned::Absolute (width) => width,
415            size::Unsigned::Relative (width) => {
416              let parent_columns = dimensions.width() / tile_width as u32;
417              std::cmp::max (1, (parent_columns as f32 * *width)  as u32)
418            }
419          };
420          Dimensions::from (dimensions::Tile::from (Vector2::new (rows, columns)))
421        }
422    }
423  } else {
424    same_as_parent()
425  };
426  log::trace!("...dimensions");
427  out
428}
429
430/// Computes the position of a free frame with the given dimensions, anchor,
431/// and offset relative to the given parent coordinates.
432///
433/// Returned position type (tile or pixel) will match that of the given parent
434/// coordinates.
435fn position (
436  parent_coordinates  : &view::Coordinates,
437  dimensions          : &view::Dimensions,
438  anchor              : &controller::Alignment,
439  offset              : &controller::Offset,
440  coord_kind_override : Option <view::coordinates::Kind>
441) -> view::Position {
442  use controller::{alignment, offset};
443  use view::{coordinates, dimensions, position, Coordinates};
444  log::trace!("position...");
445  let same_as_parent = || match parent_coordinates {
446    Coordinates::Tile (parent_position, parent_dimensions) => {
447      let dimensions = dimensions::Tile::try_from (*dimensions).unwrap();
448      let row    = match offset.vertical {
449        offset::Signed::Absolute (vertical) => match anchor.vertical {
450          alignment::Vertical::Top    => vertical,
451          alignment::Vertical::Middle =>
452            parent_dimensions.rows() as i32/2 - dimensions.rows() as i32/2
453              - vertical,
454          alignment::Vertical::Bottom =>
455            parent_dimensions.rows() as i32 - dimensions.rows() as i32
456              - vertical
457        }
458        offset::Signed::Relative (vertical) => {
459          let absolute_offset = (*vertical * parent_dimensions.rows() as f32)
460            as i32;
461          match anchor.vertical {
462            alignment::Vertical::Top    => absolute_offset,
463            alignment::Vertical::Middle =>
464              parent_dimensions.rows() as i32/2 - dimensions.rows() as i32/2
465                - absolute_offset,
466            alignment::Vertical::Bottom =>
467              parent_dimensions.rows() as i32 - dimensions.rows() as i32
468                - absolute_offset
469          }
470        }
471      };
472      let column = match offset.horizontal {
473        offset::Signed::Absolute (horizontal) => match anchor.horizontal {
474          alignment::Horizontal::Left   => horizontal,
475          alignment::Horizontal::Center =>
476            parent_dimensions.columns() as i32/2 - dimensions.columns() as i32/2
477              + horizontal,
478          alignment::Horizontal::Right  =>
479            parent_dimensions.columns() as i32 - dimensions.columns() as i32
480              - horizontal
481        }
482        offset::Signed::Relative (horizontal) => {
483          let absolute_offset =
484            (*horizontal * parent_dimensions.columns() as f32) as i32;
485          match anchor.horizontal {
486            alignment::Horizontal::Left   => absolute_offset,
487            alignment::Horizontal::Center =>
488              parent_dimensions.columns() as i32/2
489                - dimensions.columns() as i32/2 + absolute_offset,
490            alignment::Horizontal::Right  =>
491              parent_dimensions.columns() as i32 - dimensions.columns() as i32
492                - absolute_offset
493          }
494        }
495      };
496      position::Tile::from (
497        parent_position.position_rc + Vector2::new (row, column)
498      ).into()
499    }
500    Coordinates::Pixel (parent_position, parent_dimensions) => {
501      let dimensions = dimensions::Pixel::try_from (*dimensions).unwrap();
502      let y = match offset.vertical {
503        offset::Signed::Absolute (vertical) => match anchor.vertical {
504          alignment::Vertical::Bottom => vertical,
505          alignment::Vertical::Middle =>
506            parent_dimensions.height() as i32/2 - dimensions.height() as i32/2
507              + vertical,
508          alignment::Vertical::Top    =>
509            parent_dimensions.height() as i32 - dimensions.height() as i32
510              - vertical
511        }
512        offset::Signed::Relative (vertical) => {
513          let absolute_offset =
514            (*vertical * parent_dimensions.height() as f32) as i32;
515          match anchor.vertical {
516            alignment::Vertical::Bottom    =>
517              absolute_offset,
518            alignment::Vertical::Middle =>
519              parent_dimensions.height() as i32/2
520                - dimensions.height() as i32/2 + absolute_offset,
521            alignment::Vertical::Top =>
522              parent_dimensions.height() as i32 - dimensions.height() as i32
523                - absolute_offset
524          }
525        }
526      };
527      let x = match offset.horizontal {
528        offset::Signed::Absolute (horizontal) => match anchor.horizontal {
529          alignment::Horizontal::Left   => horizontal,
530          alignment::Horizontal::Center =>
531            parent_dimensions.width() as i32/2
532              - dimensions.width() as i32/2 + horizontal,
533          alignment::Horizontal::Right  =>
534            parent_dimensions.width() as i32 - dimensions.width() as i32
535              - horizontal
536        }
537        offset::Signed::Relative (horizontal) => {
538          let absolute_offset = (*horizontal * parent_dimensions.width() as f32)
539            as i32;
540          match anchor.horizontal {
541            alignment::Horizontal::Left   => absolute_offset,
542            alignment::Horizontal::Center =>
543              parent_dimensions.width() as i32/2
544                - dimensions.width() as i32/2 + absolute_offset,
545            alignment::Horizontal::Right  =>
546              parent_dimensions.width() as i32 - dimensions.width() as i32
547                - absolute_offset
548          }
549        }
550      };
551      position::Pixel::from (parent_position.position_xy + Vector2::new (x, y))
552        .into()
553    }
554  };
555  let out = if let Some (kind) = coord_kind_override {
556    match parent_coordinates.kind() {
557      coordinates::Kind::Tile  => if kind == coordinates::Kind::Tile {
558        same_as_parent()
559      } else {
560        unimplemented!("TODO: pixel position with tile position parent")
561      }
562      coordinates::Kind::Pixel => if kind == coordinates::Kind::Pixel {
563        same_as_parent()
564      } else {
565        // create a tile child attached to a pixel parent
566        let parent_aabb    = geometry::integer::Aabb2::from (
567          parent_coordinates.clone());
568        let parent_aabb_tiles = coordinates::pixel_to_tile_aabb (parent_aabb);
569        let [parent_row, parent_column] = parent_aabb_tiles.min().0
570          .into_array();
571        let parent_columns = parent_aabb_tiles.width();
572        let parent_rows    = parent_aabb_tiles.height();
573        let dimensions     = dimensions::Tile::try_from (*dimensions).unwrap();
574        let row            = match offset.vertical {
575          offset::Signed::Absolute (vertical) => match anchor.vertical {
576            alignment::Vertical::Top    => vertical,
577            alignment::Vertical::Middle =>
578              parent_rows as i32/2 - dimensions.rows() as i32/2
579                - vertical,
580            alignment::Vertical::Bottom =>
581              parent_rows as i32 - dimensions.rows() as i32
582                - vertical
583          }
584          offset::Signed::Relative (vertical) => {
585            let absolute_offset = (*vertical * parent_rows as f32)
586              as i32;
587            match anchor.vertical {
588              alignment::Vertical::Top    => absolute_offset,
589              alignment::Vertical::Middle =>
590                parent_rows as i32/2 - dimensions.rows() as i32/2
591                  - absolute_offset,
592              alignment::Vertical::Bottom =>
593                parent_rows as i32 - dimensions.rows() as i32
594                  - absolute_offset
595            }
596          }
597        };
598        let column     = match offset.horizontal {
599          offset::Signed::Absolute (horizontal) => match anchor.horizontal {
600            alignment::Horizontal::Left   => horizontal,
601            alignment::Horizontal::Center =>
602              parent_columns as i32/2 - dimensions.columns() as i32/2
603                + horizontal,
604            alignment::Horizontal::Right  =>
605              parent_columns as i32 - dimensions.columns() as i32 - horizontal
606          }
607          offset::Signed::Relative (horizontal) => {
608            let absolute_offset =
609              (*horizontal * parent_columns as f32) as i32;
610            match anchor.horizontal {
611              alignment::Horizontal::Left   => absolute_offset,
612              alignment::Horizontal::Center =>
613                parent_columns as i32/2
614                  - dimensions.columns() as i32/2 + absolute_offset,
615              alignment::Horizontal::Right  =>
616                parent_columns as i32 - dimensions.columns() as i32
617                  - absolute_offset
618            }
619          }
620        };
621        position::Tile::new_rc (parent_row + row, parent_column + column)
622          .into()
623      }
624    }
625  } else {
626    same_as_parent()
627  };
628  log::trace!("...position");
629  out
630}
631
632//
633//  builder
634//
635
636mod builder {
637  use derive_builder::Builder;
638  use crate::prelude::*;
639
640  #[derive(Builder)]
641  #[builder(pattern="owned", build_fn(private), setter(strip_option))]
642  pub struct Free <'a, A : Application> {
643    elements            : &'a Tree <Element>,
644    parent_id           : &'a NodeId,
645    #[builder(default)]
646    appearances         : controller::Appearances,
647    #[builder(default)]
648    area                : controller::Area,
649    #[builder(default)]
650    bindings            : Option <&'a controller::Bindings <A>>,
651    #[builder(default)]
652    border              : Option <view::Border>,
653    #[builder(default)]
654    clear_color         : canvas::ClearColor,
655    #[builder(default)]
656    coord_kind_override : Option <view::coordinates::Kind>,
657    #[builder(default)]
658    disabled            : bool,
659    #[builder(default)]
660    layout              : controller::component::layout::Free,
661    #[builder(default)]
662    orientation         : (controller::Orientation, controller::Area)
663  }
664
665  impl <'a, A : Application> FreeBuilder <'a, A> {
666    pub fn new (elements : &'a Tree <Element>, parent_id : &'a NodeId) -> Self {
667      FreeBuilder {
668        elements:            Some (elements),
669        parent_id:           Some (parent_id),
670        appearances:         None,
671        area:                None,
672        bindings:            None,
673        border:              None,
674        clear_color:         None,
675        coord_kind_override: None,
676        disabled:            None,
677        layout:              None,
678        orientation:         None
679      }
680    }
681  }
682
683  impl <'a, A : Application> BuildElement for FreeBuilder <'a, A> {
684    /// Create a frame element with the given parent frame, free layout and
685    /// optional color.
686    ///
687    /// Controls for free frames will be taken from the given bindings.
688    ///
689    /// If not given an explicit coordinate kind, canvas coordinates type will
690    /// match that of the given parent dimensions (tile or pixel).
691    fn build_element (self) -> Element {
692      log::trace!("build element...");
693      let Free {
694        elements, parent_id, appearances, area, bindings, border, clear_color,
695        coord_kind_override, layout, orientation, disabled
696      } = self.build()
697        .map_err(|err| log::error!("frame free builder error: {:?}", err))
698        .unwrap();
699      let bindings_empty = Bindings::empty();
700      let bindings       = bindings.unwrap_or(&bindings_empty)
701        .get_bindings (&super::CONTROLS);
702      let Widget (_, _, parent_canvas) = Frame::try_get (elements, parent_id)
703        .unwrap();
704      let parent_node   = elements.get (parent_id).unwrap();
705      let mut focus_top = true;
706      if let Some (first_child_id) = parent_node.children().first() {
707        if Menu::try_get (elements, first_child_id).is_ok() {
708          focus_top = false;
709        }
710      }
711      let controller = {
712        let mut controller      = Controller::with_bindings (&bindings);
713        controller.component    = Layout {
714          orientation, variant: (layout.clone(), area.clone()).into(),
715        }.into();
716        controller.focus_top    = focus_top;
717        controller.appearances  = appearances;
718        controller
719      };
720      let view = {
721        let coordinates = super::coordinates (
722          &parent_canvas, &layout, &area, coord_kind_override);
723        let appearance  = controller.get_appearance().clone();
724        let component   = Canvas { coordinates, clear_color, border }.into();
725        View { component, appearance, .. View::default() }
726      };
727      let mut frame =
728        Element::new ("Frame".to_string(), controller, Model::default(), view);
729      if parent_node.data().controller.state == State::Disabled || disabled {
730        frame.disable()
731      }
732      log::trace!("...build element");
733      frame
734    }
735  }
736}