1use crate::layout::generic_layout::GenericLayout;
2use crate::util::block_padding;
3use ratatui::layout::{Flex, Rect, Size};
4use ratatui::widgets::{Block, Padding};
5use std::borrow::Cow;
6use std::cmp::{max, min};
7use std::fmt::Debug;
8use std::hash::Hash;
9use std::ops::Range;
10
11#[derive(Debug, Default)]
15pub enum FormLabel {
16 #[default]
18 None,
19 Str(&'static str),
25 String(String),
31 Width(u16),
38 Size(u16, u16),
45}
46
47#[derive(Debug, Default)]
51pub enum FormWidget {
52 #[default]
54 None,
55 Width(u16),
62 Size(u16, u16),
69 StretchY(u16, u16),
81 Wide(u16, u16),
90
91 StretchX(u16, u16),
98
99 WideStretchX(u16, u16),
107
108 StretchXY(u16, u16),
117
118 WideStretchXY(u16, u16),
128}
129
130#[derive(Debug)]
238pub struct LayoutForm<W>
239where
240 W: Eq + Hash + Clone + Debug,
241{
242 spacing: u16,
244 line_spacing: u16,
246 mirror: bool,
248 flex: Flex,
250 widgets: Vec<WidgetDef<W>>,
252 blocks: Vec<BlockDef>,
254 page_breaks: Vec<usize>,
256
257 max_label: u16,
259 max_widget: u16,
260
261 max_left_padding: u16,
263 max_right_padding: u16,
264
265 c_top: u16,
268 c_bottom: u16,
271 c_left: u16,
273 c_right: u16,
275}
276
277#[derive(Debug)]
278struct WidgetDef<W>
279where
280 W: Debug + Clone,
281{
282 id: W,
284 label: FormLabel,
286 label_str: Option<Cow<'static, str>>,
288 widget: FormWidget,
290 top_border: u16,
292 bottom_border: u16,
294 opt_bottom_border: u16,
297}
298
299#[derive(Debug, Default, PartialEq, Eq, Clone, Copy)]
301pub struct BlockTag(usize);
302
303#[derive(Debug)]
304struct BlockDef {
305 id: BlockTag,
306 block: Option<Block<'static>>,
308 padding: Padding,
310 constructing: bool,
312 range: Range<usize>,
314 area: Rect,
316}
317
318#[derive(Debug)]
319struct BlockOut {
320 block: Option<Block<'static>>,
322 area: Rect,
324}
325
326#[derive(Debug, Default, Clone, Copy)]
328struct Positions {
329 label_x: u16,
331 label_width: u16,
333 widget_x: u16,
335 widget_width: u16,
337 container_left: u16,
339 container_right: u16,
341 total_width: u16,
343}
344
345#[derive(Debug, Default, Clone, Copy)]
347struct Page {
348 #[allow(dead_code)]
350 width: u16,
351 height: u16,
353 top: u16,
355 bottom: u16,
357 max_height: u16,
359
360 page_no: u16,
362 y_page: u16,
364 y: u16,
366
367 line_spacing: u16,
370
371 container_left: u16,
373 container_right: u16,
375}
376
377impl BlockDef {
378 fn as_out(&self) -> BlockOut {
379 BlockOut {
380 block: self.block.clone(),
381 area: self.area,
382 }
383 }
384}
385
386impl FormWidget {
387 #[inline(always)]
388 fn is_stretch_y(&self) -> bool {
389 match self {
390 FormWidget::None => false,
391 FormWidget::Width(_) => false,
392 FormWidget::Size(_, _) => false,
393 FormWidget::Wide(_, _) => false,
394 FormWidget::StretchX(_, _) => false,
395 FormWidget::WideStretchX(_, _) => false,
396 FormWidget::StretchXY(_, _) => true,
397 FormWidget::WideStretchXY(_, _) => true,
398 FormWidget::StretchY(_, _) => true,
399 }
400 }
401}
402
403impl<W> Default for LayoutForm<W>
404where
405 W: Eq + Clone + Hash + Debug,
406{
407 fn default() -> Self {
408 Self {
409 spacing: 1,
410 line_spacing: Default::default(),
411 mirror: Default::default(),
412 flex: Default::default(),
413 widgets: Default::default(),
414 page_breaks: Default::default(),
415 max_label: Default::default(),
416 max_widget: Default::default(),
417 blocks: Default::default(),
418 max_left_padding: Default::default(),
419 max_right_padding: Default::default(),
420 c_top: Default::default(),
421 c_bottom: Default::default(),
422 c_left: Default::default(),
423 c_right: Default::default(),
424 }
425 }
426}
427
428impl<W> LayoutForm<W>
429where
430 W: Eq + Hash + Clone + Debug,
431{
432 pub fn new() -> Self {
433 Self::default()
434 }
435
436 #[inline]
438 pub fn spacing(mut self, spacing: u16) -> Self {
439 self.spacing = spacing;
440 self
441 }
442
443 #[inline]
445 pub fn line_spacing(mut self, spacing: u16) -> Self {
446 self.line_spacing = spacing;
447 self
448 }
449
450 #[inline]
453 pub fn mirror_odd_border(mut self) -> Self {
454 self.mirror = true;
455 self
456 }
457
458 #[inline]
460 pub fn flex(mut self, flex: Flex) -> Self {
461 self.flex = flex;
462 self
463 }
464
465 pub fn min_label(mut self, width: u16) -> Self {
467 self.max_label = width;
468 self
469 }
470
471 pub fn min_widget(mut self, width: u16) -> Self {
473 self.max_widget = width;
474 self
475 }
476
477 pub fn start(&mut self, block: Option<Block<'static>>) -> BlockTag {
485 let max_idx = self.widgets.len();
486 let padding = block_padding(&block);
487
488 let tag = BlockTag(self.blocks.len());
489 self.blocks.push(BlockDef {
490 id: tag,
491 block,
492 padding,
493 constructing: true,
494 range: max_idx..max_idx,
495 area: Rect::default(),
496 });
497
498 self.c_top += padding.top;
499 self.c_bottom += padding.bottom;
500 self.c_left += padding.left;
501 self.c_right += padding.right;
502
503 self.max_left_padding = max(self.max_left_padding, self.c_left);
504 self.max_right_padding = max(self.max_right_padding, self.c_right);
505
506 tag
507 }
508
509 pub fn end(&mut self, tag: BlockTag) {
516 let max = self.widgets.len();
517 for cc in self.blocks.iter_mut().rev() {
518 if cc.id == tag && cc.constructing {
519 cc.range.end = max;
520 cc.constructing = false;
521
522 if self.c_top > 0 {
524 self.c_top -= cc.padding.top;
525 }
526 self.c_bottom -= cc.padding.bottom;
527 self.c_left -= cc.padding.left;
528 self.c_right -= cc.padding.right;
529
530 if let Some(last) = self.widgets.last_mut() {
531 last.opt_bottom_border -= cc.padding.bottom;
532 }
533
534 return;
535 }
536 if cc.constructing {
537 panic!("Unclosed container {:?}", cc.id);
538 }
539 }
540
541 panic!("No open container.");
542 }
543
544 fn validate_containers(&self) {
545 for cc in self.blocks.iter() {
546 if cc.constructing {
547 panic!("Unclosed container {:?}", cc.id);
548 }
549 }
550 }
551
552 pub fn widget(&mut self, key: W, label: FormLabel, widget: FormWidget) {
555 let (label, label_str) = match label {
557 FormLabel::Str(s) => {
558 let width = unicode_display_width::width(s) as u16;
559 (FormLabel::Width(width), Some(Cow::Borrowed(s)))
560 }
561 FormLabel::String(s) => {
562 let width = unicode_display_width::width(&s) as u16;
563 (FormLabel::Width(width), Some(Cow::Owned(s)))
564 }
565 FormLabel::Width(w) => (FormLabel::Width(w), None),
566 FormLabel::Size(w, h) => (FormLabel::Size(w, h), None),
567 FormLabel::None => (FormLabel::None, None),
568 };
569
570 let w = match &label {
571 FormLabel::None => 0,
572 FormLabel::Str(_) | FormLabel::String(_) => {
573 unreachable!()
574 }
575 FormLabel::Width(w) => *w,
576 FormLabel::Size(w, _) => *w,
577 };
578 self.max_label = max(self.max_label, w);
579
580 let w = match &widget {
581 FormWidget::None => 0,
582 FormWidget::Width(w) => *w,
583 FormWidget::Size(w, _) => *w,
584 FormWidget::StretchY(w, _) => *w,
585 FormWidget::Wide(w, _) => *w,
586 FormWidget::StretchX(w, _) => *w,
587 FormWidget::WideStretchX(w, _) => *w,
588 FormWidget::StretchXY(w, _) => *w,
589 FormWidget::WideStretchXY(w, _) => *w,
590 };
591 self.max_widget = max(self.max_widget, w);
592
593 self.widgets.push(WidgetDef {
594 id: key,
595 label,
596 label_str,
597 widget,
598 top_border: self.c_top,
599 bottom_border: self.c_bottom,
600 opt_bottom_border: self.c_bottom,
601 });
602
603 self.c_top = 0;
607 }
608
609 pub fn page_break(&mut self) {
613 self.page_breaks.push(self.widgets.len() - 1);
614 }
615
616 fn adjust_widths(&mut self, page_width: u16, border: Padding) {
618 let page_width = page_width.saturating_sub(
620 border.left + self.max_left_padding + self.max_right_padding + border.right,
621 );
622 if self.max_label + self.spacing + self.max_widget > page_width {
623 let mut reduce = self.max_label + self.spacing + self.max_widget - page_width;
624
625 if self.spacing > reduce {
626 self.spacing -= reduce;
627 reduce = 0;
628 } else {
629 reduce -= self.spacing;
630 self.spacing = 0;
631 }
632 if self.max_label > 5 {
633 if self.max_label - 5 > reduce {
634 self.max_label -= reduce;
635 reduce = 0;
636 } else {
637 reduce -= self.max_label - 5;
638 self.max_label = 5;
639 }
640 }
641 if self.max_widget > 5 {
642 if self.max_widget - 5 > reduce {
643 self.max_widget -= reduce;
644 reduce = 0;
645 } else {
646 reduce -= self.max_widget - 5;
647 self.max_widget = 5;
648 }
649 }
650 if self.max_label > reduce {
651 self.max_label -= reduce;
652 reduce = 0;
653 } else {
654 reduce -= self.max_label;
655 self.max_label = 0;
656 }
657 if self.max_widget > reduce {
658 self.max_widget -= reduce;
659 } else {
661 self.max_widget = 0;
663 }
664 }
665 }
666
667 fn find_pos(&self, layout_width: u16, border: Padding) -> Positions {
669 let label_x;
670 let widget_x;
671 let container_left;
672 let container_right;
673 let total_width;
674
675 match self.flex {
676 Flex::Legacy => {
677 label_x = border.left + self.max_left_padding;
678 widget_x = label_x + self.max_label + self.spacing;
679
680 container_left = label_x.saturating_sub(self.max_left_padding);
681 container_right = layout_width.saturating_sub(border.right);
682
683 total_width = self.max_label + self.spacing + self.max_widget;
684 }
685 Flex::Start => {
686 label_x = border.left + self.max_left_padding;
687 widget_x = label_x + self.max_label + self.spacing;
688
689 container_left = label_x.saturating_sub(self.max_left_padding);
690 container_right = widget_x + self.max_widget + self.max_right_padding;
691
692 total_width = self.max_label + self.spacing + self.max_widget;
693 }
694 Flex::Center => {
695 let rest = layout_width.saturating_sub(
696 border.left
697 + self.max_left_padding
698 + self.max_label
699 + self.spacing
700 + self.max_widget
701 + self.max_right_padding
702 + border.right,
703 );
704 label_x = border.left + self.max_left_padding + rest / 2;
705 widget_x = label_x + self.max_label + self.spacing;
706
707 container_left = label_x.saturating_sub(self.max_left_padding);
708 container_right = widget_x + self.max_widget + self.max_right_padding;
709
710 total_width = self.max_label + self.spacing + self.max_widget;
711 }
712 Flex::End => {
713 widget_x = layout_width
714 .saturating_sub(border.right + self.max_right_padding + self.max_widget);
715 label_x = widget_x.saturating_sub(self.spacing + self.max_label);
716
717 container_left = label_x.saturating_sub(self.max_left_padding);
718 container_right = layout_width.saturating_sub(border.right);
719
720 total_width = self.max_label + self.spacing + self.max_widget;
721 }
722 Flex::SpaceAround => {
723 let rest = layout_width.saturating_sub(
724 border.left
725 + self.max_left_padding
726 + self.max_label
727 + self.max_widget
728 + self.max_right_padding
729 + border.right,
730 );
731 let spacing = rest / 3;
732
733 label_x = border.left + self.max_left_padding + spacing;
734 widget_x = label_x + self.max_label + spacing;
735
736 container_left = border.left;
737 container_right = layout_width.saturating_sub(border.right);
738
739 total_width = self.max_label + spacing + self.max_widget;
740 }
741 Flex::SpaceBetween => {
742 label_x = border.left + self.max_left_padding;
743 widget_x = layout_width
744 .saturating_sub(border.right + self.max_right_padding + self.max_widget);
745
746 container_left = label_x.saturating_sub(self.max_left_padding);
747 container_right = layout_width.saturating_sub(border.right);
748
749 total_width = layout_width.saturating_sub(
750 border.left + self.max_left_padding + border.right + self.max_right_padding,
751 );
752 }
753 }
754
755 Positions {
756 container_left,
757 label_x,
758 label_width: self.max_label,
759 widget_x,
760 widget_width: self.max_widget,
761 container_right,
762 total_width,
763 }
764 }
765
766 #[inline(always)]
768 pub fn endless(self, width: u16, border: Padding) -> GenericLayout<W> {
769 self._layout::<true>(Size::new(width, u16::MAX), border)
770 }
771
772 #[inline(always)]
774 pub fn paged(self, page: Size, border: Padding) -> GenericLayout<W> {
775 self._layout::<false>(page, border)
776 }
777
778 fn _layout<const ENDLESS: bool>(mut self, page: Size, border: Padding) -> GenericLayout<W> {
780 self.validate_containers();
781 self.adjust_widths(page.width, border);
782 let pos_even = self.find_pos(page.width, border);
783 let pos_odd = if self.mirror {
784 self.find_pos(
785 page.width,
786 Padding::new(border.right, border.left, border.top, border.bottom),
787 )
788 } else {
789 pos_even
790 };
791
792 let mut gen_layout = GenericLayout::with_capacity(self.widgets.len(), self.blocks.len());
793 gen_layout.set_page_size(page);
794
795 let mut tmp = Vec::new();
796
797 let mut pos = &pos_even;
798 let mut page_bak;
799 let mut page = Page {
800 width: page.width,
801 height: page.height,
802 top: border.top,
803 bottom: border.bottom,
804 max_height: page.height.saturating_sub(border.top + border.bottom),
805
806 page_no: 0,
807 y_page: 0,
808 y: border.top,
809
810 line_spacing: 0,
811
812 container_left: pos.container_left,
813 container_right: pos.container_right,
814 };
815 let mut stretch_y = Vec::new();
817
818 for (idx, widget) in self.widgets.into_iter().enumerate() {
819 page_bak = page;
821
822 page.next_widget(self.line_spacing);
824 for cc in self.blocks.iter_mut() {
826 if cc.range.start == idx {
827 page.start_container(cc);
828 }
829 }
830 let (mut label_area, mut widget_area) = page.widget_area(&widget, pos);
832 for cc in self.blocks.iter_mut().rev() {
834 if idx + 1 == cc.range.end {
835 page.end_container(cc);
836 tmp.push(cc.as_out());
837 }
838 }
839
840 let break_overflow = if ENDLESS {
841 false
842 } else {
843 page.y.saturating_add(widget.opt_bottom_border)
844 >= page
845 .y_page
846 .saturating_add(page.height.saturating_sub(page.bottom))
847 };
848 let break_manual = if ENDLESS {
849 false
850 } else {
851 self.page_breaks.contains(&idx)
852 };
853
854 if break_overflow {
856 page = page_bak;
858 tmp.clear();
860
861 for cc in self.blocks.iter_mut().rev() {
864 if idx > cc.range.start && idx < cc.range.end {
865 page.end_container(cc);
866 tmp.push(cc.as_out());
867 cc.range.start = idx;
869 }
870 }
871 while let Some(cc) = tmp.pop() {
873 gen_layout.add_block(cc.area, cc.block);
874 }
875
876 Self::adjust_y_stretch(&page, &mut stretch_y, &mut gen_layout);
878
879 pos = page.next_page(&pos_even, &pos_odd);
881
882 page.next_widget(self.line_spacing);
886 for cc in self.blocks.iter_mut() {
888 if idx == cc.range.start {
889 page.start_container(cc);
890 }
891 }
892 (label_area, widget_area) = page.widget_area(&widget, pos);
894 for cc in self.blocks.iter_mut().rev() {
897 if idx + 1 == cc.range.end {
898 page.end_container(cc);
899 tmp.push(cc.as_out());
900 }
901 }
902 }
903
904 if widget.widget.is_stretch_y() && !ENDLESS {
906 stretch_y.push(gen_layout.widget_len());
907 }
908 gen_layout.add(widget.id.clone(), widget_area, widget.label_str, label_area);
910 while let Some(cc) = tmp.pop() {
912 gen_layout.add_block(cc.area, cc.block);
913 }
914
915 if break_manual {
916 for cc in self.blocks.iter_mut().rev() {
921 if idx + 1 > cc.range.start && idx + 1 < cc.range.end {
922 page.end_container(cc);
923 tmp.push(cc.as_out());
924 cc.range.start = idx + 1;
926 }
927 }
928 while let Some(cc) = tmp.pop() {
930 gen_layout.add_block(cc.area, cc.block);
931 }
932
933 Self::adjust_y_stretch(&page, &mut stretch_y, &mut gen_layout);
935
936 pos = page.next_page(&pos_even, &pos_odd);
938 }
939 }
940
941 Self::adjust_y_stretch(&page, &mut stretch_y, &mut gen_layout);
943
944 gen_layout.set_page_count((page.page_no + 1) as usize);
945
946 gen_layout
947 }
948
949 fn adjust_y_stretch(
952 page: &Page,
953 stretch_y: &mut Vec<usize>,
954 gen_layout: &mut GenericLayout<W>,
955 ) {
956 let bottom_y = page
957 .y_page
958 .saturating_add(page.height.saturating_sub(page.bottom));
959
960 let mut remainder = bottom_y.saturating_sub(page.y);
961 if remainder == 0 {
962 return;
963 }
964 let mut n = stretch_y.len() as u16;
965
966 for y_idx in stretch_y.drain(..) {
967 let stretch = remainder / n;
970 remainder -= stretch;
971 n -= 1;
972
973 let mut area = gen_layout.widget(y_idx);
975 let test_y = area.bottom();
976 area.height += stretch;
977 gen_layout.set_widget(y_idx, area);
978
979 for idx in y_idx + 1..gen_layout.widget_len() {
981 let mut area = gen_layout.widget(idx);
982 if area.y >= test_y {
983 area.y += stretch;
984 }
985 gen_layout.set_widget(idx, area);
986
987 let mut area = gen_layout.label(idx);
988 if area.y >= test_y {
989 area.y += stretch;
990 }
991 gen_layout.set_label(idx, area);
992 }
993
994 for idx in 0..gen_layout.block_len() {
996 let mut area = gen_layout.block_area(idx);
997 if area.y >= test_y {
998 area.y += stretch;
999 }
1000 if area.y <= test_y && area.bottom() > test_y {
1002 area.height += stretch;
1003 }
1004 gen_layout.set_block_area(idx, area);
1005 }
1006 }
1007 }
1008}
1009
1010impl Page {
1011 fn widget_area<W: Debug + Clone>(
1012 &mut self,
1013 widget: &WidgetDef<W>,
1014 pos: &Positions,
1015 ) -> (Rect, Rect) {
1016 let stacked = matches!(
1017 widget.widget,
1018 FormWidget::Wide(_, _)
1019 | FormWidget::WideStretchX(_, _)
1020 | FormWidget::WideStretchXY(_, _)
1021 );
1022
1023 let mut label_height = match &widget.label {
1024 FormLabel::None => 0,
1025 FormLabel::Str(_) | FormLabel::String(_) => unreachable!(),
1026 FormLabel::Width(_) => 1,
1027 FormLabel::Size(_, h) => *h,
1028 };
1029
1030 let mut widget_height = match &widget.widget {
1031 FormWidget::None => 0,
1032 FormWidget::Width(_) => 1,
1033 FormWidget::Size(_, h) => *h,
1034 FormWidget::StretchY(_, h) => *h,
1035 FormWidget::Wide(_, h) => *h,
1036 FormWidget::StretchX(_, h) => *h,
1037 FormWidget::WideStretchX(_, h) => *h,
1038 FormWidget::StretchXY(_, h) => *h,
1039 FormWidget::WideStretchXY(_, h) => *h,
1040 };
1041
1042 let stretch_width = self.container_right.saturating_sub(pos.widget_x);
1043 let total_stretch_width = self.container_right.saturating_sub(pos.label_x);
1044
1045 if stacked {
1046 let max_height = self
1047 .max_height
1048 .saturating_sub(widget.top_border + widget.bottom_border);
1049 if label_height + widget_height > max_height {
1050 label_height = min(1, max_height.saturating_sub(widget_height));
1051 }
1052 if label_height + widget_height > max_height {
1053 widget_height = min(1, max_height.saturating_sub(label_height));
1054 }
1055 if label_height + widget_height > max_height {
1056 label_height = 0;
1057 }
1058 if label_height + widget_height > max_height {
1059 widget_height = max_height;
1060 }
1061
1062 let mut label_area = match &widget.label {
1063 FormLabel::None => Rect::default(),
1064 FormLabel::Str(_) | FormLabel::String(_) => {
1065 unreachable!()
1066 }
1067 FormLabel::Width(_) => {
1068 Rect::new(pos.label_x, self.y, pos.label_width, label_height)
1069 }
1070 FormLabel::Size(_, _) => {
1071 Rect::new(pos.label_x, self.y, pos.label_width, label_height)
1072 }
1073 };
1074 match &widget.widget {
1075 FormWidget::Wide(_, _) => label_area.width = pos.total_width,
1076 FormWidget::WideStretchX(_, _) => label_area.width = total_stretch_width,
1077 FormWidget::WideStretchXY(_, _) => label_area.width = total_stretch_width,
1078 _ => {}
1079 }
1080
1081 self.y = self.y.saturating_add(label_area.height);
1082
1083 let widget_area = match &widget.widget {
1084 FormWidget::None => Rect::default(),
1085 FormWidget::Width(w) => Rect::new(
1086 pos.widget_x,
1087 self.y,
1088 min(*w, pos.widget_width),
1089 widget_height,
1090 ),
1091 FormWidget::Size(w, _) => Rect::new(
1092 pos.widget_x,
1093 self.y,
1094 min(*w, pos.widget_width),
1095 widget_height,
1096 ),
1097 FormWidget::StretchY(w, _) => Rect::new(
1098 pos.widget_x,
1099 self.y,
1100 min(*w, pos.widget_width),
1101 widget_height,
1102 ),
1103 FormWidget::Wide(_, _) => {
1104 Rect::new(pos.label_x, self.y, pos.total_width, widget_height)
1105 }
1106 FormWidget::StretchX(_, _) => {
1107 Rect::new(pos.widget_x, self.y, stretch_width, widget_height)
1108 }
1109 FormWidget::WideStretchX(_, _) => {
1110 Rect::new(pos.label_x, self.y, total_stretch_width, widget_height)
1111 }
1112 FormWidget::StretchXY(_, _) => {
1113 Rect::new(pos.widget_x, self.y, stretch_width, widget_height)
1114 }
1115 FormWidget::WideStretchXY(_, _) => {
1116 Rect::new(pos.label_x, self.y, total_stretch_width, widget_height)
1117 }
1118 };
1119
1120 self.y = self.y.saturating_add(widget_area.height);
1121
1122 (label_area, widget_area)
1123 } else {
1124 let max_height = self
1125 .max_height
1126 .saturating_sub(widget.top_border + widget.bottom_border);
1127 label_height = min(label_height, max_height);
1128 widget_height = min(widget_height, max_height);
1129
1130 let label_area = match &widget.label {
1131 FormLabel::None => Rect::default(),
1132 FormLabel::Str(_) | FormLabel::String(_) => {
1133 unreachable!()
1134 }
1135 FormLabel::Width(_) => {
1136 Rect::new(pos.label_x, self.y, pos.label_width, label_height)
1137 }
1138 FormLabel::Size(_, _) => {
1139 Rect::new(pos.label_x, self.y, pos.label_width, label_height)
1140 }
1141 };
1142
1143 let widget_area = match &widget.widget {
1144 FormWidget::None => Rect::default(),
1145 FormWidget::Width(w) => Rect::new(
1146 pos.widget_x,
1147 self.y,
1148 min(*w, pos.widget_width),
1149 widget_height,
1150 ),
1151 FormWidget::Size(w, _) => Rect::new(
1152 pos.widget_x,
1153 self.y,
1154 min(*w, pos.widget_width),
1155 widget_height,
1156 ),
1157 FormWidget::StretchY(w, _) => Rect::new(
1158 pos.widget_x,
1159 self.y,
1160 min(*w, pos.widget_width),
1161 widget_height,
1162 ),
1163 FormWidget::Wide(_, _) => {
1164 unreachable!()
1165 }
1166 FormWidget::StretchX(_, _) => {
1167 Rect::new(pos.widget_x, self.y, stretch_width, widget_height)
1168 }
1169 FormWidget::WideStretchX(_, _) => {
1170 unreachable!()
1171 }
1172 FormWidget::StretchXY(_, _) => {
1173 Rect::new(pos.widget_x, self.y, stretch_width, widget_height)
1174 }
1175 FormWidget::WideStretchXY(_, _) => {
1176 unreachable!()
1177 }
1178 };
1179
1180 self.y = self
1181 .y
1182 .saturating_add(max(label_area.height, widget_area.height));
1183
1184 (label_area, widget_area)
1185 }
1186 }
1187
1188 fn next_page<'a>(&mut self, pos_even: &'a Positions, pos_odd: &'a Positions) -> &'a Positions {
1190 self.page_no += 1;
1191 self.y_page = self.page_no.saturating_mul(self.height);
1192 self.y = self.y_page.saturating_add(self.top);
1193 self.line_spacing = 0;
1194
1195 if self.page_no % 2 == 0 {
1196 pos_even
1197 } else {
1198 pos_odd
1199 }
1200 }
1201
1202 fn next_widget(&mut self, adjust_spacing: u16) {
1204 self.y = self.y.saturating_add(self.line_spacing);
1205 self.line_spacing = adjust_spacing;
1206 }
1207
1208 fn end_container(&mut self, cc: &mut BlockDef) {
1210 self.y = self.y.saturating_add(cc.padding.bottom);
1211 self.container_left = self.container_left.saturating_sub(cc.padding.left);
1212 self.container_right = self.container_right.saturating_add(cc.padding.right);
1213
1214 cc.area.height = self.y.saturating_sub(cc.area.y);
1215 }
1216
1217 fn start_container(&mut self, cc: &mut BlockDef) {
1219 cc.area.x = self.container_left;
1220 cc.area.width = self.container_right.saturating_sub(self.container_left);
1221 cc.area.y = self.y;
1222
1223 self.y = self.y.saturating_add(cc.padding.top);
1224 self.container_left = self.container_left.saturating_add(cc.padding.left);
1225 self.container_right = self.container_right.saturating_sub(cc.padding.right);
1226 }
1227}