Fix on_option_hovered support in ComboBox

This commit is contained in:
Héctor Ramón Jiménez 2023-07-26 22:34:56 +02:00
parent 9eb2889d09
commit 28d32a8b64
No known key found for this signature in database
GPG key ID: 140CC052C94F138E
4 changed files with 63 additions and 23 deletions

View file

@ -15,9 +15,9 @@ struct Example {
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
enum Message { enum Message {
LanguageSelected(Language), Selected(Language),
LanguagePreview(Language), OptionHovered(Language),
LanguageBlurred, Closed,
} }
impl Sandbox for Example { impl Sandbox for Example {
@ -37,15 +37,15 @@ impl Sandbox for Example {
fn update(&mut self, message: Message) { fn update(&mut self, message: Message) {
match message { match message {
Message::LanguageSelected(language) => { Message::Selected(language) => {
self.selected_language = Some(language); self.selected_language = Some(language);
self.text = language.hello().to_string(); self.text = language.hello().to_string();
self.languages.unfocus(); self.languages.unfocus();
} }
Message::LanguagePreview(language) => { Message::OptionHovered(language) => {
self.text = language.hello().to_string(); self.text = language.hello().to_string();
} }
Message::LanguageBlurred => { Message::Closed => {
self.text = self self.text = self
.selected_language .selected_language
.map(|language| language.hello().to_string()) .map(|language| language.hello().to_string())
@ -59,17 +59,17 @@ impl Sandbox for Example {
&self.languages, &self.languages,
"Type a language...", "Type a language...",
self.selected_language.as_ref(), self.selected_language.as_ref(),
Message::LanguageSelected, Message::Selected,
) )
.on_selection(Message::LanguagePreview) .on_option_hovered(Message::OptionHovered)
.on_blur(Message::LanguageBlurred) .on_close(Message::Closed)
.width(250); .width(250);
let content = column![ let content = column![
text(&self.text),
"What is your language?", "What is your language?",
combo_box, combo_box,
vertical_space(150), vertical_space(150),
text(&self.text),
] ]
.width(Length::Fill) .width(Length::Fill)
.align_items(Alignment::Center) .align_items(Alignment::Center)

View file

@ -32,8 +32,8 @@ where
font: Option<Renderer::Font>, font: Option<Renderer::Font>,
selection: text_input::Value, selection: text_input::Value,
on_selected: Box<dyn Fn(T) -> Message>, on_selected: Box<dyn Fn(T) -> Message>,
on_selection: Option<Box<dyn Fn(T) -> Message>>, on_option_hovered: Option<Box<dyn Fn(T) -> Message>>,
on_blur: Option<Message>, on_close: Option<Message>,
on_input: Option<Box<dyn Fn(String) -> Message>>, on_input: Option<Box<dyn Fn(String) -> Message>>,
menu_style: <Renderer::Theme as menu::StyleSheet>::Style, menu_style: <Renderer::Theme as menu::StyleSheet>::Style,
padding: Padding, padding: Padding,
@ -66,9 +66,9 @@ where
font: None, font: None,
selection: text_input::Value::new(&selection), selection: text_input::Value::new(&selection),
on_selected: Box::new(on_selected), on_selected: Box::new(on_selected),
on_selection: None, on_option_hovered: None,
on_input: None, on_input: None,
on_blur: None, on_close: None,
menu_style: Default::default(), menu_style: Default::default(),
padding: text_input::DEFAULT_PADDING, padding: text_input::DEFAULT_PADDING,
size: None, size: None,
@ -87,18 +87,18 @@ where
/// Sets the message that will be produced when an option of the /// Sets the message that will be produced when an option of the
/// [`ComboBox`] is hovered using the arrow keys. /// [`ComboBox`] is hovered using the arrow keys.
pub fn on_selection( pub fn on_option_hovered(
mut self, mut self,
on_selection: impl Fn(T) -> Message + 'static, on_selection: impl Fn(T) -> Message + 'static,
) -> Self { ) -> Self {
self.on_selection = Some(Box::new(on_selection)); self.on_option_hovered = Some(Box::new(on_selection));
self self
} }
/// Sets the message that will be produced when the outside area /// Sets the message that will be produced when the outside area
/// of the [`ComboBox`] is pressed. /// of the [`ComboBox`] is pressed.
pub fn on_blur(mut self, message: Message) -> Self { pub fn on_close(mut self, message: Message) -> Self {
self.on_blur = Some(message); self.on_close = Some(message);
self self
} }
@ -424,6 +424,7 @@ where
// Then finally react to them here // Then finally react to them here
for message in local_messages { for message in local_messages {
let TextInputEvent::TextChanged(new_value) = message; let TextInputEvent::TextChanged(new_value) = message;
if let Some(on_input) = &self.on_input { if let Some(on_input) = &self.on_input {
shell.publish((on_input)(new_value.clone())); shell.publish((on_input)(new_value.clone()));
published_message_to_shell = true; published_message_to_shell = true;
@ -451,6 +452,20 @@ where
if self.state.is_focused() { if self.state.is_focused() {
self.state.with_inner(|state| { self.state.with_inner(|state| {
if !started_focused {
if let Some(on_option_hovered) = &mut self.on_option_hovered
{
let hovered_option = menu.hovered_option.unwrap_or(0);
if let Some(option) =
state.filtered_options.options.get(hovered_option)
{
shell.publish(on_option_hovered(option.clone()));
published_message_to_shell = true;
}
}
}
if let Event::Keyboard(keyboard::Event::KeyPressed { if let Event::Keyboard(keyboard::Event::KeyPressed {
key_code, key_code,
.. ..
@ -475,7 +490,9 @@ where
menu.hovered_option = Some(0); menu.hovered_option = Some(0);
} }
if let Some(on_selection) = &mut self.on_selection { if let Some(on_selection) =
&mut self.on_option_hovered
{
if let Some(option) = if let Some(option) =
menu.hovered_option.and_then(|index| { menu.hovered_option.and_then(|index| {
state state
@ -507,7 +524,9 @@ where
menu.hovered_option = Some(0); menu.hovered_option = Some(0);
} }
if let Some(on_selection) = &mut self.on_selection { if let Some(on_selection) =
&mut self.on_option_hovered
{
if let Some(option) = if let Some(option) =
menu.hovered_option.and_then(|index| { menu.hovered_option.and_then(|index| {
state state
@ -566,7 +585,7 @@ where
&& !self.state.is_focused() && !self.state.is_focused()
&& !published_message_to_shell && !published_message_to_shell
{ {
if let Some(message) = self.on_blur.take() { if let Some(message) = self.on_close.take() {
shell.publish(message); shell.publish(message);
} }
} }
@ -637,6 +656,7 @@ where
&filtered_options.options, &filtered_options.options,
hovered_option, hovered_option,
|x| (self.on_selected)(x), |x| (self.on_selected)(x),
self.on_option_hovered.as_deref(),
) )
.width(bounds.width) .width(bounds.width)
.padding(self.padding) .padding(self.padding)

View file

@ -28,6 +28,7 @@ where
options: &'a [T], options: &'a [T],
hovered_option: &'a mut Option<usize>, hovered_option: &'a mut Option<usize>,
on_selected: Box<dyn FnMut(T) -> Message + 'a>, on_selected: Box<dyn FnMut(T) -> Message + 'a>,
on_option_hovered: Option<&'a dyn Fn(T) -> Message>,
width: f32, width: f32,
padding: Padding, padding: Padding,
text_size: Option<f32>, text_size: Option<f32>,
@ -52,12 +53,14 @@ where
options: &'a [T], options: &'a [T],
hovered_option: &'a mut Option<usize>, hovered_option: &'a mut Option<usize>,
on_selected: impl FnMut(T) -> Message + 'a, on_selected: impl FnMut(T) -> Message + 'a,
on_option_hovered: Option<&'a dyn Fn(T) -> Message>,
) -> Self { ) -> Self {
Menu { Menu {
state, state,
options, options,
hovered_option, hovered_option,
on_selected: Box::new(on_selected), on_selected: Box::new(on_selected),
on_option_hovered,
width: 0.0, width: 0.0,
padding: Padding::ZERO, padding: Padding::ZERO,
text_size: None, text_size: None,
@ -187,6 +190,7 @@ where
options, options,
hovered_option, hovered_option,
on_selected, on_selected,
on_option_hovered,
width, width,
padding, padding,
font, font,
@ -200,6 +204,7 @@ where
options, options,
hovered_option, hovered_option,
on_selected, on_selected,
on_option_hovered,
font, font,
text_size, text_size,
text_line_height, text_line_height,
@ -321,6 +326,7 @@ where
options: &'a [T], options: &'a [T],
hovered_option: &'a mut Option<usize>, hovered_option: &'a mut Option<usize>,
on_selected: Box<dyn FnMut(T) -> Message + 'a>, on_selected: Box<dyn FnMut(T) -> Message + 'a>,
on_option_hovered: Option<&'a dyn Fn(T) -> Message>,
padding: Padding, padding: Padding,
text_size: Option<f32>, text_size: Option<f32>,
text_line_height: text::LineHeight, text_line_height: text::LineHeight,
@ -405,8 +411,21 @@ where
self.text_line_height.to_absolute(Pixels(text_size)), self.text_line_height.to_absolute(Pixels(text_size)),
) + self.padding.vertical(); ) + self.padding.vertical();
*self.hovered_option = let new_hovered_option =
Some((cursor_position.y / option_height) as usize); (cursor_position.y / option_height) as usize;
if let Some(on_option_hovered) = self.on_option_hovered {
if *self.hovered_option != Some(new_hovered_option) {
if let Some(option) =
self.options.get(new_hovered_option)
{
shell
.publish(on_option_hovered(option.clone()));
}
}
}
*self.hovered_option = Some(new_hovered_option);
} }
} }
Event::Touch(touch::Event::FingerPressed { .. }) => { Event::Touch(touch::Event::FingerPressed { .. }) => {

View file

@ -566,6 +566,7 @@ where
(on_selected)(option) (on_selected)(option)
}, },
None,
) )
.width(bounds.width) .width(bounds.width)
.padding(padding) .padding(padding)