par_term/
help_ui.rs

1use crate::config::Config;
2use egui::{Color32, Context, Frame, RichText, Window, epaint::Shadow};
3use std::cell::Cell;
4
5/// Help UI manager using egui
6pub struct HelpUI {
7    /// Whether the help window is currently visible
8    pub visible: bool,
9}
10
11impl HelpUI {
12    /// Create a new help UI
13    pub fn new() -> Self {
14        Self { visible: false }
15    }
16
17    /// Toggle help window visibility
18    pub fn toggle(&mut self) {
19        self.visible = !self.visible;
20    }
21
22    /// Show the help window
23    pub fn show(&mut self, ctx: &Context) {
24        if !self.visible {
25            return;
26        }
27
28        // Ensure help panel is fully opaque regardless of terminal opacity
29        let mut style = (*ctx.style()).clone();
30        let solid_bg = Color32::from_rgba_unmultiplied(24, 24, 24, 255);
31        style.visuals.window_fill = solid_bg;
32        style.visuals.panel_fill = solid_bg;
33        style.visuals.widgets.noninteractive.bg_fill = solid_bg;
34        ctx.set_style(style);
35
36        let mut open = true;
37        let close_requested = Cell::new(false);
38
39        let viewport = ctx.input(|i| i.viewport_rect());
40        Window::new("Help")
41            .resizable(true)
42            .default_width(550.0)
43            .default_height(600.0)
44            .default_pos(viewport.center())
45            .pivot(egui::Align2::CENTER_CENTER)
46            .open(&mut open)
47            .frame(
48                Frame::window(&ctx.style())
49                    .fill(solid_bg)
50                    .stroke(egui::Stroke::NONE)
51                    .shadow(Shadow {
52                        offset: [0, 0],
53                        blur: 0,
54                        spread: 0,
55                        color: Color32::TRANSPARENT,
56                    }),
57            )
58            .show(ctx, |ui| {
59                egui::ScrollArea::vertical().show(ui, |ui| {
60                    // About Section
61                    ui.heading("About par-term");
62                    ui.separator();
63
64                    ui.horizontal(|ui| {
65                        ui.label("Version:");
66                        ui.label(RichText::new(env!("CARGO_PKG_VERSION")).strong());
67                    });
68
69                    ui.add_space(4.0);
70                    ui.label(env!("CARGO_PKG_DESCRIPTION"));
71
72                    ui.add_space(4.0);
73                    ui.horizontal(|ui| {
74                        ui.label("Author:");
75                        ui.label(env!("CARGO_PKG_AUTHORS"));
76                    });
77
78                    ui.horizontal(|ui| {
79                        ui.label("License:");
80                        ui.label(env!("CARGO_PKG_LICENSE"));
81                    });
82
83                    ui.horizontal(|ui| {
84                        ui.label("Repository:");
85                        ui.hyperlink_to(
86                            env!("CARGO_PKG_REPOSITORY"),
87                            env!("CARGO_PKG_REPOSITORY"),
88                        );
89                    });
90
91                    ui.add_space(12.0);
92
93                    // Configuration Paths Section
94                    ui.heading("Configuration Paths");
95                    ui.separator();
96
97                    let config_path = Config::config_path();
98                    let shaders_dir = Config::shaders_dir();
99
100                    ui.horizontal(|ui| {
101                        ui.label("Config file:");
102                        ui.label(RichText::new(config_path.display().to_string()).monospace());
103                    });
104
105                    ui.horizontal(|ui| {
106                        ui.label("Shaders folder:");
107                        ui.label(RichText::new(shaders_dir.display().to_string()).monospace());
108                    });
109
110                    ui.add_space(12.0);
111
112                    // Keyboard Shortcuts Section
113                    ui.heading("Keyboard Shortcuts");
114                    ui.separator();
115
116                    // Use a grid for clean alignment
117                    egui::Grid::new("shortcuts_grid")
118                        .num_columns(2)
119                        .spacing([20.0, 4.0])
120                        .striped(true)
121                        .show(ui, |ui| {
122                            // Navigation
123                            ui.label(RichText::new("Navigation").strong().underline());
124                            ui.end_row();
125
126                            shortcut_row(ui, "PageUp", "Scroll up one page");
127                            shortcut_row(ui, "PageDown", "Scroll down one page");
128                            shortcut_row(ui, "Shift+Home", "Scroll to top");
129                            shortcut_row(ui, "Shift+End", "Scroll to bottom");
130                            shortcut_row(ui, "Mouse wheel", "Scroll up/down");
131
132                            ui.end_row();
133
134                            // Window & Display
135                            ui.label(RichText::new("Window & Display").strong().underline());
136                            ui.end_row();
137
138                            shortcut_row(ui, "F1", "Toggle this help panel");
139                            shortcut_row(ui, "F3", "Toggle FPS overlay");
140                            shortcut_row(ui, "F5", "Reload configuration");
141                            shortcut_row(ui, "F11", "Toggle fullscreen / Shader editor");
142                            shortcut_row(ui, "F12", "Toggle settings panel");
143
144                            ui.end_row();
145
146                            // Font & Text
147                            ui.label(RichText::new("Font & Text").strong().underline());
148                            ui.end_row();
149
150                            shortcut_row(ui, "Ctrl++", "Increase font size");
151                            shortcut_row(ui, "Ctrl+-", "Decrease font size");
152                            shortcut_row(ui, "Ctrl+0", "Reset font size to default");
153
154                            ui.end_row();
155
156                            // Selection & Clipboard
157                            ui.label(RichText::new("Selection & Clipboard").strong().underline());
158                            ui.end_row();
159
160                            shortcut_row(ui, "Click + Drag", "Select text");
161                            shortcut_row(ui, "Double-click", "Select word");
162                            shortcut_row(ui, "Triple-click", "Select line");
163                            shortcut_row(ui, "Ctrl+Shift+C", "Copy selection");
164                            shortcut_row(ui, "Ctrl+Shift+V", "Paste from clipboard");
165                            shortcut_row(ui, "Ctrl+Shift+H", "Toggle clipboard history");
166                            shortcut_row(ui, "Middle-click", "Paste (if enabled)");
167
168                            ui.end_row();
169
170                            // Terminal
171                            ui.label(RichText::new("Terminal").strong().underline());
172                            ui.end_row();
173
174                            shortcut_row(ui, "Ctrl+L", "Clear screen");
175                            shortcut_row(ui, "Ctrl+Shift+S", "Take screenshot");
176                            shortcut_row(ui, "Ctrl+Shift+R", "Toggle session recording");
177                            shortcut_row(ui, "Ctrl+Shift+F5", "Fix rendering (after monitor change)");
178
179                            ui.end_row();
180
181                            // URL Handling
182                            ui.label(RichText::new("URL Handling").strong().underline());
183                            ui.end_row();
184
185                            shortcut_row(ui, "Ctrl+Click URL", "Open URL in browser");
186                        });
187
188                    ui.add_space(12.0);
189
190                    // Mouse Actions Section
191                    ui.heading("Mouse Actions");
192                    ui.separator();
193
194                    egui::Grid::new("mouse_grid")
195                        .num_columns(2)
196                        .spacing([20.0, 4.0])
197                        .striped(true)
198                        .show(ui, |ui| {
199                            shortcut_row(ui, "Scrollbar drag", "Scroll through history");
200                            shortcut_row(ui, "Scrollbar click", "Jump to position");
201                        });
202
203                    ui.add_space(12.0);
204
205                    // Tips Section
206                    ui.heading("Tips");
207                    ui.separator();
208
209                    ui.label("• Configuration changes made via F12 settings are saved to the config file.");
210                    ui.label("• Press F5 to reload config without restarting the terminal.");
211                    ui.label("• Custom shaders can be placed in the shaders folder.");
212                    ui.label("• The shader editor (F11) allows live editing when a shader is configured.");
213                    ui.label("• If display looks corrupted after moving between monitors, press Ctrl+Shift+F5.");
214
215                    ui.add_space(12.0);
216
217                    // Close button
218                    ui.separator();
219                    ui.horizontal(|ui| {
220                        if ui.button("Close").clicked() {
221                            close_requested.set(true);
222                        }
223                        ui.label(RichText::new("Press F1 or Escape to close").weak());
224                    });
225                });
226            });
227
228        // Update visibility based on window state
229        if !open || close_requested.get() {
230            self.visible = false;
231        }
232    }
233}
234
235impl Default for HelpUI {
236    fn default() -> Self {
237        Self::new()
238    }
239}
240
241/// Helper function to add a shortcut row to the grid
242fn shortcut_row(ui: &mut egui::Ui, shortcut: &str, description: &str) {
243    ui.label(RichText::new(shortcut).monospace().strong());
244    ui.label(description);
245    ui.end_row();
246}