refactor: titles for each pane
3 files changed, +38 -9
+21-0src/views/browser.rs
| @@ -229,6 +229,24 @@ impl BrowserView { | ||
| 229 | 229 | let mut clicked_entry: Option<usize> = None; |
| 230 | 230 | let mut dbl_clicked_entry: Option<usize> = None; |
| 231 | 231 | |
| 232 | + // Compute pane titles from path | |
| 233 | + let seg_label = |seg: &PathSegment| -> String { | |
| 234 | + match seg { | |
| 235 | + PathSegment::Key(k) => k.clone(), | |
| 236 | + PathSegment::Index(i) => format!("[{}]", i), | |
| 237 | + } | |
| 238 | + }; | |
| 239 | + let selected_label = current_entries.get(self.selection).map(|e| e.label.as_str()).unwrap_or(""); | |
| 240 | + let (left_title, mid_title, right_title) = match self.path.len() { | |
| 241 | + 0 => (String::new(), "Files".to_string(), selected_label.to_string()), | |
| 242 | + 1 => ("Files".to_string(), seg_label(&self.path[0]), selected_label.to_string()), | |
| 243 | + _ => { | |
| 244 | + let parent = seg_label(&self.path[self.path.len() - 2]); | |
| 245 | + let current_seg = seg_label(&self.path[self.path.len() - 1]); | |
| 246 | + (parent, current_seg, selected_label.to_string()) | |
| 247 | + } | |
| 248 | + }; | |
| 249 | + | |
| 232 | 250 | let col_height = avail.height(); |
| 233 | 251 | ui.horizontal(|ui| { |
| 234 | 252 | ui.set_height(col_height); |
| @@ -237,6 +255,7 @@ impl BrowserView { | ||
| 237 | 255 | ui.vertical(|ui| { |
| 238 | 256 | ui.set_width(col_widths[0]); |
| 239 | 257 | ui.set_height(col_height); |
| 258 | + crate::widgets::miller::pane_title(ui, &left_title); | |
| 240 | 259 | self.render_parent_column(ui, &parent_entries, col_height); |
| 241 | 260 | }); |
| 242 | 261 | |
| @@ -246,6 +265,7 @@ impl BrowserView { | ||
| 246 | 265 | ui.vertical(|ui| { |
| 247 | 266 | ui.set_width(col_widths[1]); |
| 248 | 267 | ui.set_height(col_height); |
| 268 | + crate::widgets::miller::pane_title(ui, &mid_title); | |
| 249 | 269 | let (c, d) = self.render_current_column(ui, ¤t_entries, current, col_height); |
| 250 | 270 | clicked_entry = c; |
| 251 | 271 | dbl_clicked_entry = d; |
| @@ -258,6 +278,7 @@ impl BrowserView { | ||
| 258 | 278 | let remaining = ui.available_width(); |
| 259 | 279 | ui.set_width(remaining); |
| 260 | 280 | ui.set_height(col_height); |
| 281 | + crate::widgets::miller::pane_title(ui, &right_title); | |
| 261 | 282 | self.render_preview_column(ui, selected_child, ¤t_entries, col_height); |
| 262 | 283 | }); |
| 263 | 284 | }); |
+16-0src/widgets/miller.rs
| @@ -98,6 +98,22 @@ pub fn apply_selection(selection: &mut usize, action: MillerAction, count: usize | ||
| 98 | 98 | false |
| 99 | 99 | } |
| 100 | 100 | |
| 101 | +/// Render a pane title above a miller column. | |
| 102 | +pub fn pane_title(ui: &mut Ui, title: &str) { | |
| 103 | + if title.is_empty() { | |
| 104 | + return; | |
| 105 | + } | |
| 106 | + ui.horizontal(|ui| { | |
| 107 | + ui.label( | |
| 108 | + egui::RichText::new(title) | |
| 109 | + .color(crate::theme::CatppuccinMocha::OVERLAY1) | |
| 110 | + .family(egui::FontFamily::Monospace) | |
| 111 | + .size(10.0), | |
| 112 | + ); | |
| 113 | + }); | |
| 114 | + ui.add_space(2.0); | |
| 115 | +} | |
| 116 | + | |
| 101 | 117 | /// Draw a vertical separator line (shared by both browser views). |
| 102 | 118 | pub fn draw_separator(ui: &mut Ui, height: f32) { |
| 103 | 119 | let sep_rect = ui.available_rect_before_wrap(); |