omp_tui/components/
col.rs1use super::layout::{stack_height, stack_measure, stack_place};
2use crate::{
3 component::{Cached, Component, IntoChildren, PaintCtx, ResizeTail, Slot, next_slot},
4 context::UiContext,
5 frame::Rect,
6 props::{Prop, PropValue, Props},
7};
8
9pub struct Col {
11 props: Props,
12 slot: Slot,
13 children: Vec<Cached>,
14}
15
16impl Col {
17 pub fn new() -> Self {
19 Self { props: Props::new(), slot: next_slot(), children: Vec::new() }
20 }
21
22 pub fn with(mut self, prop: Prop, value: impl Into<PropValue>) -> Self {
24 self.props.set(prop, value);
25 self
26 }
27
28 pub fn with_str(mut self, prop: Prop, value: &str) -> Self {
30 self.props.set(prop, value);
31 self
32 }
33
34 pub fn child(mut self, children: impl IntoChildren) -> Self {
36 children.extend_children(&mut self.children);
37 self
38 }
39}
40
41impl Default for Col {
42 fn default() -> Self {
43 Self::new()
44 }
45}
46
47impl Component for Col {
48 fn props(&self) -> &Props {
49 &self.props
50 }
51
52 fn props_mut(&mut self) -> &mut Props {
53 &mut self.props
54 }
55
56 fn slot(&self) -> Slot {
57 self.slot
58 }
59
60 fn children(&self) -> &[Cached] {
61 &self.children
62 }
63
64 fn children_mut(&mut self) -> &mut [Cached] {
65 &mut self.children
66 }
67
68 fn resize_tail(&mut self) -> Option<ResizeTail<'_>> {
69 if self.props.border().is_some()
73 || self.props.valign().is_some()
74 || self.props.get(Prop::Bg).is_some()
75 || self.props.get(Prop::On).is_some()
76 {
77 return None;
78 }
79 Some(ResizeTail { children: &mut self.children, gap: self.props.gap() })
80 }
81
82 fn measure(&mut self, ctx: &UiContext) -> (u16, u16) {
83 stack_measure(ctx, &mut self.children)
84 }
85
86 fn height(&mut self, ctx: &UiContext, width: u16) -> u16 {
87 stack_height(ctx, &mut self.children, width, self.props.gap())
88 }
89
90 fn place(&mut self, ctx: &UiContext, content: Rect) {
91 stack_place(
92 ctx,
93 &mut self.children,
94 content,
95 self.props.gap(),
96 self.props.valign(),
97 self.props.align(),
98 );
99 }
100
101 fn paint(&mut self, pc: &mut PaintCtx<'_>, _rect: Rect) {
102 for child in self.children.iter_mut().filter(|child| child.visible) {
103 child.paint(pc);
104 }
105 }
106}
107
108#[cfg(test)]
109mod tests {
110 use super::Col;
111 use crate::{
112 component::{Cached, PaintCtx},
113 components::TextLeaf,
114 context::UiContext,
115 frame::{Frame, Rect, Size},
116 props::Prop,
117 test_support::frame_row_text,
118 };
119
120 #[test]
121 fn stacks_children_with_gap() {
122 let ctx = UiContext::default();
123 let mut root = Cached::new(Box::new(
124 Col::new()
125 .with(Prop::Gap, 1_u16)
126 .child(TextLeaf::new().text("first"))
127 .child(TextLeaf::new().text("second")),
128 ));
129 let height = root.height(&ctx, 12);
130 assert_eq!(height, 3);
131 root.place(&ctx, Rect::new(0, 0, 12, height));
132 let mut frame = Frame::new(Size::new(12, height));
133 let mut hits = Vec::new();
134 root.paint(&mut PaintCtx::new(&mut frame, &ctx, &mut hits, &mut Vec::new()));
135 assert_eq!(frame_row_text(&frame, 0), "first");
136 assert_eq!(frame_row_text(&frame, 1), "");
137 assert_eq!(frame_row_text(&frame, 2), "second");
138 }
139}