diff options
Diffstat (limited to 'widget/src/overlay')
| -rw-r--r-- | widget/src/overlay/menu.rs | 143 | 
1 files changed, 110 insertions, 33 deletions
diff --git a/widget/src/overlay/menu.rs b/widget/src/overlay/menu.rs index d820592d..bb8ad0e0 100644 --- a/widget/src/overlay/menu.rs +++ b/widget/src/overlay/menu.rs @@ -10,12 +10,12 @@ use crate::core::text::{self, Text};  use crate::core::touch;  use crate::core::widget::Tree;  use crate::core::{ -    Border, Clipboard, Length, Padding, Pixels, Point, Rectangle, Size, Vector, +    Background, Border, Clipboard, Color, Length, Padding, Pixels, Point, +    Rectangle, Size, Vector,  };  use crate::core::{Element, Shell, Widget};  use crate::scrollable::{self, Scrollable}; - -pub use iced_style::menu::{Appearance, StyleSheet}; +use crate::style::Theme;  /// A list of selectable options.  #[allow(missing_debug_implementations)] @@ -26,7 +26,6 @@ pub struct Menu<      Theme = crate::Theme,      Renderer = crate::Renderer,  > where -    Theme: StyleSheet,      Renderer: text::Renderer,  {      state: &'a mut State, @@ -40,14 +39,14 @@ pub struct Menu<      text_line_height: text::LineHeight,      text_shaping: text::Shaping,      font: Option<Renderer::Font>, -    style: Theme::Style, +    style: Style<Theme>,  }  impl<'a, T, Message, Theme, Renderer> Menu<'a, T, Message, Theme, Renderer>  where      T: ToString + Clone,      Message: 'a, -    Theme: StyleSheet + container::Style + scrollable::Style + 'a, +    Theme: container::Style + scrollable::Style + 'a,      Renderer: text::Renderer + 'a,  {      /// Creates a new [`Menu`] with the given [`State`], a list of options, and @@ -58,6 +57,29 @@ where          hovered_option: &'a mut Option<usize>,          on_selected: impl FnMut(T) -> Message + 'a,          on_option_hovered: Option<&'a dyn Fn(T) -> Message>, +    ) -> Self +    where +        Style<Theme>: Default, +    { +        Self::with_style( +            state, +            options, +            hovered_option, +            on_selected, +            on_option_hovered, +            Style::default(), +        ) +    } + +    /// Creates a new [`Menu`] with the given [`State`], a list of options, +    /// the message to produced when an option is selected, and its [`Style`]. +    pub fn with_style( +        state: &'a mut State, +        options: &'a [T], +        hovered_option: &'a mut Option<usize>, +        on_selected: impl FnMut(T) -> Message + 'a, +        on_option_hovered: Option<&'a dyn Fn(T) -> Message>, +        style: Style<Theme>,      ) -> Self {          Menu {              state, @@ -71,7 +93,7 @@ where              text_line_height: text::LineHeight::default(),              text_shaping: text::Shaping::Basic,              font: None, -            style: Default::default(), +            style,          }      } @@ -115,10 +137,7 @@ where      }      /// Sets the style of the [`Menu`]. -    pub fn style( -        mut self, -        style: impl Into<<Theme as StyleSheet>::Style>, -    ) -> Self { +    pub fn style(mut self, style: impl Into<Style<Theme>>) -> Self {          self.style = style.into();          self      } @@ -165,7 +184,6 @@ impl Default for State {  struct Overlay<'a, Message, Theme, Renderer>  where -    Theme: StyleSheet + container::Style,      Renderer: crate::core::Renderer,  {      position: Point, @@ -173,13 +191,13 @@ where      container: Container<'a, Message, Theme, Renderer>,      width: f32,      target_height: f32, -    style: <Theme as StyleSheet>::Style, +    style: Style<Theme>,  }  impl<'a, Message, Theme, Renderer> Overlay<'a, Message, Theme, Renderer>  where      Message: 'a, -    Theme: StyleSheet + container::Style + scrollable::Style + 'a, +    Theme: container::Style + scrollable::Style + 'a,      Renderer: text::Renderer + 'a,  {      pub fn new<T>( @@ -205,18 +223,21 @@ where              style,          } = menu; -        let container = Container::new(Scrollable::new(List { -            options, -            hovered_option, -            on_selected, -            on_option_hovered, -            font, -            text_size, -            text_line_height, -            text_shaping, -            padding, -            style: style.clone(), -        })); +        let container = Container::new( +            Scrollable::new(List { +                options, +                hovered_option, +                on_selected, +                on_option_hovered, +                font, +                text_size, +                text_line_height, +                text_shaping, +                padding, +                style: style.menu, +            }) +            .style(style.scrollable), +        );          state.tree.diff(&container as &dyn Widget<_, _, _>); @@ -235,7 +256,6 @@ impl<'a, Message, Theme, Renderer>      crate::core::Overlay<Message, Theme, Renderer>      for Overlay<'a, Message, Theme, Renderer>  where -    Theme: StyleSheet + container::Style,      Renderer: text::Renderer,  {      fn layout(&mut self, renderer: &Renderer, bounds: Size) -> layout::Node { @@ -302,9 +322,10 @@ where          layout: Layout<'_>,          cursor: mouse::Cursor,      ) { -        let appearance = StyleSheet::appearance(theme, &self.style);          let bounds = layout.bounds(); +        let appearance = (self.style.menu)(theme); +          renderer.fill_quad(              renderer::Quad {                  bounds, @@ -321,7 +342,6 @@ where  struct List<'a, T, Message, Theme, Renderer>  where -    Theme: StyleSheet,      Renderer: text::Renderer,  {      options: &'a [T], @@ -333,14 +353,13 @@ where      text_line_height: text::LineHeight,      text_shaping: text::Shaping,      font: Option<Renderer::Font>, -    style: Theme::Style, +    style: fn(&Theme) -> Appearance,  }  impl<'a, T, Message, Theme, Renderer> Widget<Message, Theme, Renderer>      for List<'a, T, Message, Theme, Renderer>  where      T: Clone + ToString, -    Theme: StyleSheet,      Renderer: text::Renderer,  {      fn size(&self) -> Size<Length> { @@ -483,7 +502,7 @@ where          _cursor: mouse::Cursor,          viewport: &Rectangle,      ) { -        let appearance = theme.appearance(&self.style); +        let appearance = (self.style)(theme);          let bounds = layout.bounds();          let text_size = @@ -553,10 +572,68 @@ impl<'a, T, Message, Theme, Renderer>  where      T: ToString + Clone,      Message: 'a, -    Theme: StyleSheet + 'a, +    Theme: 'a,      Renderer: 'a + text::Renderer,  {      fn from(list: List<'a, T, Message, Theme, Renderer>) -> Self {          Element::new(list)      }  } + +/// The appearance of a [`Menu`]. +#[derive(Debug, Clone, Copy)] +pub struct Appearance { +    /// The [`Background`] of the menu. +    pub background: Background, +    /// The [`Border`] of the menu. +    pub border: Border, +    /// The text [`Color`] of the menu. +    pub text_color: Color, +    /// The text [`Color`] of a selected option in the menu. +    pub selected_text_color: Color, +    /// The background [`Color`] of a selected option in the menu. +    pub selected_background: Background, +} + +/// The definiton of the default style of a [`Menu`]. +#[derive(Debug, PartialEq, Eq)] +pub struct Style<Theme> { +    /// The style of the [`Menu`]. +    menu: fn(&Theme) -> Appearance, +    /// The style of the [`Scrollable`] of the [`Menu`]. +    scrollable: fn(&Theme, scrollable::Status) -> scrollable::Appearance, +} + +impl<Theme> Clone for Style<Theme> { +    fn clone(&self) -> Self { +        *self +    } +} + +impl<Theme> Copy for Style<Theme> {} + +impl Default for Style<Theme> { +    fn default() -> Self { +        Self { +            menu: default, +            scrollable: scrollable::default, +        } +    } +} + +/// The default style of a [`Menu`]. +pub fn default(theme: &Theme) -> Appearance { +    let palette = theme.extended_palette(); + +    Appearance { +        background: palette.background.weak.color.into(), +        border: Border { +            width: 1.0, +            radius: 0.0.into(), +            color: palette.background.strong.color, +        }, +        text_color: palette.background.weak.text, +        selected_text_color: palette.primary.strong.text, +        selected_background: palette.primary.strong.color.into(), +    } +}  | 
