diff --git a/examples/menu/src/main.rs b/examples/menu/src/main.rs index 6885461e..b21f1252 100644 --- a/examples/menu/src/main.rs +++ b/examples/menu/src/main.rs @@ -5,8 +5,8 @@ use iced::widget::{ use iced::widget::{column as col, vertical_space}; use iced::{alignment, theme, Border, Color, Element, Length, Size}; -use iced_aw::menu::{self, Item, Menu, StyleSheet}; -use iced_aw::style::MenuBarStyle; +use iced_aw::menu::{self, Item, Menu}; +use iced_aw::style::{menu_bar::primary, Status}; use iced_aw::{menu_bar, menu_items}; use iced_aw::{quad, widgets::InnerBounds}; use iced_aw::{Bootstrap, BOOTSTRAP_FONT, BOOTSTRAP_FONT_BYTES}; @@ -416,12 +416,12 @@ impl App { }) ) .draw_path(menu::DrawPath::Backdrop) - .style(|theme:&iced::Theme| menu::Appearance{ + .style(|theme:&iced::Theme, status: Status | menu::Style{ path_border: Border{ radius: [6.0; 4].into(), ..Default::default() }, - ..theme.appearance(&MenuBarStyle::Default) + ..primary(theme, status) }); let r = row![ diff --git a/src/style.rs b/src/style.rs index 5a53c257..9c5e61a3 100644 --- a/src/style.rs +++ b/src/style.rs @@ -32,8 +32,6 @@ pub mod selection_list; #[cfg(feature = "menu")] pub mod menu_bar; -#[cfg(feature = "menu")] -pub use menu_bar::MenuBarStyle; #[cfg(feature = "context_menu")] pub mod context_menu; diff --git a/src/style/menu_bar.rs b/src/style/menu_bar.rs index f1f2817e..cace0c10 100644 --- a/src/style/menu_bar.rs +++ b/src/style/menu_bar.rs @@ -1,9 +1,10 @@ //! Change the appearance of menu bars and their menus. +use super::{Status, StyleFn}; use iced::{Background, Border, Color, Padding, Shadow, Theme, Vector}; /// The appearance of a menu bar and its menus. #[derive(Debug, Clone, Copy)] -pub struct Appearance { +pub struct Style { /// The background of the menu bar. pub bar_background: Background, /// The border of the menu bar. @@ -27,7 +28,8 @@ pub struct Appearance { /// The border of the path pub path_border: Border, } -impl std::default::Default for Appearance { + +impl std::default::Default for Style { fn default() -> Self { Self { bar_background: Color::from([0.85; 3]).into(), @@ -58,54 +60,39 @@ impl std::default::Default for Appearance { } } -/// The style sheet of a menu bar and its menus. -pub trait StyleSheet { - /// The supported style of the [`StyleSheet`]. - type Style: Default; +/// The Catalog of a [`Menu`](crate::widgets::menu::Menu). +pub trait Catalog { + ///Style for the trait to use. + type Class<'a>; - /// Produces the [`Appearance`] of a menu bar and its menus. - fn appearance(&self, style: &Self::Style) -> Appearance; -} + /// The default class produced by the [`Catalog`]. + fn default<'a>() -> Self::Class<'a>; -/// The style of a menu bar and its menus -#[derive(Default)] -#[allow(missing_debug_implementations)] -pub enum MenuBarStyle { - /// The default style. - #[default] - Default, - /// A [`Theme`] that uses a `Custom` palette. - Custom(Box>), + /// The [`Style`] of a class with the given status. + fn style(&self, class: &Self::Class<'_>, status: Status) -> Style; } -impl Appearance + 'static> From for MenuBarStyle { - fn from(f: F) -> Self { - Self::Custom(Box::new(f)) - } -} +impl Catalog for Theme { + type Class<'a> = StyleFn<'a, Self, Style>; -impl Appearance> StyleSheet for F { - type Style = Theme; + fn default<'a>() -> Self::Class<'a> { + Box::new(primary) + } - fn appearance(&self, style: &Self::Style) -> Appearance { - (self)(style) + fn style(&self, class: &Self::Class<'_>, status: Status) -> Style { + class(self, status) } } -impl StyleSheet for Theme { - type Style = MenuBarStyle; +/// The primary theme of a [`Menu`](crate::widgets::menu::Menu). +#[must_use] +pub fn primary(theme: &Theme, _status: Status) -> Style { + let palette = theme.extended_palette(); - fn appearance(&self, style: &Self::Style) -> Appearance { - let palette = self.extended_palette(); - - match style { - MenuBarStyle::Default => Appearance { - bar_background: palette.background.base.color.into(), - menu_background: palette.background.base.color.into(), - path: palette.primary.weak.color.into(), - ..Default::default() - }, - MenuBarStyle::Custom(c) => c.appearance(self), - } + Style { + bar_background: palette.background.base.color.into(), + menu_background: palette.background.base.color.into(), + path: palette.primary.weak.color.into(), + ..Default::default() } } diff --git a/src/widgets/menu.rs b/src/widgets/menu.rs index a2ddb809..3c24a139 100644 --- a/src/widgets/menu.rs +++ b/src/widgets/menu.rs @@ -149,7 +149,7 @@ mod menu_bar; mod menu_bar_overlay; mod menu_tree; -pub use crate::style::menu_bar::{Appearance, StyleSheet}; +pub use crate::style::menu_bar::{primary, Catalog, Style}; pub use common::{DrawPath, ScrollSpeed}; pub use menu_bar::MenuBar; pub use menu_tree::{Item, Menu}; diff --git a/src/widgets/menu/menu_bar.rs b/src/widgets/menu/menu_bar.rs index 1dcab0d2..f8ada1d9 100644 --- a/src/widgets/menu/menu_bar.rs +++ b/src/widgets/menu/menu_bar.rs @@ -17,6 +17,7 @@ use iced::{ use super::{common::*, flex, menu_bar_overlay::MenuBarOverlay, menu_tree::*}; use crate::style::menu_bar::*; +pub use crate::style::status::{Status, StyleFn}; #[derive(Default)] pub(super) struct MenuBarState { @@ -29,7 +30,7 @@ pub(super) struct MenuBarState { #[must_use] pub struct MenuBar<'a, Message, Theme, Renderer> where - Theme: StyleSheet, + Theme: Catalog, Renderer: renderer::Renderer, { roots: Vec>, @@ -40,11 +41,11 @@ where check_bounds_width: f32, draw_path: DrawPath, scroll_speed: ScrollSpeed, - style: Theme::Style, + class: Theme::Class<'a>, } impl<'a, Message, Theme, Renderer> MenuBar<'a, Message, Theme, Renderer> where - Theme: StyleSheet, + Theme: Catalog, Renderer: renderer::Renderer, { /// Creates a [`MenuBar`] with the given root items. @@ -67,7 +68,7 @@ where line: 60.0, pixel: 1.0, }, - style: Theme::Style::default(), + class: Theme::default(), } } @@ -113,16 +114,25 @@ where self } - /// Sets the style variant of this [`MenuBar`]. - pub fn style(mut self, style: impl Into) -> Self { - self.style = style.into(); + /// Sets the style of the [`Badge`]. + pub fn style(mut self, style: impl Fn(&Theme, Status) -> Style + 'a) -> Self + where + Theme::Class<'a>: From>, + { + self.class = (Box::new(style) as StyleFn<'a, Theme, Style>).into(); + self + } + + /// Sets the class of the input of the [`Badge`]. + pub fn class(mut self, class: impl Into>) -> Self { + self.class = class.into(); self } } impl<'a, Message, Theme, Renderer> Widget for MenuBar<'a, Message, Theme, Renderer> where - Theme: StyleSheet, + Theme: Catalog, Renderer: renderer::Renderer, { fn size(&self) -> Size { @@ -277,7 +287,7 @@ where mut cursor: mouse::Cursor, viewport: &Rectangle, ) { - let styling = theme.appearance(&self.style); + let styling = theme.style(&self.class, Status::Active); renderer.fill_quad( renderer::Quad { bounds: pad_rectangle(layout.bounds(), styling.bar_background_expand), @@ -346,7 +356,7 @@ where check_bounds_width: self.check_bounds_width, draw_path: &self.draw_path, scroll_speed: self.scroll_speed, - style: &self.style, + class: &self.class, } .overlay_element(), ) @@ -359,7 +369,7 @@ impl<'a, Message, Theme, Renderer> From> for Element<'a, Message, Theme, Renderer> where Message: 'a, - Theme: 'a + StyleSheet, + Theme: 'a + Catalog, Renderer: 'a + renderer::Renderer, { fn from(value: MenuBar<'a, Message, Theme, Renderer>) -> Self { diff --git a/src/widgets/menu/menu_bar_overlay.rs b/src/widgets/menu/menu_bar_overlay.rs index ced9b546..a4a569e3 100644 --- a/src/widgets/menu/menu_bar_overlay.rs +++ b/src/widgets/menu/menu_bar_overlay.rs @@ -17,11 +17,11 @@ use iced::{ }; use super::{common::*, menu_bar::MenuBarState, menu_tree::*}; -use crate::style::menu_bar::*; +use crate::style::{menu_bar::*, Status}; pub(super) struct MenuBarOverlay<'a, 'b, Message, Theme, Renderer> where - Theme: StyleSheet, + Theme: Catalog, Renderer: renderer::Renderer, { /// Tree{ bar_state, [item_tree...] } @@ -34,11 +34,11 @@ where pub(super) check_bounds_width: f32, pub(super) draw_path: &'b DrawPath, pub(super) scroll_speed: ScrollSpeed, - pub(super) style: &'b Theme::Style, + pub(super) class: &'b Theme::Class<'a>, } impl<'a, 'b, Message, Theme, Renderer> MenuBarOverlay<'a, 'b, Message, Theme, Renderer> where - Theme: StyleSheet, + Theme: Catalog, Renderer: renderer::Renderer, { pub(super) fn overlay_element(self) -> overlay::Element<'b, Message, Theme, Renderer> { @@ -48,7 +48,7 @@ where impl<'a, 'b, Message, Theme, Renderer> overlay::Overlay for MenuBarOverlay<'a, 'b, Message, Theme, Renderer> where - Theme: StyleSheet, + Theme: Catalog, Renderer: renderer::Renderer, { fn layout(&mut self, renderer: &Renderer, bounds: Size) -> Node { @@ -77,7 +77,7 @@ where let active_tree = &mut self.tree.children[active]; // item_tree: Tree{ stateless, [ widget_tree, menu_tree ] } let parent_bounds = self.init_root_bounds[active] + translation; - fn rec( + fn rec( renderer: &Renderer, item: &Item<'_, Message, Theme, Renderer>, tree: &mut Tree, @@ -210,7 +210,7 @@ where let mut prev_bounds_list = vec![bar_bounds]; #[rustfmt::skip] - fn rec<'a, 'b, Message, Theme: StyleSheet, Renderer: renderer::Renderer>( + fn rec<'a, 'b, Message, Theme: Catalog, Renderer: renderer::Renderer>( tree: &mut Tree, item: &mut Item<'a, Message, Theme, Renderer>, event: &Event, @@ -360,7 +360,7 @@ where let active_root = &self.roots[active]; let active_tree = &self.tree.children[active]; - fn rec<'a, 'b, Message, Theme: StyleSheet, Renderer: renderer::Renderer>( + fn rec<'a, 'b, Message, Theme: Catalog, Renderer: renderer::Renderer>( tree: &Tree, item: &Item<'a, Message, Theme, Renderer>, layout_iter: &mut impl Iterator>, @@ -429,7 +429,7 @@ where let active_root = &self.roots[active]; let active_tree = &self.tree.children[active]; - fn rec<'a, 'b, Message, Theme: StyleSheet, Renderer: renderer::Renderer>( + fn rec<'a, 'b, Message, Theme: Catalog, Renderer: renderer::Renderer>( draw_path: &DrawPath, tree: &Tree, item: &Item<'a, Message, Theme, Renderer>, @@ -438,7 +438,7 @@ where renderer: &mut Renderer, theme: &Theme, style: &renderer::Style, - theme_style: &Theme::Style, + theme_style: &Style, viewport: &Rectangle, ) { let menu = item.menu.as_ref().expect("No menu defined in this item"); @@ -483,6 +483,8 @@ where } } + let theme_style = theme.style(self.class, Status::Active); + rec( self.draw_path, active_tree, @@ -492,7 +494,7 @@ where renderer, theme, style, - self.style, + &theme_style, &viewport, ); } diff --git a/src/widgets/menu/menu_tree.rs b/src/widgets/menu/menu_tree.rs index 2f650287..87bb46ea 100644 --- a/src/widgets/menu/menu_tree.rs +++ b/src/widgets/menu/menu_tree.rs @@ -83,7 +83,7 @@ impl Default for MenuState { #[must_use] pub struct Menu<'a, Message, Theme, Renderer> where - Theme: StyleSheet, + Theme: Catalog, Renderer: renderer::Renderer, { pub(super) items: Vec>, @@ -96,7 +96,7 @@ where } impl<'a, Message, Theme, Renderer> Menu<'a, Message, Theme, Renderer> where - Theme: StyleSheet, + Theme: Catalog, Renderer: renderer::Renderer, { /// Creates a [`Menu`] with the given items. @@ -147,7 +147,7 @@ where } impl<'a, Message, Theme, Renderer> Menu<'a, Message, Theme, Renderer> where - Theme: StyleSheet, + Theme: Catalog, Renderer: renderer::Renderer, { // pub(super) fn size(&self) -> Size { @@ -412,7 +412,7 @@ where renderer: &mut Renderer, theme: &Theme, style: &renderer::Style, - theme_style: &Theme::Style, + theme_style: &Style, layout: Layout<'_>, mut cursor: mouse::Cursor, viewport: &Rectangle, @@ -426,20 +426,18 @@ where let menu_state = tree.state.downcast_ref::(); let slice = &menu_state.slice; - let styling = theme.appearance(theme_style); - // debug_draw(renderer, prescroll, check_bounds, offset_bounds); // draw background - let pad_rectangle = pad_rectangle(prescroll, styling.menu_background_expand); + let pad_rectangle = pad_rectangle(prescroll, theme_style.menu_background_expand); if pad_rectangle.intersects(viewport) { renderer.fill_quad( renderer::Quad { bounds: pad_rectangle, - border: styling.menu_border, - shadow: styling.menu_shadow, + border: theme_style.menu_border, + shadow: theme_style.menu_shadow, }, - styling.menu_background, + theme_style.menu_background, ); } @@ -459,10 +457,10 @@ where renderer.fill_quad( renderer::Quad { bounds: active_bounds, - border: styling.path_border, + border: theme_style.path_border, ..Default::default() }, - styling.path, + theme_style.path, ); } } @@ -609,44 +607,11 @@ where } } -/* fn debug_draw( - renderer: &mut Renderer, - prescroll: Rectangle, - check_bounds: Rectangle, - offset_bounds: Rectangle, -){ - [ - prescroll, - check_bounds, - offset_bounds, - ].iter() - .zip([ - Color::from([1.0, 1.0, 1.0, 0.8]), - Color::from([1.0, 0.0, 0.0, 0.1]), - Color::from([0.0, 0.0, 1.0, 0.3]), - ]) - .for_each(|(b, c)|{ - if (b.width > 0.) && (b.height > 0.) { - renderer.fill_quad( - renderer::Quad{ - bounds: *b, - border: Border{ - radius: 6.0.into(), - ..Default::default() - }, - ..Default::default() - }, - c - ); - } - }); -} */ - /// Item inside a [`Menu`] #[must_use] pub struct Item<'a, Message, Theme, Renderer> where - Theme: StyleSheet, + Theme: Catalog, Renderer: renderer::Renderer, { pub(super) item: Element<'a, Message, Theme, Renderer>, @@ -654,7 +619,7 @@ where } impl<'a, Message, Theme, Renderer> Item<'a, Message, Theme, Renderer> where - Theme: StyleSheet, + Theme: Catalog, Renderer: renderer::Renderer, { /// Creates an [`Item`] with the given element. @@ -687,7 +652,7 @@ where } impl<'a, Message, Theme, Renderer> Item<'a, Message, Theme, Renderer> where - Theme: StyleSheet, + Theme: Catalog, Renderer: renderer::Renderer, { // pub(super) fn size(&self) -> Size {