widget_usage/
widget_usage.rs1use minui::prelude::*;
17
18fn main() -> minui::Result<()> {
19 let mut app = App::new(())?;
20
21 app.run(
22 |_state, event| {
23 match event {
25 Event::KeyWithModifiers(k) if matches!(k.key, KeyKind::Char('q')) => false,
26 Event::Character('q') => false,
27 _ => true,
28 }
29 },
30 |_state, window| {
31 let (w, h) = window.get_size();
32 create_app_layout(w, h).draw(window)?;
33 window.flush()?;
34 Ok(())
35 },
36 )?;
37
38 Ok(())
39}
40
41fn create_app_layout(term_w: u16, term_h: u16) -> Container {
42 use minui::widgets::ContainerPadding;
44
45 let root = Container::new()
48 .with_position_and_size(0, 0, term_w, term_h)
49 .with_layout_direction(LayoutDirection::Vertical)
50 .with_row_gap(Gap::Pixels(1))
51 .with_padding(ContainerPadding::uniform(1));
52
53 let header_h: u16 = 3;
55 let header = Container::new()
56 .with_position_and_size(0, 0, term_w.saturating_sub(2), header_h)
57 .with_layout_direction(LayoutDirection::Vertical)
58 .with_border()
59 .with_border_chars(BorderChars::double_line())
60 .with_border_color(ColorPair::new(Color::LightBlue, Color::Black))
61 .with_title("MinUI Widget Demo")
62 .with_title_alignment(TitleAlignment::Center)
63 .with_padding(ContainerPadding::symmetric(0, 1))
64 .add_child(Label::new("Press 'q' to quit").with_text_color(Color::Cyan));
65
66 let footer_h: u16 = 3;
68 let footer = Container::new()
69 .with_position_and_size(0, 0, term_w.saturating_sub(2), footer_h)
70 .with_layout_direction(LayoutDirection::Vertical)
71 .with_border()
72 .with_border_chars(BorderChars::single_line())
73 .with_border_color(ColorPair::new(Color::Yellow, Color::Black))
74 .with_padding(ContainerPadding::symmetric(0, 1))
75 .add_child(Label::new("Status: Ready • Press 'q' to quit").with_text_color(Color::Yellow));
76
77 let body_h = term_h
80 .saturating_sub(1) .saturating_sub(1) .saturating_sub(header_h)
83 .saturating_sub(1) .saturating_sub(footer_h)
85 .saturating_sub(1); let body = Container::new()
88 .with_position_and_size(0, 0, term_w.saturating_sub(2), body_h)
89 .with_layout_direction(LayoutDirection::Horizontal)
90 .with_column_gap(Gap::Pixels(2))
91 .with_padding(ContainerPadding::uniform(0));
92
93 let panel_w = (term_w.saturating_sub(2))
96 .saturating_sub(2) / 2;
98 let panel_h = body_h;
99
100 let text_w = panel_w.saturating_sub(4).max(1);
102 let text_h = panel_h.saturating_sub(4).max(1);
103
104 let left_panel = Container::new()
105 .with_position_and_size(0, 0, panel_w, panel_h)
106 .with_layout_direction(LayoutDirection::Vertical)
107 .with_border()
108 .with_border_chars(BorderChars::single_line())
109 .with_border_color(ColorPair::new(Color::Red, Color::Black))
110 .with_title("Left")
111 .with_padding(ContainerPadding::uniform(1))
112 .add_child(
113 TextBlock::new(
114 text_w,
115 text_h,
116 "This demonstrates how Containers can be arranged side-by-side. \
117 They support borders, titles, padding, and child layout. \
118 Resize the terminal to see how clipping behaves.",
119 )
120 .with_word_wrap(),
121 );
122
123 let right_panel = Container::new()
124 .with_position_and_size(0, 0, panel_w, panel_h)
125 .with_layout_direction(LayoutDirection::Vertical)
126 .with_border()
127 .with_border_chars(BorderChars::single_line())
128 .with_border_color(ColorPair::new(Color::Green, Color::Black))
129 .with_title("Right")
130 .with_padding(ContainerPadding::uniform(1))
131 .add_child(
132 TextBlock::new(
133 text_w,
134 text_h,
135 "Multiple widgets can coexist inside Container layouts. \
136 Each Container manages styling, while children provide content. \
137 This text is wrapped using TextBlock.",
138 )
139 .with_word_wrap(),
140 );
141
142 let body = body.add_child(left_panel).add_child(right_panel);
143
144 root.add_child(header).add_child(body).add_child(footer)
145}