From 097032327d6c8b88b5f81f204101e8587e81827a Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Mon, 20 May 2024 10:52:04 -0400 Subject: [PATCH] add `PickerDelegate::selected_index_changed` (#12059) Adds the ability to have some effect run when a selection changes in a picker. If the `PickerDelegate` implements something other than `None` for `selected_index_changed` then each time the selection changes it will run that effect. For example: ```rs impl PickerDelegate for PromptManagerDelegate { //... fn selected_index_changed( &self, ix: usize, cx: &mut ViewContext>, ) -> Option> { Some(self.prompt_manager.set_active_prompt(ix, cx)) } //... } ``` This isn't currently used in any picker, but I'm adding this to allow the functionality we intended for the prompt library, we're changing selections, activates a preview in the right column. This will be useful for building any sort of UI where there's a picker on the left and a preview on the right, such as a UI like them telescope. Release Notes: - N/A --- crates/picker/src/picker.rs | 44 +++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/crates/picker/src/picker.rs b/crates/picker/src/picker.rs index da0a85a8e0..72fc1e525a 100644 --- a/crates/picker/src/picker.rs +++ b/crates/picker/src/picker.rs @@ -59,7 +59,14 @@ pub trait PickerDelegate: Sized + 'static { Vec::new() } fn set_selected_index(&mut self, ix: usize, cx: &mut ViewContext>); - + // Allows binding some optional effect to when the selection changes. + fn selected_index_changed( + &self, + _ix: usize, + _cx: &mut ViewContext>, + ) -> Option> { + None + } fn placeholder_text(&self, _cx: &mut WindowContext) -> Arc; fn no_matches_text(&self, _cx: &mut WindowContext) -> SharedString { "No matches".into() @@ -224,13 +231,31 @@ impl Picker { self.focus_handle(cx).focus(cx); } + /// Handles the selecting an index, and passing the change to the delegate. + /// If `scroll_to_index` is true, the new selected index will be scrolled into view. + /// + /// If some effect is bound to `selected_index_changed`, it will be executed. + fn set_selected_index(&mut self, ix: usize, scroll_to_index: bool, cx: &mut ViewContext) { + let previous_index = self.delegate.selected_index(); + self.delegate.set_selected_index(ix, cx); + let current_index = self.delegate.selected_index(); + + if previous_index != current_index { + if let Some(action) = self.delegate.selected_index_changed(ix, cx) { + action(cx); + } + if scroll_to_index { + self.scroll_to_item_index(ix); + } + } + } + pub fn select_next(&mut self, _: &menu::SelectNext, cx: &mut ViewContext) { let count = self.delegate.match_count(); if count > 0 { let index = self.delegate.selected_index(); let ix = if index == count - 1 { 0 } else { index + 1 }; - self.delegate.set_selected_index(ix, cx); - self.scroll_to_item_index(ix); + self.set_selected_index(ix, true, cx); cx.notify(); } } @@ -240,8 +265,7 @@ impl Picker { if count > 0 { let index = self.delegate.selected_index(); let ix = if index == 0 { count - 1 } else { index - 1 }; - self.delegate.set_selected_index(ix, cx); - self.scroll_to_item_index(ix); + self.set_selected_index(ix, true, cx); cx.notify(); } } @@ -249,8 +273,7 @@ impl Picker { fn select_first(&mut self, _: &menu::SelectFirst, cx: &mut ViewContext) { let count = self.delegate.match_count(); if count > 0 { - self.delegate.set_selected_index(0, cx); - self.scroll_to_item_index(0); + self.set_selected_index(0, true, cx); cx.notify(); } } @@ -259,7 +282,7 @@ impl Picker { let count = self.delegate.match_count(); if count > 0 { self.delegate.set_selected_index(count - 1, cx); - self.scroll_to_item_index(count - 1); + self.set_selected_index(count - 1, true, cx); cx.notify(); } } @@ -268,8 +291,7 @@ impl Picker { let count = self.delegate.match_count(); let index = self.delegate.selected_index(); let new_index = if index + 1 == count { 0 } else { index + 1 }; - self.delegate.set_selected_index(new_index, cx); - self.scroll_to_item_index(new_index); + self.set_selected_index(new_index, false, cx); cx.notify(); } @@ -319,7 +341,7 @@ impl Picker { fn handle_click(&mut self, ix: usize, secondary: bool, cx: &mut ViewContext) { cx.stop_propagation(); cx.prevent_default(); - self.delegate.set_selected_index(ix, cx); + self.set_selected_index(ix, false, cx); self.do_confirm(secondary, cx) }