diff --git a/style/src/svg.rs b/style/src/svg.rs index 9378c1a728..5053f9f8cc 100644 --- a/style/src/svg.rs +++ b/style/src/svg.rs @@ -20,4 +20,7 @@ pub trait StyleSheet { /// Produces the [`Appearance`] of the svg. fn appearance(&self, style: &Self::Style) -> Appearance; + + /// Produces the hovered [`Appearance`] of a svg content. + fn hovered(&self, style: &Self::Style) -> Appearance; } diff --git a/style/src/theme.rs b/style/src/theme.rs index 470107283e..4af07794d7 100644 --- a/style/src/theme.rs +++ b/style/src/theme.rs @@ -909,6 +909,10 @@ impl svg::StyleSheet for Theme { Svg::Custom(custom) => custom.appearance(self), } } + + fn hovered(&self, style: &Self::Style) -> svg::Appearance { + self.appearance(style) + } } impl svg::StyleSheet for fn(&Theme) -> svg::Appearance { @@ -917,6 +921,10 @@ impl svg::StyleSheet for fn(&Theme) -> svg::Appearance { fn appearance(&self, style: &Self::Style) -> svg::Appearance { (self)(style) } + + fn hovered(&self, style: &Self::Style) -> svg::Appearance { + self.appearance(style) + } } /// The style of a scrollable. diff --git a/widget/src/pick_list.rs b/widget/src/pick_list.rs index 022ca8d92a..9ff9e6f739 100644 --- a/widget/src/pick_list.rs +++ b/widget/src/pick_list.rs @@ -30,6 +30,8 @@ where Renderer::Theme: StyleSheet, { on_selected: Box Message + 'a>, + on_opened: Option, + on_closed: Option, options: Cow<'a, [T]>, placeholder: Option, selected: Option, @@ -67,6 +69,8 @@ where ) -> Self { Self { on_selected: Box::new(on_selected), + on_opened: None, + on_closed: None, options: options.into(), placeholder: None, selected, @@ -132,6 +136,18 @@ where self } + /// Sets the message that will be produced when the [`PickList`] Menu is openned menu. + pub fn on_opened(mut self, msg: Message) -> Self { + self.on_opened = Some(msg); + self + } + + /// Sets the message that will be produced when the [`PickList`] Menu is closed menu. + pub fn on_closed(mut self, msg: Message) -> Self { + self.on_closed = Some(msg); + self + } + /// Sets the style of the [`PickList`]. pub fn style( mut self, @@ -147,7 +163,7 @@ impl<'a, T: 'a, Message, Renderer> Widget where T: Clone + ToString + Eq + 'static, [T]: ToOwned>, - Message: 'a, + Message: 'a + Clone, Renderer: text::Renderer + 'a, Renderer::Theme: StyleSheet + scrollable::StyleSheet @@ -210,6 +226,8 @@ where cursor, shell, self.on_selected.as_ref(), + self.on_opened.as_ref(), + self.on_closed.as_ref(), self.selected.as_ref(), &self.options, || tree.state.downcast_mut::>(), @@ -284,7 +302,7 @@ impl<'a, T: 'a, Message, Renderer> From> where T: Clone + ToString + Eq + 'static, [T]: ToOwned>, - Message: 'a, + Message: 'a + Copy, Renderer: text::Renderer + 'a, Renderer::Theme: StyleSheet + scrollable::StyleSheet @@ -465,6 +483,8 @@ pub fn update<'a, T, P, Message>( cursor: mouse::Cursor, shell: &mut Shell<'_, Message>, on_selected: &dyn Fn(T) -> Message, + on_opened: Option<&Message>, + on_closed: Option<&Message>, selected: Option<&T>, options: &[T], state: impl FnOnce() -> &'a mut State

, @@ -472,6 +492,7 @@ pub fn update<'a, T, P, Message>( where T: PartialEq + Clone + 'a, P: text::Paragraph + 'a, + Message: Clone, { match event { Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) @@ -483,12 +504,22 @@ where // bounds or on the drop-down, either way we close the overlay. state.is_open = false; + if let Some(on_closed) = on_closed { + // Send callback when popup just close. + shell.publish(on_closed.clone()); + } + event::Status::Captured } else if cursor.is_over(layout.bounds()) { state.is_open = true; state.hovered_option = options.iter().position(|option| Some(option) == selected); + if let Some(on_opened) = on_opened { + // Send callback when popup just opened. + shell.publish(on_opened.clone()); + } + event::Status::Captured } else { event::Status::Ignored diff --git a/widget/src/svg.rs b/widget/src/svg.rs index 2d01d1ab0a..f9b16e1abd 100644 --- a/widget/src/svg.rs +++ b/widget/src/svg.rs @@ -145,7 +145,7 @@ where theme: &Renderer::Theme, _style: &renderer::Style, layout: Layout<'_>, - _cursor: mouse::Cursor, + cursor: mouse::Cursor, _viewport: &Rectangle, ) { let Size { width, height } = renderer.dimensions(&self.handle); @@ -153,6 +153,7 @@ where let bounds = layout.bounds(); let adjusted_fit = self.content_fit.fit(image_size, bounds.size()); + let is_mouse_over = cursor.is_over(bounds); let render = |renderer: &mut Renderer| { let offset = Vector::new( @@ -166,7 +167,11 @@ where ..bounds }; - let appearance = theme.appearance(&self.style); + let appearance = if is_mouse_over { + theme.appearance(&self.style) + } else { + theme.hovered(&self.style) + }; renderer.draw( self.handle.clone(),