1use lazy_static::lazy_static;
14
15use crate::{Application, Presentation, TreeHelper};
16use crate::tree::{Tree, NodeId};
17use crate::interface::{
18 model, view, Action, Controller, Element, Interface, Model, View
19};
20use crate::interface::controller::{self, controls, Controls};
21use super::{Widget, Frame, build_and_get_node_ids, frame, set_option};
22
23mod make_table;
24
25pub use self::builder::{TextboxBuilder as Builder, FitBuilder, WithFrameBuilder};
26pub use self::make_table::{box_vec, make_table, mk_table};
27
28pub type Textbox <'element> = Widget <'element,
29 controller::component::Scroll, String, view::component::Body>;
30
31lazy_static!{
36 pub static ref CONTROLS : Controls = controls::Builder::new()
37 .buttons (vec![
38 controls::button::Builtin::TextboxScrollDown,
39 controls::button::Builtin::TextboxScrollUp,
40 controls::button::Builtin::TextboxScrollRight,
41 controls::button::Builtin::TextboxScrollLeft,
42 controls::button::Builtin::TextboxPageDown,
43 controls::button::Builtin::TextboxPageUp,
44 controls::button::Builtin::TextboxPageRight,
45 controls::button::Builtin::TextboxPageLeft
46 ].into_iter().map (Into::into).collect::<Vec <_>>().into())
47 .build();
48}
49
50pub fn scroll_right (
52 _ : &controls::button::Release,
53 elements : &Tree <Element>,
54 textbox_id : &NodeId,
55 action_buffer : &mut Vec <(NodeId, Action)>
56) {
57 log::trace!("scroll_right...");
58 scroll_helper (elements, textbox_id, action_buffer,
59 controller::component::Scroll::offset_move_right, 1);
60 log::trace!("...scroll_right");
61}
62
63pub fn scroll_left (
65 _ : &controls::button::Release,
66 elements : &Tree <Element>,
67 textbox_id : &NodeId,
68 action_buffer : &mut Vec <(NodeId, Action)>
69) {
70 log::trace!("scroll_left...");
71 scroll_helper (elements, textbox_id, action_buffer,
72 controller::component::Scroll::offset_move_left, 1);
73 log::trace!("...scroll_left");
74}
75
76pub fn scroll_up (
78 _ : &controls::button::Release,
79 elements : &Tree <Element>,
80 textbox_id : &NodeId,
81 action_buffer : &mut Vec <(NodeId, Action)>
82) {
83 log::trace!("scroll_up...");
84 scroll_helper (elements, textbox_id, action_buffer,
85 controller::component::Scroll::offset_move_up, 1);
86 log::trace!("...scroll_up");
87}
88
89pub fn scroll_down (
91 _ : &controls::button::Release,
92 elements : &Tree <Element>,
93 textbox_id : &NodeId,
94 action_buffer : &mut Vec <(NodeId, Action)>
95) {
96 log::trace!("scroll_down...");
97 scroll_helper (elements, textbox_id, action_buffer,
98 controller::component::Scroll::offset_move_down, 1);
99 log::trace!("...scroll_down");
100}
101
102pub fn page_right (
104 _ : &controls::button::Release,
105 elements : &Tree <Element>,
106 textbox_id : &NodeId,
107 action_buffer : &mut Vec <(NodeId, Action)>
108) {
109 log::trace!("page_right...");
110 let (width, _) = {
112 let Widget (_, _, canvas) =
113 Frame::try_get (elements, elements.get_parent_id (textbox_id)).unwrap();
114 canvas.body_wh()
115 };
116 scroll_helper (elements, textbox_id, action_buffer,
117 controller::component::Scroll::offset_move_right, width-1);
118 log::trace!("...page_right");
119}
120
121pub fn page_left (
123 _ : &controls::button::Release,
124 elements : &Tree <Element>,
125 textbox_id : &NodeId,
126 action_buffer : &mut Vec <(NodeId, Action)>
127) {
128 log::trace!("page_left...");
129 let (width, _) = {
131 let Widget (_, _, canvas) =
132 Frame::try_get (elements, elements.get_parent_id (textbox_id)).unwrap();
133 canvas.body_wh()
134 };
135 scroll_helper (elements, textbox_id, action_buffer,
136 controller::component::Scroll::offset_move_left, width-1);
137 log::trace!("...page_left");
138}
139
140pub fn page_up (
142 _ : &controls::button::Release,
143 elements : &Tree <Element>,
144 textbox_id : &NodeId,
145 action_buffer : &mut Vec <(NodeId, Action)>
146) {
147 log::trace!("page_up...");
148 let (_, height) = {
150 let Widget (_, _, canvas) =
151 Frame::try_get (elements, elements.get_parent_id (textbox_id)).unwrap();
152 canvas.body_wh()
153 };
154 scroll_helper (elements, textbox_id, action_buffer,
155 controller::component::Scroll::offset_move_up, height-1);
156 log::trace!("...page_up");
157}
158
159pub fn page_down (
161 _ : &controls::button::Release,
162 elements : &Tree <Element>,
163 textbox_id : &NodeId,
164 action_buffer : &mut Vec <(NodeId, Action)>
165) {
166 log::trace!("page_down...");
167 let (_, height) = {
169 let Widget (_, _, canvas) =
170 Frame::try_get (elements, elements.get_parent_id (textbox_id)).unwrap();
171 canvas.body_wh()
172 };
173 scroll_helper (elements, textbox_id, action_buffer,
174 controller::component::Scroll::offset_move_down, height-1);
175 log::trace!("...page_down");
176}
177
178pub fn popup <A, P> (
184 interface : &mut Interface <A, P>,
185 parent_id : NodeId,
186 text : String,
187 appearances : Option <controller::Appearances>,
188 border : Option <view::Border>
189) -> [NodeId; 2] where
190 A : Application,
191 P : Presentation
192{
193 let mut builder = FitBuilder::<A>::new (interface.elements(), &parent_id)
194 .frame_anchor (controller::Alignment::middle_center())
195 .text (text);
196 set_option!(builder, frame_appearances, appearances);
197 set_option!(builder, frame_border, border);
198 let [frame_id, textbox_id] =
199 build_and_get_node_ids!(interface, builder, ["Frame", "Textbox"]);
200 let _ = interface.action (&frame_id, Action::Focus);
201 [frame_id, textbox_id]
202}
203
204pub fn get_contents (elements : &Tree <Element>, textbox_id : &NodeId)
206 -> String
207{
208 let Widget (_, contents, _) = Textbox::try_get (elements, textbox_id).unwrap();
209 contents.clone()
210}
211
212pub fn set_contents (
214 elements : &Tree <Element>,
215 textbox_id : &NodeId,
216 contents : String,
217 action_buffer : &mut Vec <(NodeId, Action)>
218) {
219 let new_body = {
220 let Widget (scroll, _, _) = Textbox::try_get (elements, textbox_id).unwrap();
222 let Widget (_, _, canvas) =
223 Frame::try_get (elements, elements.get_parent_id (textbox_id)).unwrap();
224 body (canvas, &scroll, &contents)
225 };
226 { let update_text =
228 Box::new (|model : &mut Model| model.component = contents.into());
229 action_buffer.push ((textbox_id.clone(), Action::ModifyModel (update_text)));
230 }
231 { let update_body =
233 Box::new (|view : &mut View| view.component = new_body.into());
234 action_buffer.push ((textbox_id.clone(), Action::ModifyView (update_body)));
235 }
236}
237
238pub fn fit_to_contents (
240 elements : &Tree <Element>,
241 textbox_id : &NodeId,
242 action_buffer : &mut Vec <(NodeId, Action)>
243) {
244 use controller::component::layout;
245 let (width, height) = {
246 let contents = get_contents (elements, textbox_id);
247 let lines = contents.lines().map (str::len).collect::<Vec <_>>();
248 let height = lines.len() as u32;
249 let width = (*lines.iter().max().unwrap_or (&0)) as u32;
250 (width, height)
251 };
252 let frame_id = elements.get_parent_id (textbox_id);
253 let mut layout = {
254 let Widget (layout, _, _) = Frame::try_get (elements, frame_id).unwrap();
255 layout.clone()
256 };
257 match layout.variant {
258 layout::Variant::Free (ref mut free, _) => {
259 let old_size = free.size;
260 free.size.width = width.into();
261 free.size.height = height.into();
262 if old_size != free.size {
263 frame::set_layout (elements, frame_id, layout, None, action_buffer);
264 }
265 }
266 layout::Variant::Tiled (_) =>
267 log::warn!("fit to contents called on tiled textbox frame")
268 }
269}
270
271pub fn push_line (
274 elements : &Tree <Element>,
275 textbox_id : &NodeId,
276 line : String,
277 action_buffer : &mut Vec <(NodeId, Action)>
278) {
279 let new_body = {
280 let Widget (scroll, contents, _) = Textbox::try_get (elements, textbox_id)
282 .unwrap();
283 let mut contents = contents.clone();
284 contents.push ('\n');
285 contents.push_str (&line);
286 let Widget (_, _, canvas) =
287 Frame::try_get (elements, elements.get_parent_id (textbox_id)).unwrap();
288 body (canvas, &scroll, &contents)
289 };
290 { let update_text = Box::new (move |model : &mut Model| match model.component {
292 model::Component::Text (ref mut text) => {
293 text.push ('\n');
294 text.push_str (&line);
295 }
296 _ => unreachable!()
297 });
298 action_buffer.push ((textbox_id.clone(), Action::ModifyModel (update_text)));
299 }
300 { let update_body =
302 Box::new (|view : &mut View| view.component = new_body.into());
303 action_buffer.push ((textbox_id.clone(), Action::ModifyView (update_body)));
304 }
305}
306
307pub (crate) fn body (
312 canvas : &view::component::Canvas,
313 scroll : &controller::component::Scroll,
314 text : &String
315) -> view::component::Body {
316 use controller::{alignment, offset};
317 log::trace!("body...");
318 let (body_width, body_height) = canvas.body_wh();
319 let lines = text.lines().count() as u32;
320 let longest = text.lines().map (str::len).max().unwrap_or_default() as u32;
321 let scroll_horizontal = match scroll.offset.horizontal {
322 offset::Signed::Absolute (horizontal) => horizontal,
323 offset::Signed::Relative (horizontal) => {
324 let horizontal_max = longest.saturating_sub (body_width) as f32;
325 (*horizontal * horizontal_max).round() as i32
326 }
327 };
328 let scroll_vertical = match scroll.offset.vertical {
329 offset::Signed::Absolute (vertical) => vertical,
330 offset::Signed::Relative (vertical) => {
331 let vertical_max = lines.saturating_sub (body_height) as f32;
332 (*vertical * vertical_max).round() as i32
333 }
334 };
335 let mut body = String::new();
336 let (skip, body_top) = match scroll.alignment.vertical {
337 alignment::Vertical::Top => (scroll_vertical as usize, 0),
338 alignment::Vertical::Bottom => {
339 for _ in 0..body_height.saturating_sub (lines) {
340 body.push ('\n');
341 }
342 ( (lines.saturating_sub (body_height) as i32 - scroll_vertical).max (0)
343 as usize,
344 0
345 )
346 }
347 alignment::Vertical::Middle => {
348 let center = lines as i32 / 2;
349 let body_top = center - body_height as i32 / 2 - scroll_vertical;
350 for _ in body_top..0 {
351 body.push ('\n');
352 }
353 (body_top.max (0) as usize, body_top)
354 }
355 };
356 let take = (body_height as i32 + body_top.min (0)).max (0) as usize;
360 let mut lines = text.lines().skip (skip).take (take);
361 while let Some (line) = lines.next() {
362 let len = line.len();
363 let (space, start, end) = match scroll.alignment.horizontal {
364 alignment::Horizontal::Left => (
365 0,
366 scroll_horizontal as usize,
367 (scroll_horizontal as usize + body_width as usize).min (len)
368 ),
369 alignment::Horizontal::Center => {
370 let center = longest as i32 / 2;
371 let body_left = center - body_width as i32 / 2 + scroll_horizontal;
372 let body_right = center + body_width as i32 / 2 + scroll_horizontal;
373 let line_start = center - len as i32 / 2;
374 let line_end = center + len as i32 / 2 - (len as i32 + 1) % 2;
375 let space = (line_start - body_left).max (0) as usize;
376 let start = (body_left - line_start).max (0) as usize;
377 let end = len - (line_end - body_right).max (0) as usize;
378 (space, start, end)
379 }
380 alignment::Horizontal::Right =>
381 ( (body_width as usize + scroll_horizontal as usize)
382 .saturating_sub (len),
383 len.saturating_sub (body_width as usize)
384 .saturating_sub (scroll_horizontal as usize),
385 len
386 )
387 };
388 if start < end {
389 for _ in 0..space {
390 body.push ('\0');
391 }
392 for ch in line.chars().skip (start).take (end - start) {
395 body.push (ch);
396 }
397 body.push ('\n');
398 } else if start == end {
399 body.push ('\n');
400 }
401 }
402 log::trace!("...body");
403 view::component::Body (body)
404}
405
406fn scroll_helper (
411 elements : &Tree <Element>,
412 textbox_id : &NodeId,
413 action_buffer : &mut Vec <(NodeId, Action)>,
414 scroll_fun : fn (&mut controller::component::Scroll, u32),
415 count : u32
416) {
417 use controller::{alignment, offset};
418 let Widget (scroll, text, _) = Textbox::try_get (elements, textbox_id)
419 .unwrap();
420 let Widget (_, _, canvas) =
421 Frame::try_get (elements, elements.get_parent_id (textbox_id)).unwrap();
422 let lines = text.lines().count() as u32;
423 let longest = text.lines().map (str::len).max().unwrap() as u32;
424 let (body_width, body_height) = canvas.body_wh();
425 let horizontal_max = longest.saturating_sub (body_width) as i32;
426 let vertical_max = lines.saturating_sub (body_height) as i32;
427 let new_scroll = {
428 let mut scroll = scroll.clone();
429 scroll_fun (&mut scroll, count);
430 match &mut scroll.offset.horizontal {
431 offset::Signed::Absolute (horizontal) => {
432 match scroll.alignment.horizontal {
433 alignment::Horizontal::Left | alignment::Horizontal::Right => {
434 *horizontal = (*horizontal).max (0);
435 *horizontal = (*horizontal).min (horizontal_max);
436 }
437 alignment::Horizontal::Center => {
438 *horizontal = (*horizontal)
439 .min (horizontal_max / 2 + (body_width+1) as i32 % 2)
440 .max (-horizontal_max / 2);
441 }
442 }
443 }
444 _ => {} }
446 match &mut scroll.offset.vertical {
447 offset::Signed::Absolute (vertical) => {
448 match scroll.alignment.vertical {
449 alignment::Vertical::Top | alignment::Vertical::Bottom => {
450 *vertical = (*vertical).max (0);
451 *vertical = (*vertical).min (vertical_max);
452 }
453 alignment::Vertical::Middle => {
454 if vertical_max == 0 {
455 *vertical = 0;
456 } else {
457 *vertical = (*vertical)
458 .min (vertical_max / 2 + body_height as i32 % 2)
459 .max (-vertical_max / 2);
460 }
461 }
462 }
463 }
464 _ => {} }
466 scroll
467 };
468 if &new_scroll != scroll {
469 let new_body = body (canvas, &new_scroll, text);
470 { let update_scroll = Box::new (move |controller : &mut Controller|
472 controller.component = new_scroll.into());
473 action_buffer.push (
474 (textbox_id.clone(), Action::ModifyController (update_scroll)));
475 }
476 { let update_body = Box::new (move |view : &mut View|
478 view.component = new_body.into());
479 action_buffer.push (
480 (textbox_id.clone(), Action::ModifyView (update_body)));
481 }
482 }
483}
484
485mod builder {
490 use derive_builder::Builder;
491 use crate::prelude::*;
492 #[derive(Builder)]
501 #[builder(pattern="owned", build_fn(private), setter(strip_option))]
502 pub struct Textbox <'a, A : Application> {
503 elements : &'a Tree <Element>,
504 parent_id : &'a NodeId,
505 #[builder(default)]
506 appearances : controller::Appearances,
507 #[builder(default)]
508 bindings : Option <&'a controller::Bindings <A>>,
509 #[builder(default)]
510 frame_appearances : controller::Appearances,
511 #[builder(default)]
512 frame_border : Option <view::Border>,
513 #[builder(default)]
514 frame_clear_color : Option <canvas::ClearColor>,
515 #[builder(default)]
516 frame_disabled : bool,
517 #[builder(default)]
518 frame_layout : controller::component::Layout,
519 #[builder(default)]
520 text : String,
521 #[builder(default)]
522 scroll : Option <controller::component::Scroll>
523 }
524
525 #[derive(Builder)]
526 #[builder(pattern="owned", build_fn(private), setter(strip_option))]
527 pub struct Fit <'a, A : Application> {
528 elements : &'a Tree <Element>,
529 parent_id : &'a NodeId,
530 #[builder(default)]
531 appearances : controller::Appearances,
532 #[builder(default)]
533 bindings : Option <&'a controller::Bindings <A>>,
534 #[builder(default)]
535 frame_anchor : controller::Alignment,
536 #[builder(default)]
537 frame_appearances : controller::Appearances,
538 #[builder(default)]
539 frame_area : controller::Area,
540 #[builder(default)]
541 frame_border : Option <view::Border>,
542 #[builder(default)]
543 frame_clear_color : Option <canvas::ClearColor>,
544 #[builder(default)]
545 frame_disabled : bool,
546 #[builder(default)]
547 frame_offset : controller::Offset,
548 #[builder(default)]
549 scroll : Option <controller::component::Scroll>,
550 #[builder(default)]
551 text : String
552 }
553
554 #[derive(Builder)]
555 #[builder(pattern="owned", build_fn(private), setter(strip_option))]
556 pub struct WithFrame <'a, A : Application> {
557 elements : &'a Tree <Element>,
558 frame_id : &'a NodeId,
559 #[builder(default)]
560 appearances : controller::Appearances,
561 #[builder(default)]
562 bindings : Option <&'a controller::Bindings <A>>,
563 #[builder(default)]
564 scroll : Option <controller::component::Scroll>,
565 #[builder(default)]
566 text : String
567 }
568
569 impl <'a, A : Application> TextboxBuilder <'a, A> {
570 pub fn new (elements : &'a Tree <Element>, parent_id : &'a NodeId) -> Self {
571 TextboxBuilder {
572 elements: Some (elements),
573 parent_id: Some (parent_id),
574 appearances: None,
575 bindings: None,
576 frame_appearances: None,
577 frame_border: None,
578 frame_clear_color: None,
579 frame_disabled: None,
580 frame_layout: None,
581 scroll: None,
582 text: None
583 }
584 }
585 }
586
587 impl <'a, A : Application> BuildActions for TextboxBuilder <'a, A> {
588 fn build_actions (self) -> Vec<(NodeId, Action)> {
589 use std::convert::TryInto;
590 use crate::tree::{InsertBehavior, Node};
591 use view::coordinates;
592 log::trace!("build actions...");
593 let Textbox {
594 elements, parent_id, appearances, bindings, frame_appearances,
595 frame_border, frame_clear_color, frame_disabled, frame_layout, text,
596 scroll
597 } = self.build()
598 .map_err(|err| log::error!("frame builder error: {:?}", err))
599 .unwrap();
600 let bindings_empty = Bindings::empty();
601 let bindings = bindings.unwrap_or (&bindings_empty);
602 { let Widget (_, _, canvas) = Frame::try_get (elements, parent_id)
604 .unwrap();
605 assert!(canvas.coordinates.kind() == coordinates::Kind::Tile);
606 }
607 let mut out = vec![];
608 let (mut subtree, order) = {
609 let mut actions = {
610 let mut frame = frame::Builder::new (elements, parent_id)
611 .appearances (frame_appearances)
612 .bindings (&bindings)
613 .disabled (frame_disabled)
614 .layout (frame_layout);
615 set_option!(frame, border, frame_border);
616 set_option!(frame, clear_color, frame_clear_color);
617 frame.build_actions()
618 };
619 out.extend (actions.drain (1..));
620 debug_assert_eq!(actions.len(), 1);
621 actions.pop().unwrap().1.try_into().unwrap()
622 };
623 let frame_id = subtree.root_node_id().unwrap().clone();
624 let textbox = {
625 let Widget (_, _, canvas) = Frame::try_get (&subtree, &frame_id)
626 .unwrap();
627 let scroll = scroll.unwrap_or (Scroll::default_tile_absolute());
628 let body = super::body (canvas, &scroll, &text);
629 let controller = {
630 let mut controller = Controller::with_bindings (
631 &bindings.get_bindings (&super::CONTROLS));
632 controller.appearances = appearances;
633 controller.component = scroll.into();
634 controller
635 };
636 let model = Model { component: text.into(), .. Model::default() };
637 let view = view::Component::from (body).into();
638 Element::new ("Textbox".to_string(), controller, model, view)
639 };
640 let _ = subtree
641 .insert (Node::new (textbox), InsertBehavior::UnderNode (&frame_id))
642 .unwrap();
643 out.push ((parent_id.clone(), Action::Create (subtree, order)));
644 log::trace!("...build actions");
645 out
646 }
647 }
648
649 impl <'a, A : Application> FitBuilder <'a, A> {
650 pub fn new (elements : &'a Tree <Element>, parent_id : &'a NodeId) -> Self {
651 FitBuilder {
652 elements: Some (elements),
653 parent_id: Some (parent_id),
654 appearances: None,
655 bindings: None,
656 frame_anchor: None,
657 frame_appearances: None,
658 frame_area: None,
659 frame_border: None,
660 frame_clear_color: None,
661 frame_disabled: None,
662 frame_offset: None,
663 text: None,
664 scroll: None
665 }
666 }
667 }
668
669 impl <'a, A : Application> BuildActions for FitBuilder <'a, A> {
670 fn build_actions (self) -> Vec<(NodeId, Action)> {
672 use std::convert::TryInto;
673 use crate::tree::InsertBehavior;
674 log::trace!("fit build actions...");
675 let Fit {
676 elements, parent_id, appearances, bindings, frame_anchor,
677 frame_appearances, frame_area, frame_border, frame_clear_color,
678 frame_disabled, frame_offset, scroll, text
679 } = self.build()
680 .map_err(|err| log::error!("frame builder error: {:?}", err))
681 .unwrap();
682 let bindings_empty = Bindings::empty();
683 let bindings = bindings.unwrap_or (&bindings_empty);
684 { let Widget (_, _, canvas) = Frame::try_get (elements, parent_id)
686 .unwrap();
687 assert!(canvas.coordinates.kind() == coordinates::Kind::Tile);
688 }
689 let mut out = vec![];
690 let (mut subtree, order) = {
691 let size = {
692 let longest = text.lines().map (str::len).max().unwrap() as u32;
693 let lines = text.lines().count() as u32;
694 let (border_w, border_h) = frame_border.as_ref()
695 .map (Border::total_wh).unwrap_or ((0,0));
696 let width = (longest + border_w as u32).into();
697 let height = (lines + border_h as u32).into();
698 controller::Size { width, height }
699 };
700 let layout = layout::Variant::from ((
701 layout::Free { anchor: frame_anchor, offset: frame_offset, size },
702 frame_area
703 ));
704 let mut actions = {
705 let mut frame = frame::Builder::new (elements, parent_id)
706 .appearances (frame_appearances)
707 .bindings (bindings)
708 .disabled (frame_disabled)
709 .layout (layout.into());
710 set_option!(frame, border, frame_border);
711 set_option!(frame, clear_color, frame_clear_color);
712 frame.build_actions()
713 };
714 out.extend (actions.drain (1..));
715 debug_assert_eq!(actions.len(), 1);
716 actions.pop().unwrap().1.try_into().unwrap()
717 };
718 let frame_id = subtree.root_node_id().unwrap().clone();
719 let textbox = {
720 let Widget (_, _, canvas) = Frame::try_get (&subtree, &frame_id)
721 .unwrap();
722 let scroll = scroll.unwrap_or (Scroll::default_tile_absolute());
723 let body = super::body (canvas, &scroll, &text);
724 let controller = {
725 let mut controller = Controller::with_bindings (&bindings);
726 controller.appearances = appearances;
727 controller.component = scroll.into();
728 controller
729 };
730 let model = Model {
731 component: text.clone().into(), .. Model::default()
732 };
733 let view = view::Component::from (body).into();
734 Element::new ("Textbox".to_string(), controller, model, view)
735 };
736 let _ = subtree
737 .insert (Node::new (textbox), InsertBehavior::UnderNode (&frame_id))
738 .unwrap();
739 out.push ((parent_id.clone(), Action::Create (subtree, order)));
740 log::trace!("...fit build actions");
741 out
742 }
743 }
744
745 impl <'a, A : Application> WithFrameBuilder <'a, A> {
746 pub fn new (elements : &'a Tree <Element>, frame_id : &'a NodeId) -> Self {
747 WithFrameBuilder {
748 elements: Some (elements),
749 frame_id: Some (frame_id),
750 bindings: None,
751 appearances: None,
752 text: None,
753 scroll: None
754 }
755 }
756 }
757
758 impl <'a, A : Application> BuildElement for WithFrameBuilder <'a, A> {
759 fn build_element (self) -> Element {
762 use view::coordinates;
763 log::trace!("with frame build element...");
764 let WithFrame {
765 elements, frame_id, bindings, appearances, text, scroll
766 } = self.build()
767 .map_err(|err| log::error!("frame builder error: {:?}", err)).unwrap();
768 let bindings_empty = Bindings::empty();
769 let bindings = bindings.unwrap_or (&bindings_empty)
770 .get_bindings (&super::CONTROLS);
771 let Widget (_, _, canvas) = Frame::try_get (elements, &frame_id)
772 .unwrap();
773 assert!(canvas.coordinates.kind() == coordinates::Kind::Tile);
774 let scroll = scroll.unwrap_or (Scroll::default_tile_absolute());
775 let body = super::body (canvas, &scroll, &text);
776 let controller = {
777 let mut controller = Controller::with_bindings (&bindings);
778 controller.appearances = appearances;
779 controller.component = scroll.into();
780 controller
781 };
782 let model = Model { component: text.into(), .. Model::default() };
783 let view = view::Component::from (body).into();
784 log::trace!("...with frame build element");
785 Element::new ("Textbox".to_string(), controller, model, view)
786 }
787 }
788}