Skip to main content

13_split_panes/
13_split_panes.rs

1//! Example 13: Split Panes
2//!
3//! Demonstrates the Split widget for creating resizable panel layouts.
4//!
5//! Run with: cargo run -p telex-tui --example 13_split_panes
6
7use crossterm::event::KeyCode;
8use crossterm::style::Color;
9use telex::prelude::*;
10
11telex::require_api!(0, 2);
12
13fn main() {
14    telex::run_with_theme(App, telex::theme::Theme::nord()).unwrap();
15}
16
17struct App;
18
19impl Component for App {
20    fn render(&self, cx: Scope) -> View {
21        let show_help = state!(cx, || false);
22
23        // F1 toggles help
24        cx.use_command(
25            KeyBinding::key(KeyCode::F(1)),
26            with!(show_help => move || show_help.update(|v| *v = !*v)),
27        );
28
29        let selected_item = state!(cx, || 0usize);
30
31        let items = vec![
32            "README.md".to_string(),
33            "Cargo.toml".to_string(),
34            "src/".to_string(),
35            "src/main.rs".to_string(),
36            "src/lib.rs".to_string(),
37            "tests/".to_string(),
38        ];
39
40        let on_select = with!(selected_item => move |idx: usize| {
41            selected_item.set(idx);
42        });
43
44        let detail_text = match selected_item.get() {
45            0 => "# README\n\nThis is a demo of split panes.\n\nThe left panel shows a file list,\nthe right panel shows details.",
46            1 => "[package]\nname = \"demo\"\nversion = \"0.1.0\"\nedition = \"2021\"",
47            2 => "Directory: src/\n\nContains the main source files.",
48            3 => "fn main() {\n    println!(\"Hello, world!\");\n}",
49            4 => "pub mod utils;\npub mod widgets;",
50            5 => "Directory: tests/\n\nContains integration tests.",
51            _ => "Select an item to see details.",
52        };
53
54        // Horizontal split: file list on left, details on right
55        View::vstack()
56            .child(
57                View::boxed()
58                    .flex(1)
59                    .child(
60                        View::split()
61                            .horizontal()
62                            .ratio(0.3)
63                            .min_first(15)
64                            .first(
65                                View::vstack()
66                                    .child(
67                                        View::styled_text("Files")
68                                            .color(Color::Cyan)
69                                            .bold()
70                                            .build(),
71                                    )
72                                    .child(
73                                        View::list()
74                                            .items(items)
75                                            .selected(selected_item.get())
76                                            .on_select(on_select)
77                                            .build(),
78                                    )
79                                    .child(View::gap(1))
80                                    .build(),
81                            )
82                            .second(
83                                View::vstack()
84                                    .child(
85                                        View::styled_text("Details")
86                                            .color(Color::Green)
87                                            .bold()
88                                            .build(),
89                                    )
90                                    .child(
91                                        View::boxed()
92                                            .border(true)
93                                            .flex(1)
94                                            .child(View::text(detail_text))
95                                            .build(),
96                                    )
97                                    .build(),
98                            )
99                            .build(),
100                    )
101                    .build(),
102            )
103            .child(
104                View::styled_text("↑↓: select file | F1 help | Ctrl+Q: quit")
105                    .dim()
106                    .build(),
107            )
108            .child(
109                View::modal()
110                    .visible(show_help.get())
111                    .title("Example 13: Split Panes")
112                    .on_dismiss(with!(show_help => move || show_help.set(false)))
113                    .child(
114                        View::vstack()
115                            .child(View::styled_text("What you're seeing").bold().build())
116                            .child(View::text("• Horizontal split: file list / details"))
117                            .child(View::text("• ratio(0.3) = 30% left, 70% right"))
118                            .child(View::text("• min_first(15) sets minimum pane width"))
119                            .child(View::gap(1))
120                            .child(View::styled_text("Key concepts").bold().build())
121                            .child(View::text("• View::split() creates resizable panes"))
122                            .child(View::text("• .horizontal() or .vertical() orientation"))
123                            .child(View::text("• .first() and .second() set pane content"))
124                            .child(View::text("• Splits can be nested"))
125                            .child(View::gap(1))
126                            .child(View::styled_text("Try this").bold().build())
127                            .child(View::text("• Select different files to see details"))
128                            .child(View::text("• Resize terminal to see layout adapt"))
129                            .child(View::gap(1))
130                            .child(View::styled_text("Next up").bold().build())
131                            .child(View::text("→ 14_tabs: tabbed interfaces"))
132                            .child(View::gap(1))
133                            .child(View::styled_text("Press Escape to close").dim().build())
134                            .build(),
135                    )
136                    .build(),
137            )
138            .build()
139    }
140}