1use crate::layout::generic_layout::GenericLayout;
2use crate::util::{block_padding, block_padding2};
3use ratatui::layout::{Flex, Rect, Size};
4use ratatui::widgets::{Block, Borders, Padding};
5use std::borrow::Cow;
6use std::cmp::{max, min};
7use std::collections::VecDeque;
8use std::fmt::Debug;
9use std::hash::Hash;
10use std::mem;
11use std::ops::Range;
12use std::rc::Rc;
13
14#[derive(Debug, Default)]
18pub enum FormLabel {
19 #[default]
21 None,
22 Str(&'static str),
29 String(String),
36 Width(u16),
43 Size(u16, u16),
50}
51
52#[derive(Debug, Default)]
56pub enum FormWidget {
57 #[default]
59 None,
60 Width(u16),
66 Size(u16, u16),
72 StretchY(u16, u16),
81 Wide(u16, u16),
88 StretchX(u16, u16),
92 WideStretchX(u16, u16),
96 StretchXY(u16, u16),
105
106 WideStretchXY(u16, u16),
115}
116
117#[derive(Debug)]
231pub struct LayoutForm<W>
232where
233 W: Eq + Hash + Clone + Debug,
234{
235 spacing: u16,
237 line_spacing: u16,
239 column_spacing: u16,
241 page_border: Padding,
243 mirror_border: bool,
245 columns: u16,
247 flex: Flex,
249 widgets: Vec<WidgetDef<W>>,
251 blocks: VecDeque<BlockDef>,
253 page_breaks: Vec<usize>,
255
256 min_label: u16,
258 min_widget: u16,
259 min_widget_wide: u16,
260
261 max_left_padding: u16,
263 max_right_padding: u16,
264
265 left_padding: u16,
267 right_padding: u16,
269}
270
271#[derive(Debug)]
272struct WidgetDef<W>
273where
274 W: Debug + Clone,
275{
276 id: W,
278 label: FormLabel,
280 label_str: Option<Cow<'static, str>>,
282 widget: FormWidget,
284}
285
286#[derive(Debug, Default, PartialEq, Eq, Clone, Copy)]
288pub struct BlockTag(usize);
289
290#[derive(Debug)]
291struct BlockDef {
292 id: BlockTag,
293 block: Option<Block<'static>>,
295 padding: Padding,
297 constructing: bool,
299 range: Range<usize>,
301 area: Rect,
303}
304
305#[derive(Debug)]
306struct BlockOut {
307 block: Option<Block<'static>>,
309 area: Rect,
311}
312
313#[derive(Debug, Default, Clone, Copy)]
315struct XPositions {
316 label_left: u16,
318 label_width: u16,
320 widget_left: u16,
322 widget_width: u16,
324 widget_right: u16,
326 container_left: u16,
328 container_right: u16,
330 total_width: u16,
332}
333
334#[derive(Default, Debug, Clone)]
336struct PageDef {
337 page_border: Padding,
339 full_width: u16,
341 flex: Flex,
343 max_left_padding: u16,
345 max_right_padding: u16,
347 max_label: u16,
349 max_widget: u16,
351
352 #[allow(dead_code)]
354 width: u16,
355 height: u16,
357 top: u16,
359 bottom: u16,
361 columns: u16,
363 column_spacing: u16,
365 spacing: u16,
367 line_spacing: u16,
369}
370
371#[derive(Default, Debug, Clone)]
373struct Page {
374 def: Rc<PageDef>,
376 page_no: u16,
378 page_start: u16,
380 page_end: u16,
382
383 y: u16,
385
386 top_padding: u16,
388 bottom_padding: u16,
390 bottom_padding_break: u16,
392 effective_line_spacing: u16,
394
395 x_pos: XPositions,
397}
398
399impl BlockDef {
400 fn as_out(&self) -> BlockOut {
401 BlockOut {
402 block: self.block.clone(),
403 area: self.area,
404 }
405 }
406}
407
408impl FormWidget {
409 #[inline(always)]
410 fn is_stretch_y(&self) -> bool {
411 match self {
412 FormWidget::None => false,
413 FormWidget::Width(_) => false,
414 FormWidget::Size(_, _) => false,
415 FormWidget::Wide(_, _) => false,
416 FormWidget::StretchX(_, _) => false,
417 FormWidget::WideStretchX(_, _) => false,
418 FormWidget::StretchXY(_, _) => true,
419 FormWidget::WideStretchXY(_, _) => true,
420 FormWidget::StretchY(_, _) => true,
421 }
422 }
423}
424
425impl<W> Default for LayoutForm<W>
426where
427 W: Eq + Clone + Hash + Debug,
428{
429 fn default() -> Self {
430 Self {
431 spacing: 1,
432 line_spacing: Default::default(),
433 column_spacing: 1,
434 page_border: Default::default(),
435 mirror_border: Default::default(),
436 columns: 1,
437 flex: Default::default(),
438 widgets: Default::default(),
439 page_breaks: Default::default(),
440 min_label: Default::default(),
441 min_widget: Default::default(),
442 min_widget_wide: Default::default(),
443 blocks: Default::default(),
444 max_left_padding: Default::default(),
445 max_right_padding: Default::default(),
446 left_padding: Default::default(),
447 right_padding: Default::default(),
448 }
449 }
450}
451
452impl<W> LayoutForm<W>
453where
454 W: Eq + Hash + Clone + Debug,
455{
456 pub fn new() -> Self {
457 Self::default()
458 }
459
460 #[inline]
462 pub fn spacing(mut self, spacing: u16) -> Self {
463 self.spacing = spacing;
464 self
465 }
466
467 #[inline]
469 pub fn line_spacing(mut self, spacing: u16) -> Self {
470 self.line_spacing = spacing;
471 self
472 }
473
474 #[inline]
476 pub fn column_spacing(mut self, spacing: u16) -> Self {
477 self.column_spacing = spacing;
478 self
479 }
480
481 pub fn padding(mut self, border: Padding) -> Self {
483 self.page_border = border;
484 self
485 }
486
487 #[deprecated(since = "2.0.0", note = "use padding. is clearer.")]
489 pub fn border(mut self, border: Padding) -> Self {
490 self.page_border = border;
491 self
492 }
493
494 #[inline]
497 pub fn mirror_odd_border(mut self) -> Self {
498 self.mirror_border = true;
499 self
500 }
501
502 pub fn columns(mut self, columns: u8) -> Self {
504 assert_ne!(columns, 0);
505 self.columns = columns as u16;
506 self
507 }
508
509 #[inline]
511 pub fn flex(mut self, flex: Flex) -> Self {
512 self.flex = flex;
513 self
514 }
515
516 pub fn min_label(mut self, width: u16) -> Self {
518 self.min_label = width;
519 self
520 }
521
522 pub fn min_widget(mut self, width: u16) -> Self {
524 self.min_widget = width;
525 self
526 }
527
528 pub fn start(&mut self, block: Option<Block<'static>>) -> BlockTag {
536 let max_idx = self.widgets.len();
537 let padding = block_padding(&block);
538
539 let tag = BlockTag(self.blocks.len());
540 self.blocks.push_back(BlockDef {
541 id: tag,
542 block,
543 padding,
544 constructing: true,
545 range: max_idx..max_idx,
546 area: Rect::default(),
547 });
548
549 self.left_padding += padding.left;
550 self.right_padding += padding.right;
551
552 self.max_left_padding = max(self.max_left_padding, self.left_padding);
553 self.max_right_padding = max(self.max_right_padding, self.right_padding);
554
555 tag
556 }
557
558 pub fn end(&mut self, tag: BlockTag) {
565 let max = self.widgets.len();
566 for cc in self.blocks.iter_mut().rev() {
567 if cc.id == tag && cc.constructing {
568 cc.range.end = max;
569 cc.constructing = false;
570
571 self.left_padding -= cc.padding.left;
573 self.right_padding -= cc.padding.right;
574
575 return;
576 }
577 if cc.constructing {
578 panic!("Unclosed container {:?}", cc.id);
579 }
580 }
581
582 panic!("No open container.");
583 }
584
585 pub fn end_all(&mut self) {
587 let max = self.widgets.len();
588 for cc in self.blocks.iter_mut().rev() {
589 if cc.constructing {
590 cc.range.end = max;
591 cc.constructing = false;
592
593 self.left_padding -= cc.padding.left;
595 self.right_padding -= cc.padding.right;
596 }
597 }
598 }
599
600 pub fn widgets(&mut self, list: impl IntoIterator<Item = (W, FormLabel, FormWidget)>) {
602 for (k, l, w) in list {
603 self.widget(k, l, w);
604 }
605 }
606
607 pub fn widget(&mut self, key: W, label: FormLabel, widget: FormWidget) {
610 let (label, label_str) = match label {
612 FormLabel::Str(s) => {
613 let width = unicode_display_width::width(s) as u16;
614 (FormLabel::Width(width), Some(Cow::Borrowed(s)))
615 }
616 FormLabel::String(s) => {
617 let width = unicode_display_width::width(&s) as u16;
618 (FormLabel::Width(width), Some(Cow::Owned(s)))
619 }
620 FormLabel::Width(w) => (FormLabel::Width(w), None),
621 FormLabel::Size(w, h) => (FormLabel::Size(w, h), None),
622 FormLabel::None => (FormLabel::None, None),
623 };
624
625 let w = match &label {
626 FormLabel::None => 0,
627 FormLabel::Str(_) | FormLabel::String(_) => {
628 unreachable!()
629 }
630 FormLabel::Width(w) => *w,
631 FormLabel::Size(w, _) => *w,
632 };
633 self.min_label = max(self.min_label, w);
634
635 let (w, ww) = match &widget {
636 FormWidget::None => (0, 0),
637 FormWidget::Width(w) => (*w, 0),
638 FormWidget::Size(w, _) => (*w, 0),
639 FormWidget::StretchY(w, _) => (*w, 0),
640 FormWidget::Wide(w, _) => (0, *w),
641 FormWidget::StretchX(w, _) => (*w, 0),
642 FormWidget::WideStretchX(w, _) => (0, *w),
643 FormWidget::StretchXY(w, _) => (*w, 0),
644 FormWidget::WideStretchXY(w, _) => (0, *w),
645 };
646 self.min_widget = max(self.min_widget, w);
647 self.min_widget_wide = max(self.min_widget_wide, ww);
648
649 self.widgets.push(WidgetDef {
650 id: key,
651 label,
652 label_str,
653 widget,
654 });
655 }
656
657 pub fn page_break(&mut self) {
661 self.page_breaks.push(self.widgets.len() - 1);
662 }
663
664 pub fn column_break(&mut self) {
669 self.page_breaks.push(self.widgets.len() - 1);
670 }
671
672 fn validate_containers(&self) {
673 for cc in self.blocks.iter() {
674 if cc.constructing {
675 panic!("Unclosed container {:?}", cc.id);
676 }
677 }
678 }
679
680 #[inline(always)]
682 pub fn build_endless(self, width: u16) -> GenericLayout<W> {
683 self.validate_containers();
684 build_layout::<W, true>(self, Size::new(width, u16::MAX))
685 }
686
687 #[inline(always)]
689 pub fn build_paged(self, page: Size) -> GenericLayout<W> {
690 self.validate_containers();
691 build_layout::<W, false>(self, page)
692 }
693}
694
695impl XPositions {
696 fn new(page: &Page, column: u16, mirror: bool) -> XPositions {
697 let border = if mirror {
698 Padding::new(
699 page.def.page_border.right,
700 page.def.page_border.left,
701 page.def.page_border.top,
702 page.def.page_border.bottom,
703 )
704 } else {
705 page.def.page_border
706 };
707
708 let layout_width = page
709 .def
710 .full_width
711 .saturating_sub(border.left)
712 .saturating_sub(border.right);
713 let n_col_spacers = page.def.columns.saturating_sub(1);
714 let column_width =
715 layout_width.saturating_sub(page.def.column_spacing * n_col_spacers) / page.def.columns;
716 let right_margin = page.def.full_width.saturating_sub(border.right);
717
718 let offset;
719 let label_left;
720 let widget_left;
721 let container_left;
722 let container_right;
723 let widget_right;
724
725 match page.def.flex {
726 Flex::Legacy => {
727 offset = border.left + (column_width + page.def.column_spacing) * column;
728 label_left = page.def.max_left_padding;
729 widget_left = label_left + page.def.max_label + page.def.spacing;
730 widget_right = column_width.saturating_sub(page.def.max_right_padding);
731
732 container_left = 0;
733 container_right = column_width;
734 }
735 Flex::Start => {
736 let single_width = page.def.max_left_padding
737 + page.def.max_label
738 + page.def.spacing
739 + page.def.max_widget
740 + page.def.max_right_padding
741 + page.def.column_spacing;
742
743 offset = border.left + single_width * column;
744 label_left = page.def.max_left_padding;
745 widget_left = label_left + page.def.max_label + page.def.spacing;
746 widget_right = widget_left + page.def.max_widget;
747
748 container_left = 0;
749 container_right = widget_right + page.def.max_right_padding;
750 }
751 Flex::Center => {
752 let single_width = page.def.max_left_padding
753 + page.def.max_label
754 + page.def.spacing
755 + page.def.max_widget
756 + page.def.max_right_padding
757 + page.def.column_spacing;
758 let rest = layout_width
759 .saturating_sub(single_width * page.def.columns)
760 .saturating_add(page.def.column_spacing);
761
762 offset = border.left + rest / 2 + single_width * column;
763 label_left = page.def.max_left_padding;
764 widget_left = label_left + page.def.max_label + page.def.spacing;
765 widget_right = widget_left + page.def.max_widget;
766
767 container_left = 0;
768 container_right = widget_right + page.def.max_right_padding;
769 }
770 Flex::End => {
771 let single_width = page.def.max_left_padding
772 + page.def.max_label
773 + page.def.spacing
774 + page.def.max_widget
775 + page.def.max_right_padding
776 + page.def.column_spacing;
777
778 offset = right_margin
779 .saturating_sub(single_width * (page.def.columns - column))
780 .saturating_add(page.def.column_spacing);
781 label_left = page.def.max_left_padding;
782 widget_left = label_left + page.def.max_label + page.def.spacing;
783 widget_right = widget_left + page.def.max_widget;
784
785 container_left = 0;
786 container_right = widget_right + page.def.max_right_padding;
787 }
788 Flex::SpaceAround => {
789 let single_width = page.def.max_left_padding
790 + page.def.max_label
791 + page.def.spacing
792 + page.def.max_widget
793 + page.def.max_right_padding;
794 let rest = layout_width.saturating_sub(single_width * page.def.columns);
795 let spacing = rest / (page.def.columns + 1);
796
797 offset = border.left + spacing + (single_width + spacing) * column;
798 label_left = page.def.max_left_padding;
799 widget_left = label_left + page.def.max_label + page.def.spacing;
800 widget_right = widget_left + page.def.max_widget;
801
802 container_left = 0;
803 container_right = widget_right + page.def.max_right_padding;
804 }
805 Flex::SpaceBetween => {
806 let single_width = page.def.max_left_padding
807 + page.def.max_label
808 + page.def.max_widget
809 + page.def.max_right_padding;
810 let rest = layout_width.saturating_sub(single_width * page.def.columns);
811 let spacing = if page.def.columns > 1 {
812 rest / (page.def.columns - 1)
813 } else {
814 0
815 };
816
817 offset = border.left + (single_width + spacing) * column;
818 label_left = page.def.max_left_padding;
819 widget_left = label_left + page.def.max_label + page.def.spacing;
820 widget_right = widget_left + page.def.max_widget;
821
822 container_left = 0;
823 container_right = widget_right + page.def.max_right_padding;
824 }
825 }
826
827 XPositions {
828 label_left: offset + label_left,
829 label_width: page.def.max_label,
830 widget_left: offset + widget_left,
831 widget_width: page.def.max_widget,
832 widget_right: offset + widget_right,
833 container_left: offset + container_left,
834 container_right: offset + container_right,
835 total_width: widget_right - label_left,
836 }
837 }
838}
839
840impl Page {
841 fn adjusted_widths<W>(layout: &LayoutForm<W>, page_size: Size) -> (u16, u16, u16)
842 where
843 W: Eq + Hash + Clone + Debug,
844 {
845 let layout_width = page_size
846 .width
847 .saturating_sub(layout.page_border.left)
848 .saturating_sub(layout.page_border.right);
849 let n_col_spacers = layout.columns.saturating_sub(1);
850 let column_width =
851 layout_width.saturating_sub(layout.column_spacing * n_col_spacers) / layout.columns;
852
853 let mut max_label = layout.min_label;
854 let mut max_widget = max(
855 layout.min_widget,
856 layout
857 .min_widget_wide
858 .saturating_sub(layout.min_label)
859 .saturating_sub(layout.spacing),
860 );
861 let mut spacing = layout.spacing;
862
863 let nominal =
864 layout.max_left_padding + max_label + spacing + max_widget + layout.max_right_padding;
865
866 if nominal > column_width {
867 let mut reduce = nominal - column_width;
868
869 if spacing > reduce {
870 spacing -= reduce;
871 reduce = 0;
872 } else {
873 reduce -= spacing;
874 spacing = 0;
875 }
876 if max_label > 5 {
877 if max_label - 5 > reduce {
878 max_label -= reduce;
879 reduce = 0;
880 } else {
881 reduce -= max_label - 5;
882 max_label = 5;
883 }
884 }
885 if max_widget > 5 {
886 if max_widget - 5 > reduce {
887 max_widget -= reduce;
888 reduce = 0;
889 } else {
890 reduce -= max_widget - 5;
891 max_widget = 5;
892 }
893 }
894 if max_label > reduce {
895 max_label -= reduce;
896 reduce = 0;
897 } else {
898 reduce -= max_label;
899 max_label = 0;
900 }
901 if max_widget > reduce {
902 max_widget -= reduce;
903 } else {
905 max_widget = 0;
907 }
908 }
909
910 (max_label, spacing, max_widget)
911 }
912
913 fn new<W>(layout: &LayoutForm<W>, page_size: Size) -> Self
914 where
915 W: Eq + Hash + Clone + Debug,
916 {
917 let (max_label, spacing, max_widget) = Self::adjusted_widths(layout, page_size);
918
919 let def = PageDef {
920 page_border: layout.page_border,
921 full_width: page_size.width,
922 flex: layout.flex,
923 max_left_padding: layout.max_left_padding,
924 max_right_padding: layout.max_right_padding,
925 max_label,
926 max_widget,
927 width: page_size.width,
928 height: page_size.height,
929 top: layout.page_border.top,
930 bottom: layout.page_border.bottom,
931 columns: layout.columns,
932 column_spacing: layout.column_spacing,
933 spacing,
934 line_spacing: layout.line_spacing,
935 };
936 let mut s = Page {
937 def: Rc::new(def),
938 page_no: 0,
939 page_start: 0,
940 page_end: page_size.height.saturating_sub(layout.page_border.bottom),
941 y: layout.page_border.top,
942 top_padding: 0,
943 bottom_padding: 0,
944 bottom_padding_break: 0,
945 effective_line_spacing: 0,
946 x_pos: Default::default(),
947 };
948 s.x_pos = XPositions::new(&s, 0, false);
949 s
950 }
951}
952
953fn adjust_blocks<W>(layout: &mut LayoutForm<W>, page_height: u16)
955where
956 W: Eq + Hash + Clone + Debug,
957{
958 if page_height == u16::MAX {
959 return;
960 }
961
962 if page_height < 3 {
963 for block_def in layout.blocks.iter_mut() {
964 if let Some(block) = block_def.block.as_mut() {
965 let padding = block_padding2(block);
966 let borders = if padding.left > 0 {
967 Borders::LEFT
968 } else {
969 Borders::NONE
970 } | if padding.right > 0 {
971 Borders::RIGHT
972 } else {
973 Borders::NONE
974 };
975
976 *block = mem::take(block).borders(borders);
977 block_def.padding.top = 0;
978 block_def.padding.bottom = 0;
979 }
980 }
981 }
982}
983
984fn build_layout<W, const ENDLESS: bool>(
986 mut layout: LayoutForm<W>,
987 page_size: Size,
988) -> GenericLayout<W>
989where
990 W: Eq + Hash + Clone + Debug,
991{
992 let mut gen_layout = GenericLayout::with_capacity(
993 layout.widgets.len(), layout.blocks.len() * 2,
995 );
996 gen_layout.set_page_size(page_size);
997
998 adjust_blocks(&mut layout, page_size.height);
1000
1001 let mut stretch = Vec::with_capacity(layout.widgets.len());
1003 let mut blocks_out = Vec::with_capacity(layout.blocks.len());
1004
1005 let mut saved_page;
1006 let mut page = Page::new(&layout, page_size);
1007
1008 for (idx, widget) in layout.widgets.iter_mut().enumerate() {
1009 saved_page = page.clone();
1011
1012 let mut label_area;
1013 let mut widget_area;
1014
1015 (label_area, widget_area) = next_widget(&mut page, &mut layout.blocks, widget, idx, false);
1016 next_blocks(&mut page, &mut layout.blocks, idx, &mut blocks_out);
1017
1018 if !ENDLESS && page.y.saturating_add(page.bottom_padding_break) > page.page_end {
1020 page = saved_page;
1022
1023 blocks_out.clear();
1025 page_break_blocks(&mut page, &mut layout.blocks, idx, &mut blocks_out);
1026 push_blocks(&mut blocks_out, &mut gen_layout);
1027 adjust_y_stretch(&page, &mut stretch, &mut gen_layout);
1028 page_break::<ENDLESS>(&mut page);
1029 assert!(stretch.is_empty());
1030
1031 (label_area, widget_area) =
1033 next_widget(&mut page, &mut layout.blocks, widget, idx, true);
1034 next_blocks(&mut page, &mut layout.blocks, idx, &mut blocks_out);
1035 }
1036
1037 if !ENDLESS && widget.widget.is_stretch_y() {
1039 stretch.push(gen_layout.widget_len());
1040 }
1041
1042 gen_layout.add(
1044 widget.id.clone(),
1045 widget_area,
1046 widget.label_str.take(),
1047 label_area,
1048 );
1049
1050 push_blocks(&mut blocks_out, &mut gen_layout);
1051
1052 if layout.page_breaks.contains(&idx) {
1054 assert!(blocks_out.is_empty());
1055 page_break_blocks(&mut page, &mut layout.blocks, idx + 1, &mut blocks_out);
1056 push_blocks(&mut blocks_out, &mut gen_layout);
1057 if !ENDLESS {
1058 adjust_y_stretch(&page, &mut stretch, &mut gen_layout);
1059 }
1060 page_break::<ENDLESS>(&mut page);
1061 assert!(stretch.is_empty());
1062 }
1063
1064 drop_blocks(&mut layout.blocks, idx);
1065 assert!(blocks_out.is_empty());
1066 }
1067
1068 adjust_y_stretch(&page, &mut stretch, &mut gen_layout);
1070
1071 gen_layout.set_page_count(((page.page_no + page.def.columns) / page.def.columns) as usize);
1072 gen_layout
1073}
1074
1075fn drop_blocks(_block_def: &mut VecDeque<BlockDef>, _idx: usize) {
1078 }
1091
1092fn page_break_blocks(
1093 page: &mut Page,
1094 block_def: &mut VecDeque<BlockDef>,
1095 idx: usize,
1096 blocks_out: &mut Vec<BlockOut>,
1097) {
1098 for block in block_def.iter_mut().rev() {
1101 if idx > block.range.start && idx < block.range.end {
1102 end_block(page, block);
1103 blocks_out.push(block.as_out());
1104
1105 block.range.start = idx;
1107 }
1108 }
1112}
1113
1114fn page_break<const ENDLESS: bool>(page: &mut Page) {
1116 page.page_no += 1;
1118
1119 let column = page.page_no % page.def.columns;
1120 let mirror = (page.page_no / page.def.columns) % 2 == 1;
1121
1122 if !ENDLESS {
1123 page.page_start = (page.page_no / page.def.columns).saturating_mul(page.def.height);
1124 page.page_end = page
1125 .page_start
1126 .saturating_add(page.def.height.saturating_sub(page.def.bottom));
1127 }
1128
1129 page.x_pos = XPositions::new(page, column, mirror);
1130 page.y = page.page_start.saturating_add(page.def.top);
1131
1132 page.effective_line_spacing = 0;
1133 page.top_padding = 0;
1134 page.bottom_padding = 0;
1135 page.bottom_padding_break = 0;
1136}
1137
1138fn next_widget<W>(
1140 page: &mut Page,
1141 block_def: &mut VecDeque<BlockDef>,
1142 widget: &WidgetDef<W>,
1143 idx: usize,
1144 must_fit: bool,
1145) -> (Rect, Rect)
1146where
1147 W: Eq + Hash + Clone + Debug,
1148{
1149 page.y = page.y.saturating_add(page.effective_line_spacing);
1151
1152 page.effective_line_spacing = page.def.line_spacing;
1153 page.top_padding = 0;
1154 page.bottom_padding = 0;
1155 page.bottom_padding_break = 0;
1156
1157 for block in block_def.iter_mut() {
1159 if block.range.start == idx {
1160 start_block(page, block);
1161 }
1162 if block.range.start <= idx {
1163 widget_padding(page, idx, block);
1164 }
1165 }
1169
1170 let (label_area, widget_area, advance) = areas_and_advance(page, widget, must_fit);
1172
1173 page.y = page.y.saturating_add(advance);
1174
1175 (label_area, widget_area)
1176}
1177
1178fn start_block(page: &mut Page, block: &mut BlockDef) {
1180 block.area.x = page.x_pos.container_left;
1182 block.area.width = page
1183 .x_pos
1184 .container_right
1185 .saturating_sub(page.x_pos.container_left);
1186 block.area.y = page.y;
1187
1188 page.y = page.y.saturating_add(block.padding.top);
1190 page.top_padding += block.padding.top;
1191 page.x_pos.container_left = page.x_pos.container_left.saturating_add(block.padding.left);
1192 page.x_pos.container_right = page
1193 .x_pos
1194 .container_right
1195 .saturating_sub(block.padding.right);
1196}
1197
1198fn widget_padding(page: &mut Page, idx: usize, block: &mut BlockDef) {
1199 if block.range.end > idx + 1 {
1200 page.bottom_padding_break += block.padding.bottom;
1201 } else if block.range.end == idx + 1 {
1202 page.bottom_padding += block.padding.bottom;
1203 }
1204}
1205
1206fn next_blocks(
1207 page: &mut Page,
1208 block_def: &mut VecDeque<BlockDef>,
1209 idx: usize,
1210 blocks_out: &mut Vec<BlockOut>,
1211) {
1212 for block in block_def.iter_mut().rev() {
1215 if idx + 1 == block.range.end {
1216 end_block(page, block);
1217 blocks_out.push(block.as_out());
1218 }
1219 }
1223}
1224
1225fn push_blocks<W: Eq + Hash + Clone>(
1226 blocks_out: &mut Vec<BlockOut>,
1227 gen_layout: &mut GenericLayout<W>,
1228) {
1229 while let Some(cc) = blocks_out.pop() {
1230 gen_layout.add_block(cc.area, cc.block);
1231 }
1232}
1233
1234fn end_block(page: &mut Page, block: &mut BlockDef) {
1236 page.y = page.y.saturating_add(block.padding.bottom);
1238 page.x_pos.container_left = page.x_pos.container_left.saturating_sub(block.padding.left);
1239 page.x_pos.container_right = page
1240 .x_pos
1241 .container_right
1242 .saturating_add(block.padding.right);
1243
1244 block.area.height = page.y.saturating_sub(block.area.y);
1246}
1247
1248fn areas_and_advance<W: Debug + Clone>(
1251 page: &Page,
1252 widget: &WidgetDef<W>,
1253 must_fit: bool,
1254) -> (Rect, Rect, u16) {
1255 let stacked = matches!(
1260 widget.widget,
1261 FormWidget::Wide(_, _) | FormWidget::WideStretchX(_, _) | FormWidget::WideStretchXY(_, _)
1262 );
1263
1264 let mut label_height = match &widget.label {
1265 FormLabel::None => 0,
1266 FormLabel::Str(_) | FormLabel::String(_) => unreachable!(),
1267 FormLabel::Width(_) => 1,
1268 FormLabel::Size(_, h) => *h,
1269 };
1270
1271 let mut widget_height = match &widget.widget {
1272 FormWidget::None => 0,
1273 FormWidget::Width(_) => 1,
1274 FormWidget::Size(_, h) => *h,
1275 FormWidget::StretchY(_, h) => *h,
1276 FormWidget::Wide(_, h) => *h,
1277 FormWidget::StretchX(_, h) => *h,
1278 FormWidget::WideStretchX(_, h) => *h,
1279 FormWidget::StretchXY(_, h) => *h,
1280 FormWidget::WideStretchXY(_, h) => *h,
1281 };
1282
1283 let stretch_width = page
1284 .x_pos
1285 .widget_right
1286 .saturating_sub(page.x_pos.widget_left);
1287 let total_stretch_width = page
1288 .x_pos
1289 .widget_right
1290 .saturating_sub(page.x_pos.label_left);
1291
1292 let max_height = if !must_fit {
1293 page.def
1294 .height
1295 .saturating_sub(page.def.top)
1296 .saturating_sub(page.def.bottom)
1297 .saturating_sub(page.top_padding)
1298 .saturating_sub(page.bottom_padding)
1299 } else {
1300 page.def
1301 .height
1302 .saturating_sub(page.y - page.page_start)
1303 .saturating_sub(page.def.bottom)
1304 .saturating_sub(page.bottom_padding_break)
1305 };
1306
1307 if stacked {
1308 if label_height + widget_height > max_height {
1309 label_height = max(1, max_height.saturating_sub(widget_height));
1310 }
1311 if label_height + widget_height > max_height {
1312 widget_height = max(1, max_height.saturating_sub(label_height));
1313 }
1314 if label_height + widget_height > max_height {
1315 label_height = 0;
1316 }
1317 if label_height + widget_height > max_height {
1318 widget_height = max_height;
1319 }
1320
1321 let mut label_area = match &widget.label {
1322 FormLabel::None => Rect::new(
1323 page.x_pos.label_left, page.y,
1325 0,
1326 0,
1327 ),
1328 FormLabel::Str(_) | FormLabel::String(_) => unreachable!(),
1329 FormLabel::Width(_) => Rect::new(
1330 page.x_pos.label_left,
1331 page.y,
1332 page.x_pos.label_width,
1333 label_height,
1334 ),
1335 FormLabel::Size(_, _) => Rect::new(
1336 page.x_pos.label_left,
1337 page.y,
1338 page.x_pos.label_width,
1339 label_height,
1340 ),
1341 };
1342 match &widget.widget {
1343 FormWidget::Wide(_, _) => label_area.width = page.x_pos.total_width,
1344 FormWidget::WideStretchX(_, _) => label_area.width = total_stretch_width,
1345 FormWidget::WideStretchXY(_, _) => label_area.width = total_stretch_width,
1346 _ => {}
1347 }
1348
1349 let widget_area = match &widget.widget {
1350 FormWidget::None => unreachable!(),
1351 FormWidget::Width(_) => unreachable!(),
1352 FormWidget::Size(_, _) => unreachable!(),
1353 FormWidget::StretchY(_, _) => unreachable!(),
1354 FormWidget::Wide(w, _) => Rect::new(
1355 page.x_pos.label_left,
1356 page.y + label_height,
1357 min(*w, page.x_pos.total_width),
1358 widget_height,
1359 ),
1360 FormWidget::StretchX(_, _) => unreachable!(),
1361 FormWidget::WideStretchX(_, _) => Rect::new(
1362 page.x_pos.label_left,
1363 page.y + label_height,
1364 total_stretch_width,
1365 widget_height,
1366 ),
1367 FormWidget::StretchXY(_, _) => unreachable!(),
1368 FormWidget::WideStretchXY(_, _) => Rect::new(
1369 page.x_pos.label_left,
1370 page.y + label_height,
1371 total_stretch_width,
1372 widget_height,
1373 ),
1374 };
1375
1376 (
1377 label_area,
1378 widget_area,
1379 label_area.height + widget_area.height,
1380 )
1381 } else {
1382 label_height = min(label_height, max_height);
1383 widget_height = min(widget_height, max_height);
1384 let height = max(label_height, widget_height);
1385
1386 let label_area = match &widget.label {
1387 FormLabel::None => Rect::new(
1388 page.x_pos.label_left, page.y,
1390 0,
1391 0,
1392 ),
1393 FormLabel::Str(_) | FormLabel::String(_) => unreachable!(),
1394 FormLabel::Width(_) => Rect::new(
1395 page.x_pos.label_left,
1396 page.y,
1397 page.x_pos.label_width,
1398 height,
1399 ),
1400 FormLabel::Size(_, _) => Rect::new(
1401 page.x_pos.label_left,
1402 page.y,
1403 page.x_pos.label_width,
1404 height,
1405 ),
1406 };
1407
1408 let widget_area = match &widget.widget {
1409 FormWidget::None => Rect::default(),
1410 FormWidget::Width(w) => Rect::new(
1411 page.x_pos.widget_left,
1412 page.y,
1413 min(*w, page.x_pos.widget_width),
1414 height,
1415 ),
1416 FormWidget::Size(w, _) => Rect::new(
1417 page.x_pos.widget_left,
1418 page.y,
1419 min(*w, page.x_pos.widget_width),
1420 height,
1421 ),
1422 FormWidget::StretchY(w, _) => Rect::new(
1423 page.x_pos.widget_left,
1424 page.y,
1425 min(*w, page.x_pos.widget_width),
1426 height,
1427 ),
1428 FormWidget::Wide(_, _) => unreachable!(),
1429 FormWidget::StretchX(_, _) => Rect::new(
1430 page.x_pos.widget_left, page.y,
1432 stretch_width,
1433 height,
1434 ),
1435 FormWidget::WideStretchX(_, _) => unreachable!(),
1436 FormWidget::StretchXY(_, _) => Rect::new(
1437 page.x_pos.widget_left, page.y,
1439 stretch_width,
1440 height,
1441 ),
1442 FormWidget::WideStretchXY(_, _) => unreachable!(),
1443 };
1444
1445 (
1446 label_area,
1447 widget_area,
1448 max(label_area.height, widget_area.height),
1449 )
1450 }
1451}
1452
1453fn adjust_y_stretch<W: Eq + Hash + Clone>(
1456 page: &Page,
1457 stretch_y: &mut Vec<usize>,
1458 gen_layout: &mut GenericLayout<W>,
1459) {
1460 let mut remainder = page.page_end.saturating_sub(page.y);
1461 if remainder == 0 {
1462 stretch_y.clear();
1463 return;
1464 }
1465
1466 let mut n = stretch_y.len() as u16;
1467 for y_idx in stretch_y.drain(..) {
1468 let stretch = remainder / n;
1471 remainder -= stretch;
1472 n -= 1;
1473
1474 let mut area = gen_layout.widget(y_idx);
1476 let test_y = area.bottom();
1477 let test_x = page.x_pos.container_left;
1478
1479 area.height += stretch;
1480 gen_layout.set_widget(y_idx, area);
1481
1482 for idx in y_idx + 1..gen_layout.widget_len() {
1484 let mut area = gen_layout.widget(idx);
1485 if area.y >= test_y {
1486 area.y += stretch;
1487 }
1488 gen_layout.set_widget(idx, area);
1489
1490 let mut area = gen_layout.label(idx);
1491 if area.y >= test_y {
1492 area.y += stretch;
1493 }
1494 gen_layout.set_label(idx, area);
1495 }
1496
1497 for idx in 0..gen_layout.block_len() {
1499 let mut area = gen_layout.block_area(idx);
1500 if area.x >= test_x && area.y >= test_y {
1501 area.y += stretch;
1502 }
1503 if area.x >= test_x && area.y <= test_y && area.bottom() > test_y {
1505 area.height += stretch;
1506 }
1507 gen_layout.set_block_area(idx, area);
1508 }
1509 }
1510}