irongit

refactor: scrollable list uses on select hook

huncholanehuncholaneauthored
parent 5e9e0a7commit bd69b571ad115dcd155321bdee82dd5ea776894cBrowse files

2 files changed, +35 -44

+8-9src/widgets/jq_bar.rs
@@ -124,16 +124,15 @@ impl JqBar {
124124 let cycle_up = ui.input(|i| i.key_pressed(egui::Key::ArrowUp))
125125 || ui.input_mut(|i| i.consume_key(egui::Modifiers::CTRL, egui::Key::P));
126126
127- let moved = if cycle_down {
128- self.comp_list.down(self.completions.len())
127+ let count = self.completions.len();
128+ let mut selected: Option<usize> = None;
129+ if cycle_down {
130+ self.comp_list.down(count, &mut |idx| { selected = Some(idx); });
129131 } else if cycle_up {
130- self.comp_list.up()
131- } else {
132- false
133- };
134-
135- if moved {
136- let comp = self.completions[self.comp_list.selection].clone();
132+ self.comp_list.up(&mut |idx| { selected = Some(idx); });
133+ }
134+ if let Some(idx) = selected {
135+ let comp = self.completions[idx].clone();
137136 self.apply_completion(&comp);
138137 self.refocus = true;
139138 response.previewing = true;
+27-35src/widgets/scrollable_list.rs
@@ -2,9 +2,9 @@ use egui::{self, Ui};
22
33 /// A virtually-scrolled list that tracks selection and auto-scrolls.
44 ///
5-/// The caller owns keyboard logic and sets `selection` directly.
6-/// The list handles rendering, virtual scrolling, click detection,
7-/// and scrolling to keep the selection visible.
5+/// Caller provides hooks:
6+/// - `render_row` — draw each row
7+/// - `on_select` — called when selection changes (keyboard or click)
88 pub struct ScrollableList {
99 pub selection: usize,
1010 prev_selection: usize,
@@ -20,13 +20,26 @@ impl ScrollableList {
2020 }
2121 }
2222
23- /// Render the list.
23+ /// Move selection down. Calls `on_select` if it moved.
24+ pub fn down(&mut self, count: usize, on_select: &mut dyn FnMut(usize)) {
25+ if count > 0 && self.selection + 1 < count {
26+ self.selection += 1;
27+ on_select(self.selection);
28+ }
29+ }
30+
31+ /// Move selection up. Calls `on_select` if it moved.
32+ pub fn up(&mut self, on_select: &mut dyn FnMut(usize)) {
33+ if self.selection > 0 {
34+ self.selection -= 1;
35+ on_select(self.selection);
36+ }
37+ }
38+
39+ /// Render the list with virtual scrolling.
2440 ///
2541 /// - `render_row(ui, index, is_selected)` — draw one row, return its Response
26- /// - `on_select(index)` — called when selection changes (arrow scroll or click)
27- /// - `on_accept(index)` — called when a row is double-clicked
28- ///
29- /// Returns true if a click changed the selection.
42+ /// - `on_select(index)` — called when a row is clicked
3043 pub fn show(
3144 &mut self,
3245 ui: &mut Ui,
@@ -35,7 +48,7 @@ impl ScrollableList {
3548 row_height: f32,
3649 max_height: Option<f32>,
3750 render_row: &mut dyn FnMut(&mut Ui, usize, bool) -> egui::Response,
38- on_click: &mut dyn FnMut(usize),
51+ on_select: &mut dyn FnMut(usize),
3952 ) {
4053 if count == 0 {
4154 return;
@@ -51,12 +64,11 @@ impl ScrollableList {
5164
5265 let visible_h = max_height.unwrap_or(f32::MAX);
5366
54- // When selection changes, set scroll offset directly so show_rows
55- // renders the selected row (scroll_to_me only works for visible rows).
56- let scroll_offset = if needs_scroll {
67+ // Set scroll offset directly so show_rows renders the selected row.
68+ let scroll_offset = if needs_scroll && visible_h < f32::MAX {
5769 let target_y = self.selection as f32 * row_height;
5870 let centered = (target_y - visible_h / 2.0 + row_height / 2.0).max(0.0);
59- Some(egui::vec2(0.0, centered))
71+ Some(centered)
6072 } else {
6173 None
6274 };
@@ -68,7 +80,7 @@ impl ScrollableList {
6880 area = area.max_height(h);
6981 }
7082 if let Some(offset) = scroll_offset {
71- area = area.vertical_scroll_offset(offset.y);
83+ area = area.vertical_scroll_offset(offset);
7284 }
7385
7486 let mut clicked_idx: Option<usize> = None;
@@ -86,27 +98,7 @@ impl ScrollableList {
8698
8799 if let Some(idx) = clicked_idx {
88100 self.selection = idx;
89- on_click(idx);
90- }
91- }
92-
93- /// Move selection down by 1. Returns true if it moved.
94- pub fn down(&mut self, count: usize) -> bool {
95- if count > 0 && self.selection + 1 < count {
96- self.selection += 1;
97- true
98- } else {
99- false
100- }
101- }
102-
103- /// Move selection up by 1. Returns true if it moved.
104- pub fn up(&mut self) -> bool {
105- if self.selection > 0 {
106- self.selection -= 1;
107- true
108- } else {
109- false
101+ on_select(idx);
110102 }
111103 }
112104