diff options
author | 2022-07-09 02:28:52 +0200 | |
---|---|---|
committer | 2022-07-09 02:28:52 +0200 | |
commit | e053e25d2ccb17f7a162685a106a8bbd915a873f (patch) | |
tree | 5304f3ea2712e8889c7278ec5e57418f484d8f6c /native | |
parent | 66eb6263003c1bbedd1fd14d6b12f172d20a6211 (diff) | |
parent | 7105db97a53d90adf429091298f31c90974d8f08 (diff) | |
download | iced-e053e25d2ccb17f7a162685a106a8bbd915a873f.tar.gz iced-e053e25d2ccb17f7a162685a106a8bbd915a873f.tar.bz2 iced-e053e25d2ccb17f7a162685a106a8bbd915a873f.zip |
Merge pull request #1362 from iced-rs/theming
Theming
Diffstat (limited to '')
32 files changed, 602 insertions, 266 deletions
diff --git a/native/src/element.rs b/native/src/element.rs index 119b7892..425bddc2 100644 --- a/native/src/element.rs +++ b/native/src/element.rs @@ -244,13 +244,20 @@ where pub fn draw( &self, renderer: &mut Renderer, + theme: &Renderer::Theme, style: &renderer::Style, layout: Layout<'_>, cursor_position: Point, viewport: &Rectangle, ) { - self.widget - .draw(renderer, style, layout, cursor_position, viewport) + self.widget.draw( + renderer, + theme, + style, + layout, + cursor_position, + viewport, + ) } /// Returns the current [`mouse::Interaction`] of the [`Element`]. @@ -350,13 +357,20 @@ where fn draw( &self, renderer: &mut Renderer, + theme: &Renderer::Theme, style: &renderer::Style, layout: Layout<'_>, cursor_position: Point, viewport: &Rectangle, ) { - self.widget - .draw(renderer, style, layout, cursor_position, viewport) + self.widget.draw( + renderer, + theme, + style, + layout, + cursor_position, + viewport, + ) } fn mouse_interaction( @@ -444,6 +458,7 @@ where fn draw( &self, renderer: &mut Renderer, + theme: &Renderer::Theme, style: &renderer::Style, layout: Layout<'_>, cursor_position: Point, @@ -471,6 +486,7 @@ where self.element.widget.draw( renderer, + theme, style, layout, cursor_position, diff --git a/native/src/lib.rs b/native/src/lib.rs index db60976f..2d0dd6ec 100644 --- a/native/src/lib.rs +++ b/native/src/lib.rs @@ -76,6 +76,8 @@ pub use iced_core::{ Rectangle, Size, Vector, }; pub use iced_futures::{executor, futures}; +pub use iced_style::application; +pub use iced_style::theme; #[doc(no_inline)] pub use executor::Executor; @@ -93,5 +95,6 @@ pub use renderer::Renderer; pub use runtime::Runtime; pub use shell::Shell; pub use subscription::Subscription; +pub use theme::Theme; pub use user_interface::UserInterface; pub use widget::Widget; diff --git a/native/src/overlay.rs b/native/src/overlay.rs index 86878f6a..792d2905 100644 --- a/native/src/overlay.rs +++ b/native/src/overlay.rs @@ -34,6 +34,7 @@ where fn draw( &self, renderer: &mut Renderer, + theme: &Renderer::Theme, style: &renderer::Style, layout: Layout<'_>, cursor_position: Point, diff --git a/native/src/overlay/element.rs b/native/src/overlay/element.rs index 24c0fe01..de2e1f37 100644 --- a/native/src/overlay/element.rs +++ b/native/src/overlay/element.rs @@ -94,11 +94,13 @@ where pub fn draw( &self, renderer: &mut Renderer, + theme: &Renderer::Theme, style: &renderer::Style, layout: Layout<'_>, cursor_position: Point, ) { - self.overlay.draw(renderer, style, layout, cursor_position) + self.overlay + .draw(renderer, theme, style, layout, cursor_position) } } @@ -173,10 +175,12 @@ where fn draw( &self, renderer: &mut Renderer, + theme: &Renderer::Theme, style: &renderer::Style, layout: Layout<'_>, cursor_position: Point, ) { - self.content.draw(renderer, style, layout, cursor_position) + self.content + .draw(renderer, theme, style, layout, cursor_position) } } diff --git a/native/src/overlay/menu.rs b/native/src/overlay/menu.rs index 13fa7beb..979a13c3 100644 --- a/native/src/overlay/menu.rs +++ b/native/src/overlay/menu.rs @@ -7,18 +7,22 @@ use crate::overlay; use crate::renderer; use crate::text::{self, Text}; use crate::touch; +use crate::widget::container::{self, Container}; use crate::widget::scrollable::{self, Scrollable}; -use crate::widget::Container; use crate::{ Clipboard, Color, Element, Layout, Length, Padding, Point, Rectangle, Shell, Size, Vector, Widget, }; -pub use iced_style::menu::Style; +pub use iced_style::menu::{Appearance, StyleSheet}; /// A list of selectable options. #[allow(missing_debug_implementations)] -pub struct Menu<'a, T, Renderer: text::Renderer> { +pub struct Menu<'a, T, Renderer> +where + Renderer: text::Renderer, + Renderer::Theme: StyleSheet, +{ state: &'a mut State, options: &'a [T], hovered_option: &'a mut Option<usize>, @@ -27,13 +31,15 @@ pub struct Menu<'a, T, Renderer: text::Renderer> { padding: Padding, text_size: Option<u16>, font: Renderer::Font, - style: Style, + style: <Renderer::Theme as StyleSheet>::Style, } impl<'a, T, Renderer> Menu<'a, T, Renderer> where T: ToString + Clone, Renderer: text::Renderer + 'a, + Renderer::Theme: + StyleSheet + container::StyleSheet + scrollable::StyleSheet, { /// Creates a new [`Menu`] with the given [`State`], a list of options, and /// the message to produced when an option is selected. @@ -81,7 +87,10 @@ where } /// Sets the style of the [`Menu`]. - pub fn style(mut self, style: impl Into<Style>) -> Self { + pub fn style( + mut self, + style: impl Into<<Renderer::Theme as StyleSheet>::Style>, + ) -> Self { self.style = style.into(); self } @@ -117,17 +126,24 @@ impl State { } } -struct Overlay<'a, Message, Renderer: text::Renderer> { +struct Overlay<'a, Message, Renderer> +where + Renderer: crate::Renderer, + Renderer::Theme: StyleSheet + container::StyleSheet, +{ container: Container<'a, Message, Renderer>, width: u16, target_height: f32, - style: Style, + style: <Renderer::Theme as StyleSheet>::Style, } -impl<'a, Message, Renderer: text::Renderer> Overlay<'a, Message, Renderer> +impl<'a, Message, Renderer> Overlay<'a, Message, Renderer> where Message: 'a, Renderer: 'a, + Renderer: text::Renderer, + Renderer::Theme: + StyleSheet + container::StyleSheet + scrollable::StyleSheet, { pub fn new<T>(menu: Menu<'a, T, Renderer>, target_height: f32) -> Self where @@ -153,9 +169,8 @@ where font, text_size, padding, - style: style.clone(), - })) - .padding(1); + style, + })); Self { container, @@ -170,6 +185,7 @@ impl<'a, Message, Renderer> crate::Overlay<Message, Renderer> for Overlay<'a, Message, Renderer> where Renderer: text::Renderer, + Renderer::Theme: StyleSheet + container::StyleSheet, { fn layout( &self, @@ -241,35 +257,50 @@ where fn draw( &self, renderer: &mut Renderer, + theme: &Renderer::Theme, style: &renderer::Style, layout: Layout<'_>, cursor_position: Point, ) { + let appearance = theme.appearance(self.style); let bounds = layout.bounds(); renderer.fill_quad( renderer::Quad { - bounds, - border_color: self.style.border_color, - border_width: self.style.border_width, + bounds: Rectangle { + width: bounds.width - 1.0, + ..bounds + }, + border_color: appearance.border_color, + border_width: appearance.border_width, border_radius: 0.0, }, - self.style.background, + appearance.background, ); - self.container - .draw(renderer, style, layout, cursor_position, &bounds); + self.container.draw( + renderer, + theme, + style, + layout, + cursor_position, + &bounds, + ); } } -struct List<'a, T, Renderer: text::Renderer> { +struct List<'a, T, Renderer> +where + Renderer: text::Renderer, + Renderer::Theme: StyleSheet, +{ options: &'a [T], hovered_option: &'a mut Option<usize>, last_selection: &'a mut Option<T>, padding: Padding, text_size: Option<u16>, font: Renderer::Font, - style: Style, + style: <Renderer::Theme as StyleSheet>::Style, } impl<'a, T, Message, Renderer> Widget<Message, Renderer> @@ -277,6 +308,7 @@ impl<'a, T, Message, Renderer> Widget<Message, Renderer> where T: Clone + ToString, Renderer: text::Renderer, + Renderer::Theme: StyleSheet, { fn width(&self) -> Length { Length::Fill @@ -389,11 +421,13 @@ where fn draw( &self, renderer: &mut Renderer, + theme: &Renderer::Theme, _style: &renderer::Style, layout: Layout<'_>, _cursor_position: Point, viewport: &Rectangle, ) { + let appearance = theme.appearance(self.style); let bounds = layout.bounds(); let text_size = self.text_size.unwrap_or(renderer.default_size()); @@ -425,7 +459,7 @@ where border_width: 0.0, border_radius: 0.0, }, - self.style.selected_background, + appearance.selected_background, ); } @@ -440,9 +474,9 @@ where size: f32::from(text_size), font: self.font.clone(), color: if is_selected { - self.style.selected_text_color + appearance.selected_text_color } else { - self.style.text_color + appearance.text_color }, horizontal_alignment: alignment::Horizontal::Left, vertical_alignment: alignment::Vertical::Center, @@ -457,6 +491,7 @@ where T: ToString + Clone, Message: 'a, Renderer: 'a + text::Renderer, + Renderer::Theme: StyleSheet, { fn into(self) -> Element<'a, Message, Renderer> { Element::new(self) diff --git a/native/src/program/state.rs b/native/src/program/state.rs index cb87a628..7ec2a04f 100644 --- a/native/src/program/state.rs +++ b/native/src/program/state.rs @@ -1,4 +1,6 @@ +use crate::application; use crate::mouse; +use crate::renderer; use crate::user_interface::{self, UserInterface}; use crate::{Clipboard, Command, Debug, Event, Point, Program, Size}; @@ -19,6 +21,7 @@ where impl<P> State<P> where P: Program + 'static, + <P::Renderer as crate::Renderer>::Theme: application::StyleSheet, { /// Creates a new [`State`] with the provided [`Program`], initializing its /// primitive with the given logical bounds and renderer. @@ -86,6 +89,8 @@ where bounds: Size, cursor_position: Point, renderer: &mut P::Renderer, + theme: &<P::Renderer as crate::Renderer>::Theme, + style: &renderer::Style, clipboard: &mut dyn Clipboard, debug: &mut Debug, ) -> Option<Command<P::Message>> { @@ -115,7 +120,7 @@ where if messages.is_empty() { debug.draw_started(); self.mouse_interaction = - user_interface.draw(renderer, cursor_position); + user_interface.draw(renderer, theme, style, cursor_position); debug.draw_finished(); self.cache = Some(user_interface.into_cache()); @@ -147,7 +152,7 @@ where debug.draw_started(); self.mouse_interaction = - user_interface.draw(renderer, cursor_position); + user_interface.draw(renderer, theme, style, cursor_position); debug.draw_finished(); self.cache = Some(user_interface.into_cache()); @@ -163,7 +168,10 @@ fn build_user_interface<'a, P: Program>( renderer: &mut P::Renderer, size: Size, debug: &mut Debug, -) -> UserInterface<'a, P::Message, P::Renderer> { +) -> UserInterface<'a, P::Message, P::Renderer> +where + <P::Renderer as crate::Renderer>::Theme: application::StyleSheet, +{ debug.view_started(); let view = program.view(); debug.view_finished(); diff --git a/native/src/renderer.rs b/native/src/renderer.rs index 73d2f401..a7305a55 100644 --- a/native/src/renderer.rs +++ b/native/src/renderer.rs @@ -9,6 +9,9 @@ use crate::{Background, Color, Element, Rectangle, Vector}; /// A component that can be used by widgets to draw themselves on a screen. pub trait Renderer: Sized { + /// The supported theme of the [`Renderer`]. + type Theme; + /// Lays out the elements of a user interface. /// /// You should override this if you need to perform any operations before or diff --git a/native/src/renderer/null.rs b/native/src/renderer/null.rs index a5b2f277..c591f4e2 100644 --- a/native/src/renderer/null.rs +++ b/native/src/renderer/null.rs @@ -1,6 +1,6 @@ use crate::renderer::{self, Renderer}; use crate::text::{self, Text}; -use crate::{Background, Font, Point, Rectangle, Size, Vector}; +use crate::{Background, Font, Point, Rectangle, Size, Theme, Vector}; /// A renderer that does nothing. /// @@ -16,6 +16,8 @@ impl Null { } impl Renderer for Null { + type Theme = Theme; + fn with_layer(&mut self, _bounds: Rectangle, _f: impl FnOnce(&mut Self)) {} fn with_translation( diff --git a/native/src/user_interface.rs b/native/src/user_interface.rs index 2f2dc110..97a004e7 100644 --- a/native/src/user_interface.rs +++ b/native/src/user_interface.rs @@ -1,4 +1,5 @@ //! Implement your own event loop to drive a user interface. +use crate::application; use crate::event::{self, Event}; use crate::layout; use crate::mouse; @@ -28,6 +29,7 @@ pub struct UserInterface<'a, Message, Renderer> { impl<'a, Message, Renderer> UserInterface<'a, Message, Renderer> where Renderer: crate::Renderer, + Renderer::Theme: application::StyleSheet, { /// Builds a user interface for an [`Element`]. /// @@ -301,8 +303,10 @@ where /// [completing the last example](#example-1): /// /// ```no_run - /// use iced_native::{clipboard, Size, Point}; + /// use iced_native::clipboard; + /// use iced_native::renderer; /// use iced_native::user_interface::{self, UserInterface}; + /// use iced_native::{Size, Point, Theme}; /// use iced_wgpu::Renderer; /// /// # mod iced_wgpu { @@ -349,7 +353,7 @@ where /// ); /// /// // Draw the user interface - /// let mouse_cursor = user_interface.draw(&mut renderer, cursor_position); + /// let mouse_cursor = user_interface.draw(&mut renderer, &Theme::default(), &renderer::Style::default(), cursor_position); /// /// cache = user_interface.into_cache(); /// @@ -364,6 +368,8 @@ where pub fn draw( &mut self, renderer: &mut Renderer, + theme: &Renderer::Theme, + style: &renderer::Style, cursor_position: Point, ) -> mouse::Interaction { // TODO: Move to shell level (?) @@ -395,7 +401,8 @@ where self.root.widget.draw( renderer, - &renderer::Style::default(), + theme, + style, Layout::new(&self.base), base_cursor, &viewport, @@ -436,7 +443,8 @@ where renderer.with_layer(overlay_bounds, |renderer| { overlay.draw( renderer, - &renderer::Style::default(), + theme, + style, Layout::new(layout), cursor_position, ); diff --git a/native/src/widget.rs b/native/src/widget.rs index 8417dad1..9fe96e33 100644 --- a/native/src/widget.rs +++ b/native/src/widget.rs @@ -125,6 +125,7 @@ where fn draw( &self, renderer: &mut Renderer, + theme: &Renderer::Theme, style: &renderer::Style, layout: Layout<'_>, cursor_position: Point, diff --git a/native/src/widget/button.rs b/native/src/widget/button.rs index b03d9f27..d4e88424 100644 --- a/native/src/widget/button.rs +++ b/native/src/widget/button.rs @@ -12,7 +12,7 @@ use crate::{ Rectangle, Shell, Vector, Widget, }; -pub use iced_style::button::{Style, StyleSheet}; +pub use iced_style::button::{Appearance, StyleSheet}; /// A generic widget that produces a message when pressed. /// @@ -55,20 +55,25 @@ pub use iced_style::button::{Style, StyleSheet}; /// } /// ``` #[allow(missing_debug_implementations)] -pub struct Button<'a, Message, Renderer> { +pub struct Button<'a, Message, Renderer> +where + Renderer: crate::Renderer, + Renderer::Theme: StyleSheet, +{ state: &'a mut State, content: Element<'a, Message, Renderer>, on_press: Option<Message>, width: Length, height: Length, padding: Padding, - style_sheet: Box<dyn StyleSheet + 'a>, + style: <Renderer::Theme as StyleSheet>::Style, } impl<'a, Message, Renderer> Button<'a, Message, Renderer> where Message: Clone, Renderer: crate::Renderer, + Renderer::Theme: StyleSheet, { /// Creates a new [`Button`] with some local [`State`] and the given /// content. @@ -83,7 +88,7 @@ where width: Length::Shrink, height: Length::Shrink, padding: Padding::new(5), - style_sheet: Default::default(), + style: Default::default(), } } @@ -112,12 +117,12 @@ where self } - /// Sets the style of the [`Button`]. + /// Sets the style of this [`Button`]. pub fn style( mut self, - style_sheet: impl Into<Box<dyn StyleSheet + 'a>>, + style: <Renderer::Theme as StyleSheet>::Style, ) -> Self { - self.style_sheet = style_sheet.into(); + self.style = style; self } } @@ -195,23 +200,29 @@ pub fn draw<'a, Renderer: crate::Renderer>( bounds: Rectangle, cursor_position: Point, is_enabled: bool, - style_sheet: &dyn StyleSheet, + style_sheet: &dyn StyleSheet< + Style = <Renderer::Theme as StyleSheet>::Style, + >, + style: <Renderer::Theme as StyleSheet>::Style, state: impl FnOnce() -> &'a State, -) -> Style { +) -> Appearance +where + Renderer::Theme: StyleSheet, +{ let is_mouse_over = bounds.contains(cursor_position); let styling = if !is_enabled { - style_sheet.disabled() + style_sheet.disabled(style) } else if is_mouse_over { let state = state(); if state.is_pressed { - style_sheet.pressed() + style_sheet.pressed(style) } else { - style_sheet.hovered() + style_sheet.hovered(style) } } else { - style_sheet.active() + style_sheet.active(style) }; if styling.background.is_some() || styling.border_width > 0.0 { @@ -287,6 +298,7 @@ impl<'a, Message, Renderer> Widget<Message, Renderer> where Message: Clone, Renderer: crate::Renderer, + Renderer::Theme: StyleSheet, { fn width(&self) -> Length { self.width @@ -354,6 +366,7 @@ where fn draw( &self, renderer: &mut Renderer, + theme: &Renderer::Theme, _style: &renderer::Style, layout: Layout<'_>, cursor_position: Point, @@ -367,12 +380,14 @@ where bounds, cursor_position, self.on_press.is_some(), - self.style_sheet.as_ref(), + theme, + self.style, || &self.state, ); self.content.draw( renderer, + theme, &renderer::Style { text_color: styling.text_color, }, @@ -397,6 +412,7 @@ impl<'a, Message, Renderer> From<Button<'a, Message, Renderer>> where Message: 'a + Clone, Renderer: 'a + crate::Renderer, + Renderer::Theme: StyleSheet, { fn from( button: Button<'a, Message, Renderer>, diff --git a/native/src/widget/checkbox.rs b/native/src/widget/checkbox.rs index b6d920df..9e7f183a 100644 --- a/native/src/widget/checkbox.rs +++ b/native/src/widget/checkbox.rs @@ -12,7 +12,7 @@ use crate::{ Widget, }; -pub use iced_style::checkbox::{Style, StyleSheet}; +pub use iced_style::checkbox::{Appearance, StyleSheet}; /// A box that can be checked. /// @@ -32,7 +32,11 @@ pub use iced_style::checkbox::{Style, StyleSheet}; /// ///  #[allow(missing_debug_implementations)] -pub struct Checkbox<'a, Message, Renderer: text::Renderer> { +pub struct Checkbox<'a, Message, Renderer> +where + Renderer: text::Renderer, + Renderer::Theme: StyleSheet + widget::text::StyleSheet, +{ is_checked: bool, on_toggle: Box<dyn Fn(bool) -> Message + 'a>, label: String, @@ -41,10 +45,14 @@ pub struct Checkbox<'a, Message, Renderer: text::Renderer> { spacing: u16, text_size: Option<u16>, font: Renderer::Font, - style_sheet: Box<dyn StyleSheet + 'a>, + style: <Renderer::Theme as StyleSheet>::Style, } -impl<'a, Message, Renderer: text::Renderer> Checkbox<'a, Message, Renderer> { +impl<'a, Message, Renderer> Checkbox<'a, Message, Renderer> +where + Renderer: text::Renderer, + Renderer::Theme: StyleSheet + widget::text::StyleSheet, +{ /// The default size of a [`Checkbox`]. const DEFAULT_SIZE: u16 = 20; @@ -72,7 +80,7 @@ impl<'a, Message, Renderer: text::Renderer> Checkbox<'a, Message, Renderer> { spacing: Self::DEFAULT_SPACING, text_size: None, font: Renderer::Font::default(), - style_sheet: Default::default(), + style: Default::default(), } } @@ -111,9 +119,9 @@ impl<'a, Message, Renderer: text::Renderer> Checkbox<'a, Message, Renderer> { /// Sets the style of the [`Checkbox`]. pub fn style( mut self, - style_sheet: impl Into<Box<dyn StyleSheet + 'a>>, + style: impl Into<<Renderer::Theme as StyleSheet>::Style>, ) -> Self { - self.style_sheet = style_sheet.into(); + self.style = style.into(); self } } @@ -122,6 +130,7 @@ impl<'a, Message, Renderer> Widget<Message, Renderer> for Checkbox<'a, Message, Renderer> where Renderer: text::Renderer, + Renderer::Theme: StyleSheet + widget::text::StyleSheet, { fn width(&self) -> Length { self.width @@ -197,6 +206,7 @@ where fn draw( &self, renderer: &mut Renderer, + theme: &Renderer::Theme, style: &renderer::Style, layout: Layout<'_>, cursor_position: Point, @@ -208,9 +218,9 @@ where let mut children = layout.children(); let custom_style = if is_mouse_over { - self.style_sheet.hovered(self.is_checked) + theme.hovered(self.style, self.is_checked) } else { - self.style_sheet.active(self.is_checked) + theme.active(self.style, self.is_checked) }; { @@ -252,9 +262,11 @@ where style, label_layout, &self.label, - self.font.clone(), self.text_size, - custom_style.text_color, + self.font.clone(), + widget::text::Appearance { + color: custom_style.text_color, + }, alignment::Horizontal::Left, alignment::Vertical::Center, ); @@ -265,8 +277,9 @@ where impl<'a, Message, Renderer> From<Checkbox<'a, Message, Renderer>> for Element<'a, Message, Renderer> where - Renderer: 'a + text::Renderer, Message: 'a, + Renderer: 'a + text::Renderer, + Renderer::Theme: StyleSheet + widget::text::StyleSheet, { fn from( checkbox: Checkbox<'a, Message, Renderer>, diff --git a/native/src/widget/column.rs b/native/src/widget/column.rs index 268218b1..01ddd9f1 100644 --- a/native/src/widget/column.rs +++ b/native/src/widget/column.rs @@ -187,13 +187,21 @@ where fn draw( &self, renderer: &mut Renderer, + theme: &Renderer::Theme, style: &renderer::Style, layout: Layout<'_>, cursor_position: Point, viewport: &Rectangle, ) { for (child, layout) in self.children.iter().zip(layout.children()) { - child.draw(renderer, style, layout, cursor_position, viewport); + child.draw( + renderer, + theme, + style, + layout, + cursor_position, + viewport, + ); } } diff --git a/native/src/widget/container.rs b/native/src/widget/container.rs index 0e7c301e..493aa67b 100644 --- a/native/src/widget/container.rs +++ b/native/src/widget/container.rs @@ -12,13 +12,17 @@ use crate::{ use std::u32; -pub use iced_style::container::{Style, StyleSheet}; +pub use iced_style::container::{Appearance, StyleSheet}; /// An element decorating some content. /// /// It is normally used for alignment purposes. #[allow(missing_debug_implementations)] -pub struct Container<'a, Message, Renderer> { +pub struct Container<'a, Message, Renderer> +where + Renderer: crate::Renderer, + Renderer::Theme: StyleSheet, +{ padding: Padding, width: Length, height: Length, @@ -26,13 +30,14 @@ pub struct Container<'a, Message, Renderer> { max_height: u32, horizontal_alignment: alignment::Horizontal, vertical_alignment: alignment::Vertical, - style_sheet: Box<dyn StyleSheet + 'a>, + style: <Renderer::Theme as StyleSheet>::Style, content: Element<'a, Message, Renderer>, } impl<'a, Message, Renderer> Container<'a, Message, Renderer> where Renderer: crate::Renderer, + Renderer::Theme: StyleSheet, { /// Creates an empty [`Container`]. pub fn new<T>(content: T) -> Self @@ -47,7 +52,7 @@ where max_height: u32::MAX, horizontal_alignment: alignment::Horizontal::Left, vertical_alignment: alignment::Vertical::Top, - style_sheet: Default::default(), + style: Default::default(), content: content.into(), } } @@ -109,9 +114,9 @@ where /// Sets the style of the [`Container`]. pub fn style( mut self, - style_sheet: impl Into<Box<dyn StyleSheet + 'a>>, + style: impl Into<<Renderer::Theme as StyleSheet>::Style>, ) -> Self { - self.style_sheet = style_sheet.into(); + self.style = style.into(); self } } @@ -146,6 +151,7 @@ impl<'a, Message, Renderer> Widget<Message, Renderer> for Container<'a, Message, Renderer> where Renderer: crate::Renderer, + Renderer::Theme: StyleSheet, { fn width(&self) -> Length { self.width @@ -209,17 +215,19 @@ where fn draw( &self, renderer: &mut Renderer, + theme: &Renderer::Theme, renderer_style: &renderer::Style, layout: Layout<'_>, cursor_position: Point, viewport: &Rectangle, ) { - let style = self.style_sheet.style(); + let style = theme.appearance(self.style); draw_background(renderer, &style, layout.bounds()); self.content.draw( renderer, + theme, &renderer::Style { text_color: style .text_color @@ -244,20 +252,20 @@ where /// Draws the background of a [`Container`] given its [`Style`] and its `bounds`. pub fn draw_background<Renderer>( renderer: &mut Renderer, - style: &Style, + appearance: &Appearance, bounds: Rectangle, ) where Renderer: crate::Renderer, { - if style.background.is_some() || style.border_width > 0.0 { + if appearance.background.is_some() || appearance.border_width > 0.0 { renderer.fill_quad( renderer::Quad { bounds, - border_radius: style.border_radius, - border_width: style.border_width, - border_color: style.border_color, + border_radius: appearance.border_radius, + border_width: appearance.border_width, + border_color: appearance.border_color, }, - style + appearance .background .unwrap_or(Background::Color(Color::TRANSPARENT)), ); @@ -267,8 +275,9 @@ pub fn draw_background<Renderer>( impl<'a, Message, Renderer> From<Container<'a, Message, Renderer>> for Element<'a, Message, Renderer> where - Renderer: 'a + crate::Renderer, Message: 'a, + Renderer: 'a + crate::Renderer, + Renderer::Theme: StyleSheet, { fn from( column: Container<'a, Message, Renderer>, diff --git a/native/src/widget/image.rs b/native/src/widget/image.rs index 8e7a28e5..72075bd1 100644 --- a/native/src/widget/image.rs +++ b/native/src/widget/image.rs @@ -136,6 +136,7 @@ where fn draw( &self, renderer: &mut Renderer, + _theme: &Renderer::Theme, _style: &renderer::Style, layout: Layout<'_>, _cursor_position: Point, diff --git a/native/src/widget/image/viewer.rs b/native/src/widget/image/viewer.rs index 840b88e5..1aa75aa0 100644 --- a/native/src/widget/image/viewer.rs +++ b/native/src/widget/image/viewer.rs @@ -303,6 +303,7 @@ where fn draw( &self, renderer: &mut Renderer, + _theme: &Renderer::Theme, _style: &renderer::Style, layout: Layout<'_>, _cursor_position: Point, diff --git a/native/src/widget/pane_grid.rs b/native/src/widget/pane_grid.rs index 0ceec83e..eb969dbf 100644 --- a/native/src/widget/pane_grid.rs +++ b/native/src/widget/pane_grid.rs @@ -36,6 +36,7 @@ use crate::mouse; use crate::overlay; use crate::renderer; use crate::touch; +use crate::widget::container; use crate::{ Clipboard, Color, Element, Layout, Length, Point, Rectangle, Shell, Size, Vector, Widget, @@ -93,7 +94,11 @@ pub use iced_style::pane_grid::{Line, StyleSheet}; /// .on_resize(10, Message::PaneResized); /// ``` #[allow(missing_debug_implementations)] -pub struct PaneGrid<'a, Message, Renderer> { +pub struct PaneGrid<'a, Message, Renderer> +where + Renderer: crate::Renderer, + Renderer::Theme: StyleSheet + container::StyleSheet, +{ state: &'a mut state::Internal, action: &'a mut state::Action, elements: Vec<(Pane, Content<'a, Message, Renderer>)>, @@ -103,12 +108,13 @@ pub struct PaneGrid<'a, Message, Renderer> { on_click: Option<Box<dyn Fn(Pane) -> Message + 'a>>, on_drag: Option<Box<dyn Fn(DragEvent) -> Message + 'a>>, on_resize: Option<(u16, Box<dyn Fn(ResizeEvent) -> Message + 'a>)>, - style_sheet: Box<dyn StyleSheet + 'a>, + style: <Renderer::Theme as StyleSheet>::Style, } impl<'a, Message, Renderer> PaneGrid<'a, Message, Renderer> where Renderer: crate::Renderer, + Renderer::Theme: StyleSheet + container::StyleSheet, { /// Creates a [`PaneGrid`] with the given [`State`] and view function. /// @@ -136,7 +142,7 @@ where on_click: None, on_drag: None, on_resize: None, - style_sheet: Default::default(), + style: Default::default(), } } @@ -196,8 +202,11 @@ where } /// Sets the style of the [`PaneGrid`]. - pub fn style(mut self, style: impl Into<Box<dyn StyleSheet + 'a>>) -> Self { - self.style_sheet = style.into(); + pub fn style( + mut self, + style: impl Into<<Renderer::Theme as StyleSheet>::Style>, + ) -> Self { + self.style = style.into(); self } } @@ -468,11 +477,12 @@ pub fn draw<Renderer, T>( layout: Layout<'_>, cursor_position: Point, renderer: &mut Renderer, - style: &renderer::Style, + theme: &Renderer::Theme, + default_style: &renderer::Style, viewport: &Rectangle, spacing: u16, resize_leeway: Option<u16>, - style_sheet: &dyn StyleSheet, + style: <Renderer::Theme as StyleSheet>::Style, elements: impl Iterator<Item = (Pane, T)>, draw_pane: impl Fn( T, @@ -484,6 +494,7 @@ pub fn draw<Renderer, T>( ), ) where Renderer: crate::Renderer, + Renderer::Theme: StyleSheet, { let picked_pane = action.picked_pane(); @@ -545,7 +556,7 @@ pub fn draw<Renderer, T>( draw_pane( pane, renderer, - style, + default_style, layout, pane_cursor_position, viewport, @@ -558,7 +569,7 @@ pub fn draw<Renderer, T>( draw_pane( pane, renderer, - style, + default_style, layout, pane_cursor_position, viewport, @@ -569,9 +580,9 @@ pub fn draw<Renderer, T>( if let Some((axis, split_region, is_picked)) = picked_split { let highlight = if is_picked { - style_sheet.picked_split() + theme.picked_split(style) } else { - style_sheet.hovered_split() + theme.hovered_split(style) }; if let Some(highlight) = highlight { @@ -649,6 +660,7 @@ impl<'a, Message, Renderer> Widget<Message, Renderer> for PaneGrid<'a, Message, Renderer> where Renderer: crate::Renderer, + Renderer::Theme: StyleSheet + container::StyleSheet, { fn width(&self) -> Length { self.width @@ -754,6 +766,7 @@ where fn draw( &self, renderer: &mut Renderer, + theme: &Renderer::Theme, style: &renderer::Style, layout: Layout<'_>, cursor_position: Point, @@ -765,14 +778,22 @@ where layout, cursor_position, renderer, + theme, style, viewport, self.spacing, self.on_resize.as_ref().map(|(leeway, _)| *leeway), - self.style_sheet.as_ref(), + self.style, self.elements.iter().map(|(pane, content)| (*pane, content)), |pane, renderer, style, layout, cursor_position, rectangle| { - pane.draw(renderer, style, layout, cursor_position, rectangle); + pane.draw( + renderer, + theme, + style, + layout, + cursor_position, + rectangle, + ); }, ) } @@ -793,8 +814,9 @@ where impl<'a, Message, Renderer> From<PaneGrid<'a, Message, Renderer>> for Element<'a, Message, Renderer> where - Renderer: 'a + crate::Renderer, Message: 'a, + Renderer: 'a + crate::Renderer, + Renderer::Theme: StyleSheet + container::StyleSheet, { fn from( pane_grid: PaneGrid<'a, Message, Renderer>, diff --git a/native/src/widget/pane_grid/content.rs b/native/src/widget/pane_grid/content.rs index 407f5458..4c9e65c9 100644 --- a/native/src/widget/pane_grid/content.rs +++ b/native/src/widget/pane_grid/content.rs @@ -11,22 +11,27 @@ use crate::{Clipboard, Element, Layout, Point, Rectangle, Shell, Size}; /// /// [`Pane`]: crate::widget::pane_grid::Pane #[allow(missing_debug_implementations)] -pub struct Content<'a, Message, Renderer> { +pub struct Content<'a, Message, Renderer> +where + Renderer: crate::Renderer, + Renderer::Theme: container::StyleSheet, +{ title_bar: Option<TitleBar<'a, Message, Renderer>>, body: Element<'a, Message, Renderer>, - style_sheet: Box<dyn container::StyleSheet + 'a>, + style: <Renderer::Theme as container::StyleSheet>::Style, } impl<'a, Message, Renderer> Content<'a, Message, Renderer> where Renderer: crate::Renderer, + Renderer::Theme: container::StyleSheet, { /// Creates a new [`Content`] with the provided body. pub fn new(body: impl Into<Element<'a, Message, Renderer>>) -> Self { Self { title_bar: None, body: body.into(), - style_sheet: Default::default(), + style: Default::default(), } } @@ -42,9 +47,9 @@ where /// Sets the style of the [`Content`]. pub fn style( mut self, - style_sheet: impl Into<Box<dyn container::StyleSheet + 'a>>, + style: impl Into<<Renderer::Theme as container::StyleSheet>::Style>, ) -> Self { - self.style_sheet = style_sheet.into(); + self.style = style.into(); self } } @@ -52,6 +57,7 @@ where impl<'a, Message, Renderer> Content<'a, Message, Renderer> where Renderer: crate::Renderer, + Renderer::Theme: container::StyleSheet, { /// Draws the [`Content`] with the provided [`Renderer`] and [`Layout`]. /// @@ -59,15 +65,18 @@ where pub fn draw( &self, renderer: &mut Renderer, + theme: &Renderer::Theme, style: &renderer::Style, layout: Layout<'_>, cursor_position: Point, viewport: &Rectangle, ) { + use container::StyleSheet; + let bounds = layout.bounds(); { - let style = self.style_sheet.style(); + let style = theme.appearance(self.style); container::draw_background(renderer, &style, bounds); } @@ -81,6 +90,7 @@ where title_bar.draw( renderer, + theme, style, title_bar_layout, cursor_position, @@ -90,14 +100,21 @@ where self.body.draw( renderer, + theme, style, body_layout, cursor_position, viewport, ); } else { - self.body - .draw(renderer, style, layout, cursor_position, viewport); + self.body.draw( + renderer, + theme, + style, + layout, + cursor_position, + viewport, + ); } } @@ -239,6 +256,7 @@ where impl<'a, Message, Renderer> Draggable for &Content<'a, Message, Renderer> where Renderer: crate::Renderer, + Renderer::Theme: container::StyleSheet, { fn can_be_dragged_at( &self, @@ -260,6 +278,7 @@ impl<'a, T, Message, Renderer> From<T> for Content<'a, Message, Renderer> where T: Into<Element<'a, Message, Renderer>>, Renderer: crate::Renderer, + Renderer::Theme: container::StyleSheet, { fn from(element: T) -> Self { Self::new(element) diff --git a/native/src/widget/pane_grid/title_bar.rs b/native/src/widget/pane_grid/title_bar.rs index 6713724a..14c3ab4e 100644 --- a/native/src/widget/pane_grid/title_bar.rs +++ b/native/src/widget/pane_grid/title_bar.rs @@ -12,17 +12,22 @@ use crate::{ /// /// [`Pane`]: crate::widget::pane_grid::Pane #[allow(missing_debug_implementations)] -pub struct TitleBar<'a, Message, Renderer> { +pub struct TitleBar<'a, Message, Renderer> +where + Renderer: crate::Renderer, + Renderer::Theme: container::StyleSheet, +{ content: Element<'a, Message, Renderer>, controls: Option<Element<'a, Message, Renderer>>, padding: Padding, always_show_controls: bool, - style_sheet: Box<dyn container::StyleSheet + 'a>, + style: <Renderer::Theme as container::StyleSheet>::Style, } impl<'a, Message, Renderer> TitleBar<'a, Message, Renderer> where Renderer: crate::Renderer, + Renderer::Theme: container::StyleSheet, { /// Creates a new [`TitleBar`] with the given content. pub fn new<E>(content: E) -> Self @@ -34,7 +39,7 @@ where controls: None, padding: Padding::ZERO, always_show_controls: false, - style_sheet: Default::default(), + style: Default::default(), } } @@ -56,9 +61,9 @@ where /// Sets the style of the [`TitleBar`]. pub fn style( mut self, - style: impl Into<Box<dyn container::StyleSheet + 'a>>, + style: impl Into<<Renderer::Theme as container::StyleSheet>::Style>, ) -> Self { - self.style_sheet = style.into(); + self.style = style.into(); self } @@ -79,6 +84,7 @@ where impl<'a, Message, Renderer> TitleBar<'a, Message, Renderer> where Renderer: crate::Renderer, + Renderer::Theme: container::StyleSheet, { /// Draws the [`TitleBar`] with the provided [`Renderer`] and [`Layout`]. /// @@ -86,14 +92,17 @@ where pub fn draw( &self, renderer: &mut Renderer, + theme: &Renderer::Theme, inherited_style: &renderer::Style, layout: Layout<'_>, cursor_position: Point, viewport: &Rectangle, show_controls: bool, ) { + use container::StyleSheet; + let bounds = layout.bounds(); - let style = self.style_sheet.style(); + let style = theme.appearance(self.style); let inherited_style = renderer::Style { text_color: style.text_color.unwrap_or(inherited_style.text_color), }; @@ -118,6 +127,7 @@ where } controls.draw( renderer, + theme, &inherited_style, controls_layout, cursor_position, @@ -129,6 +139,7 @@ where if show_title { self.content.draw( renderer, + theme, &inherited_style, title_layout, cursor_position, diff --git a/native/src/widget/pick_list.rs b/native/src/widget/pick_list.rs index 0374aef7..c6cfcc01 100644 --- a/native/src/widget/pick_list.rs +++ b/native/src/widget/pick_list.rs @@ -9,19 +9,23 @@ use crate::overlay::menu::{self, Menu}; use crate::renderer; use crate::text::{self, Text}; use crate::touch; +use crate::widget::container; +use crate::widget::scrollable; use crate::{ Clipboard, Element, Layout, Length, Padding, Point, Rectangle, Shell, Size, Widget, }; use std::borrow::Cow; -pub use iced_style::pick_list::{Style, StyleSheet}; +pub use iced_style::pick_list::{Appearance, StyleSheet}; /// A widget for selecting a single value from a list of options. #[allow(missing_debug_implementations)] -pub struct PickList<'a, T, Message, Renderer: text::Renderer> +pub struct PickList<'a, T, Message, Renderer> where [T]: ToOwned<Owned = Vec<T>>, + Renderer: text::Renderer, + Renderer::Theme: StyleSheet, { state: &'a mut State<T>, on_selected: Box<dyn Fn(T) -> Message>, @@ -32,7 +36,7 @@ where padding: Padding, text_size: Option<u16>, font: Renderer::Font, - style_sheet: Box<dyn StyleSheet + 'a>, + style: <Renderer::Theme as StyleSheet>::Style, } /// The local state of a [`PickList`]. @@ -64,11 +68,12 @@ impl<T> Default for State<T> { } } -impl<'a, T: 'a, Message, Renderer: text::Renderer> - PickList<'a, T, Message, Renderer> +impl<'a, T: 'a, Message, Renderer> PickList<'a, T, Message, Renderer> where T: ToString + Eq, [T]: ToOwned<Owned = Vec<T>>, + Renderer: text::Renderer, + Renderer::Theme: StyleSheet, { /// The default padding of a [`PickList`]. pub const DEFAULT_PADDING: Padding = Padding::new(5); @@ -92,7 +97,7 @@ where text_size: None, padding: Self::DEFAULT_PADDING, font: Default::default(), - style_sheet: Default::default(), + style: Default::default(), } } @@ -129,9 +134,9 @@ where /// Sets the style of the [`PickList`]. pub fn style( mut self, - style_sheet: impl Into<Box<dyn StyleSheet + 'a>>, + style: impl Into<<Renderer::Theme as StyleSheet>::Style>, ) -> Self { - self.style_sheet = style_sheet.into(); + self.style = style.into(); self } } @@ -317,12 +322,13 @@ pub fn overlay<'a, T, Message, Renderer>( text_size: Option<u16>, font: Renderer::Font, options: &'a [T], - style_sheet: &dyn StyleSheet, + style: <Renderer::Theme as StyleSheet>::Style, ) -> Option<overlay::Element<'a, Message, Renderer>> where + T: Clone + ToString, Message: 'a, Renderer: text::Renderer + 'a, - T: Clone + ToString, + Renderer::Theme: StyleSheet, { if state.is_open { let bounds = layout.bounds(); @@ -336,7 +342,7 @@ where .width(bounds.width.round() as u16) .padding(padding) .font(font) - .style(style_sheet.menu()); + .style(style); if let Some(text_size) = text_size { menu = menu.text_size(text_size); @@ -351,6 +357,7 @@ where /// Draws a [`PickList`]. pub fn draw<T, Renderer>( renderer: &mut Renderer, + theme: &Renderer::Theme, layout: Layout<'_>, cursor_position: Point, padding: Padding, @@ -358,9 +365,10 @@ pub fn draw<T, Renderer>( font: &Renderer::Font, placeholder: Option<&str>, selected: Option<&T>, - style_sheet: &dyn StyleSheet, + style: <Renderer::Theme as StyleSheet>::Style, ) where Renderer: text::Renderer, + Renderer::Theme: StyleSheet, T: ToString, { let bounds = layout.bounds(); @@ -368,9 +376,9 @@ pub fn draw<T, Renderer>( let is_selected = selected.is_some(); let style = if is_mouse_over { - style_sheet.hovered() + theme.hovered(style) } else { - style_sheet.active() + theme.active(style) }; renderer.fill_quad( @@ -430,6 +438,7 @@ where [T]: ToOwned<Owned = Vec<T>>, Message: 'static, Renderer: text::Renderer + 'a, + Renderer::Theme: StyleSheet, { fn width(&self) -> Length { self.width @@ -490,6 +499,7 @@ where fn draw( &self, renderer: &mut Renderer, + theme: &Renderer::Theme, _style: &renderer::Style, layout: Layout<'_>, cursor_position: Point, @@ -497,6 +507,7 @@ where ) { draw( renderer, + theme, layout, cursor_position, self.padding, @@ -504,7 +515,7 @@ where &self.font, self.placeholder.as_ref().map(String::as_str), self.selected.as_ref(), - self.style_sheet.as_ref(), + self.style, ) } @@ -520,7 +531,7 @@ where self.text_size, self.font.clone(), &self.options, - self.style_sheet.as_ref(), + self.style, ) } } @@ -530,8 +541,14 @@ impl<'a, T: 'a, Message, Renderer> Into<Element<'a, Message, Renderer>> where T: Clone + ToString + Eq, [T]: ToOwned<Owned = Vec<T>>, - Renderer: text::Renderer + 'a, Message: 'static, + Renderer: text::Renderer + 'a, + Renderer::Theme: StyleSheet + + container::StyleSheet + + scrollable::StyleSheet + + menu::StyleSheet, + <Renderer::Theme as StyleSheet>::Style: + Into<<Renderer::Theme as menu::StyleSheet>::Style>, { fn into(self) -> Element<'a, Message, Renderer> { Element::new(self) diff --git a/native/src/widget/progress_bar.rs b/native/src/widget/progress_bar.rs index c26c38fa..4eb7438a 100644 --- a/native/src/widget/progress_bar.rs +++ b/native/src/widget/progress_bar.rs @@ -5,13 +5,13 @@ use crate::{Color, Element, Layout, Length, Point, Rectangle, Size, Widget}; use std::ops::RangeInclusive; -pub use iced_style::progress_bar::{Style, StyleSheet}; +pub use iced_style::progress_bar::{Appearance, StyleSheet}; /// A bar that displays progress. /// /// # Example /// ``` -/// # use iced_native::widget::ProgressBar; +/// # type ProgressBar = iced_native::widget::ProgressBar<iced_native::renderer::Null>; /// let value = 50.0; /// /// ProgressBar::new(0.0..=100.0, value); @@ -19,15 +19,23 @@ pub use iced_style::progress_bar::{Style, StyleSheet}; /// ///  #[allow(missing_debug_implementations)] -pub struct ProgressBar<'a> { +pub struct ProgressBar<Renderer> +where + Renderer: crate::Renderer, + Renderer::Theme: StyleSheet, +{ range: RangeInclusive<f32>, value: f32, width: Length, height: Option<Length>, - style_sheet: Box<dyn StyleSheet + 'a>, + style: <Renderer::Theme as StyleSheet>::Style, } -impl<'a> ProgressBar<'a> { +impl<Renderer> ProgressBar<Renderer> +where + Renderer: crate::Renderer, + Renderer::Theme: StyleSheet, +{ /// The default height of a [`ProgressBar`]. pub const DEFAULT_HEIGHT: u16 = 30; @@ -42,7 +50,7 @@ impl<'a> ProgressBar<'a> { range, width: Length::Fill, height: None, - style_sheet: Default::default(), + style: Default::default(), } } @@ -61,16 +69,17 @@ impl<'a> ProgressBar<'a> { /// Sets the style of the [`ProgressBar`]. pub fn style( mut self, - style_sheet: impl Into<Box<dyn StyleSheet + 'a>>, + style: impl Into<<Renderer::Theme as StyleSheet>::Style>, ) -> Self { - self.style_sheet = style_sheet.into(); + self.style = style.into(); self } } -impl<'a, Message, Renderer> Widget<Message, Renderer> for ProgressBar<'a> +impl<'a, Message, Renderer> Widget<Message, Renderer> for ProgressBar<Renderer> where Renderer: crate::Renderer, + Renderer::Theme: StyleSheet, { fn width(&self) -> Length { self.width @@ -97,6 +106,7 @@ where fn draw( &self, renderer: &mut Renderer, + theme: &Renderer::Theme, _style: &renderer::Style, layout: Layout<'_>, _cursor_position: Point, @@ -112,7 +122,7 @@ where / (range_end - range_start) }; - let style = self.style_sheet.style(); + let style = theme.appearance(self.style); renderer.fill_quad( renderer::Quad { @@ -141,13 +151,16 @@ where } } -impl<'a, Message, Renderer> From<ProgressBar<'a>> +impl<'a, Message, Renderer> From<ProgressBar<Renderer>> for Element<'a, Message, Renderer> where - Renderer: 'a + crate::Renderer, Message: 'a, + Renderer: 'a + crate::Renderer, + Renderer::Theme: StyleSheet, { - fn from(progress_bar: ProgressBar<'a>) -> Element<'a, Message, Renderer> { + fn from( + progress_bar: ProgressBar<Renderer>, + ) -> Element<'a, Message, Renderer> { Element::new(progress_bar) } } diff --git a/native/src/widget/radio.rs b/native/src/widget/radio.rs index 657ae786..ba45a0f4 100644 --- a/native/src/widget/radio.rs +++ b/native/src/widget/radio.rs @@ -12,14 +12,14 @@ use crate::{ Shell, Widget, }; -pub use iced_style::radio::{Style, StyleSheet}; +pub use iced_style::radio::{Appearance, StyleSheet}; /// A circular button representing a choice. /// /// # Example /// ``` -/// # type Radio<'a, Message> = -/// # iced_native::widget::Radio<'a, Message, iced_native::renderer::Null>; +/// # type Radio<Message> = +/// # iced_native::widget::Radio<Message, iced_native::renderer::Null>; /// # /// #[derive(Debug, Clone, Copy, PartialEq, Eq)] /// pub enum Choice { @@ -41,7 +41,11 @@ pub use iced_style::radio::{Style, StyleSheet}; /// ///  #[allow(missing_debug_implementations)] -pub struct Radio<'a, Message, Renderer: text::Renderer> { +pub struct Radio<Message, Renderer> +where + Renderer: text::Renderer, + Renderer::Theme: StyleSheet, +{ is_selected: bool, on_click: Message, label: String, @@ -50,12 +54,14 @@ pub struct Radio<'a, Message, Renderer: text::Renderer> { spacing: u16, text_size: Option<u16>, font: Renderer::Font, - style_sheet: Box<dyn StyleSheet + 'a>, + style: <Renderer::Theme as StyleSheet>::Style, } -impl<'a, Message, Renderer: text::Renderer> Radio<'a, Message, Renderer> +impl<Message, Renderer> Radio<Message, Renderer> where Message: Clone, + Renderer: text::Renderer, + Renderer::Theme: StyleSheet, { /// The default size of a [`Radio`] button. pub const DEFAULT_SIZE: u16 = 28; @@ -90,7 +96,7 @@ where spacing: Self::DEFAULT_SPACING, //15 text_size: None, font: Default::default(), - style_sheet: Default::default(), + style: Default::default(), } } @@ -127,18 +133,18 @@ where /// Sets the style of the [`Radio`] button. pub fn style( mut self, - style_sheet: impl Into<Box<dyn StyleSheet + 'a>>, + style: impl Into<<Renderer::Theme as StyleSheet>::Style>, ) -> Self { - self.style_sheet = style_sheet.into(); + self.style = style.into(); self } } -impl<'a, Message, Renderer> Widget<Message, Renderer> - for Radio<'a, Message, Renderer> +impl<Message, Renderer> Widget<Message, Renderer> for Radio<Message, Renderer> where Message: Clone, Renderer: text::Renderer, + Renderer::Theme: StyleSheet + widget::text::StyleSheet, { fn width(&self) -> Length { self.width @@ -211,6 +217,7 @@ where fn draw( &self, renderer: &mut Renderer, + theme: &Renderer::Theme, style: &renderer::Style, layout: Layout<'_>, cursor_position: Point, @@ -222,9 +229,9 @@ where let mut children = layout.children(); let custom_style = if is_mouse_over { - self.style_sheet.hovered() + theme.hovered(self.style) } else { - self.style_sheet.active() + theme.active(self.style) }; { @@ -270,9 +277,11 @@ where style, label_layout, &self.label, - self.font.clone(), self.text_size, - custom_style.text_color, + self.font.clone(), + widget::text::Appearance { + color: custom_style.text_color, + }, alignment::Horizontal::Left, alignment::Vertical::Center, ); @@ -280,15 +289,14 @@ where } } -impl<'a, Message, Renderer> From<Radio<'a, Message, Renderer>> +impl<'a, Message, Renderer> From<Radio<Message, Renderer>> for Element<'a, Message, Renderer> where Message: 'a + Clone, Renderer: 'a + text::Renderer, + Renderer::Theme: StyleSheet + widget::text::StyleSheet, { - fn from( - radio: Radio<'a, Message, Renderer>, - ) -> Element<'a, Message, Renderer> { + fn from(radio: Radio<Message, Renderer>) -> Element<'a, Message, Renderer> { Element::new(radio) } } diff --git a/native/src/widget/row.rs b/native/src/widget/row.rs index 7a7c70c6..9cff74c6 100644 --- a/native/src/widget/row.rs +++ b/native/src/widget/row.rs @@ -187,13 +187,21 @@ where fn draw( &self, renderer: &mut Renderer, + theme: &Renderer::Theme, style: &renderer::Style, layout: Layout<'_>, cursor_position: Point, viewport: &Rectangle, ) { for (child, layout) in self.children.iter().zip(layout.children()) { - child.draw(renderer, style, layout, cursor_position, viewport); + child.draw( + renderer, + theme, + style, + layout, + cursor_position, + viewport, + ); } } diff --git a/native/src/widget/rule.rs b/native/src/widget/rule.rs index 69619583..26285df4 100644 --- a/native/src/widget/rule.rs +++ b/native/src/widget/rule.rs @@ -3,25 +3,33 @@ use crate::layout; use crate::renderer; use crate::{Color, Element, Layout, Length, Point, Rectangle, Size, Widget}; -pub use iced_style::rule::{FillMode, Style, StyleSheet}; +pub use iced_style::rule::{Appearance, FillMode, StyleSheet}; /// Display a horizontal or vertical rule for dividing content. #[allow(missing_debug_implementations)] -pub struct Rule<'a> { +pub struct Rule<Renderer> +where + Renderer: crate::Renderer, + Renderer::Theme: StyleSheet, +{ width: Length, height: Length, is_horizontal: bool, - style_sheet: Box<dyn StyleSheet + 'a>, + style: <Renderer::Theme as StyleSheet>::Style, } -impl<'a> Rule<'a> { +impl<Renderer> Rule<Renderer> +where + Renderer: crate::Renderer, + Renderer::Theme: StyleSheet, +{ /// Creates a horizontal [`Rule`] with the given height. pub fn horizontal(height: u16) -> Self { Rule { width: Length::Fill, height: Length::Units(height), is_horizontal: true, - style_sheet: Default::default(), + style: Default::default(), } } @@ -31,23 +39,24 @@ impl<'a> Rule<'a> { width: Length::from(Length::Units(width)), height: Length::Fill, is_horizontal: false, - style_sheet: Default::default(), + style: Default::default(), } } /// Sets the style of the [`Rule`]. pub fn style( mut self, - style_sheet: impl Into<Box<dyn StyleSheet + 'a>>, + style: impl Into<<Renderer::Theme as StyleSheet>::Style>, ) -> Self { - self.style_sheet = style_sheet.into(); + self.style = style.into(); self } } -impl<'a, Message, Renderer> Widget<Message, Renderer> for Rule<'a> +impl<Message, Renderer> Widget<Message, Renderer> for Rule<Renderer> where Renderer: crate::Renderer, + Renderer::Theme: StyleSheet, { fn width(&self) -> Length { self.width @@ -70,13 +79,14 @@ where fn draw( &self, renderer: &mut Renderer, + theme: &Renderer::Theme, _style: &renderer::Style, layout: Layout<'_>, _cursor_position: Point, _viewport: &Rectangle, ) { let bounds = layout.bounds(); - let style = self.style_sheet.style(); + let style = theme.style(self.style); let bounds = if self.is_horizontal { let line_y = (bounds.y + (bounds.height / 2.0) @@ -120,12 +130,14 @@ where } } -impl<'a, Message, Renderer> From<Rule<'a>> for Element<'a, Message, Renderer> +impl<'a, Message, Renderer> From<Rule<Renderer>> + for Element<'a, Message, Renderer> where - Renderer: 'a + crate::Renderer, Message: 'a, + Renderer: 'a + crate::Renderer, + Renderer::Theme: StyleSheet, { - fn from(rule: Rule<'a>) -> Element<'a, Message, Renderer> { + fn from(rule: Rule<Renderer>) -> Element<'a, Message, Renderer> { Element::new(rule) } } diff --git a/native/src/widget/scrollable.rs b/native/src/widget/scrollable.rs index 8958f6da..5d550315 100644 --- a/native/src/widget/scrollable.rs +++ b/native/src/widget/scrollable.rs @@ -25,7 +25,11 @@ pub mod style { /// A widget that can vertically display an infinite amount of content with a /// scrollbar. #[allow(missing_debug_implementations)] -pub struct Scrollable<'a, Message, Renderer> { +pub struct Scrollable<'a, Message, Renderer> +where + Renderer: crate::Renderer, + Renderer::Theme: StyleSheet, +{ state: &'a mut State, height: Length, max_height: u32, @@ -34,10 +38,14 @@ pub struct Scrollable<'a, Message, Renderer> { scroller_width: u16, content: Column<'a, Message, Renderer>, on_scroll: Option<Box<dyn Fn(f32) -> Message + 'a>>, - style_sheet: Box<dyn StyleSheet + 'a>, + style: <Renderer::Theme as StyleSheet>::Style, } -impl<'a, Message, Renderer: crate::Renderer> Scrollable<'a, Message, Renderer> { +impl<'a, Message, Renderer> Scrollable<'a, Message, Renderer> +where + Renderer: crate::Renderer, + Renderer::Theme: StyleSheet, +{ /// Creates a new [`Scrollable`] with the given [`State`]. pub fn new(state: &'a mut State) -> Self { Scrollable { @@ -49,7 +57,7 @@ impl<'a, Message, Renderer: crate::Renderer> Scrollable<'a, Message, Renderer> { scroller_width: 10, content: Column::new(), on_scroll: None, - style_sheet: Default::default(), + style: Default::default(), } } @@ -132,9 +140,9 @@ impl<'a, Message, Renderer: crate::Renderer> Scrollable<'a, Message, Renderer> { /// Sets the style of the [`Scrollable`] . pub fn style( mut self, - style_sheet: impl Into<Box<dyn StyleSheet + 'a>>, + style: impl Into<<Renderer::Theme as StyleSheet>::Style>, ) -> Self { - self.style_sheet = style_sheet.into(); + self.style = style.into(); self } @@ -428,15 +436,17 @@ pub fn mouse_interaction( pub fn draw<Renderer>( state: &State, renderer: &mut Renderer, + theme: &Renderer::Theme, layout: Layout<'_>, cursor_position: Point, scrollbar_width: u16, scrollbar_margin: u16, scroller_width: u16, - style_sheet: &dyn StyleSheet, + style: <Renderer::Theme as StyleSheet>::Style, draw_content: impl FnOnce(&mut Renderer, Layout<'_>, Point, &Rectangle), ) where Renderer: crate::Renderer, + Renderer::Theme: StyleSheet, { let bounds = layout.bounds(); let content_layout = layout.children().next().unwrap(); @@ -482,11 +492,11 @@ pub fn draw<Renderer>( }); let style = if state.is_scroller_grabbed() { - style_sheet.dragging() + theme.dragging(style) } else if is_mouse_over_scrollbar { - style_sheet.hovered() + theme.hovered(style) } else { - style_sheet.active() + theme.active(style) }; let is_scrollbar_visible = @@ -618,6 +628,7 @@ impl<'a, Message, Renderer> Widget<Message, Renderer> for Scrollable<'a, Message, Renderer> where Renderer: crate::Renderer, + Renderer::Theme: StyleSheet, { fn width(&self) -> Length { Widget::<Message, Renderer>::width(&self.content) @@ -702,6 +713,7 @@ where fn draw( &self, renderer: &mut Renderer, + theme: &Renderer::Theme, style: &renderer::Style, layout: Layout<'_>, cursor_position: Point, @@ -710,15 +722,17 @@ where draw( &self.state, renderer, + theme, layout, cursor_position, self.scrollbar_width, self.scrollbar_margin, self.scroller_width, - self.style_sheet.as_ref(), + self.style, |renderer, layout, cursor_position, viewport| { self.content.draw( renderer, + theme, style, layout, cursor_position, @@ -914,8 +928,9 @@ struct Scroller { impl<'a, Message, Renderer> From<Scrollable<'a, Message, Renderer>> for Element<'a, Message, Renderer> where - Renderer: 'a + crate::Renderer, Message: 'a, + Renderer: 'a + crate::Renderer, + Renderer::Theme: StyleSheet, { fn from( scrollable: Scrollable<'a, Message, Renderer>, diff --git a/native/src/widget/slider.rs b/native/src/widget/slider.rs index f2e84ea9..bda31327 100644 --- a/native/src/widget/slider.rs +++ b/native/src/widget/slider.rs @@ -13,7 +13,7 @@ use crate::{ use std::ops::RangeInclusive; -pub use iced_style::slider::{Handle, HandleShape, Style, StyleSheet}; +pub use iced_style::slider::{Appearance, Handle, HandleShape, StyleSheet}; /// An horizontal bar and a handle that selects a single value from a range of /// values. @@ -25,8 +25,10 @@ pub use iced_style::slider::{Handle, HandleShape, Style, StyleSheet}; /// /// # Example /// ``` -/// # use iced_native::widget::slider::{self, Slider}; +/// # use iced_native::widget::slider; +/// # use iced_native::renderer::Null; /// # +/// # type Slider<'a, T, Message> = slider::Slider<'a, T, Message, Null>; /// #[derive(Clone)] /// pub enum Message { /// SliderChanged(f32), @@ -40,7 +42,11 @@ pub use iced_style::slider::{Handle, HandleShape, Style, StyleSheet}; /// ///  #[allow(missing_debug_implementations)] -pub struct Slider<'a, T, Message> { +pub struct Slider<'a, T, Message, Renderer> +where + Renderer: crate::Renderer, + Renderer::Theme: StyleSheet, +{ state: &'a mut State, range: RangeInclusive<T>, step: T, @@ -49,13 +55,15 @@ pub struct Slider<'a, T, Message> { on_release: Option<Message>, width: Length, height: u16, - style_sheet: Box<dyn StyleSheet + 'a>, + style: <Renderer::Theme as StyleSheet>::Style, } -impl<'a, T, Message> Slider<'a, T, Message> +impl<'a, T, Message, Renderer> Slider<'a, T, Message, Renderer> where T: Copy + From<u8> + std::cmp::PartialOrd, Message: Clone, + Renderer: crate::Renderer, + Renderer::Theme: StyleSheet, { /// The default height of a [`Slider`]. pub const DEFAULT_HEIGHT: u16 = 22; @@ -99,7 +107,7 @@ where on_release: None, width: Length::Fill, height: Self::DEFAULT_HEIGHT, - style_sheet: Default::default(), + style: Default::default(), } } @@ -129,9 +137,9 @@ where /// Sets the style of the [`Slider`]. pub fn style( mut self, - style_sheet: impl Into<Box<dyn StyleSheet + 'a>>, + style: impl Into<<Renderer::Theme as StyleSheet>::Style>, ) -> Self { - self.style_sheet = style_sheet.into(); + self.style = style.into(); self } @@ -230,26 +238,29 @@ where } /// Draws a [`Slider`]. -pub fn draw<T>( - renderer: &mut impl crate::Renderer, +pub fn draw<T, R>( + renderer: &mut R, layout: Layout<'_>, cursor_position: Point, state: &State, value: T, range: &RangeInclusive<T>, - style_sheet: &dyn StyleSheet, + style_sheet: &dyn StyleSheet<Style = <R::Theme as StyleSheet>::Style>, + style: <R::Theme as StyleSheet>::Style, ) where T: Into<f64> + Copy, + R: crate::Renderer, + R::Theme: StyleSheet, { let bounds = layout.bounds(); let is_mouse_over = bounds.contains(cursor_position); let style = if state.is_dragging { - style_sheet.dragging() + style_sheet.dragging(style) } else if is_mouse_over { - style_sheet.hovered() + style_sheet.hovered(style) } else { - style_sheet.active() + style_sheet.active(style) }; let rail_y = bounds.y + (bounds.height / 2.0).round(); @@ -357,11 +368,12 @@ impl State { } impl<'a, T, Message, Renderer> Widget<Message, Renderer> - for Slider<'a, T, Message> + for Slider<'a, T, Message, Renderer> where T: Copy + Into<f64> + num_traits::FromPrimitive, Message: Clone, Renderer: crate::Renderer, + Renderer::Theme: StyleSheet, { fn width(&self) -> Length { self.width @@ -410,6 +422,7 @@ where fn draw( &self, renderer: &mut Renderer, + theme: &Renderer::Theme, _style: &renderer::Style, layout: Layout<'_>, cursor_position: Point, @@ -422,7 +435,8 @@ where &self.state, self.value, &self.range, - self.style_sheet.as_ref(), + theme, + self.style, ) } @@ -437,14 +451,17 @@ where } } -impl<'a, T, Message, Renderer> From<Slider<'a, T, Message>> +impl<'a, T, Message, Renderer> From<Slider<'a, T, Message, Renderer>> for Element<'a, Message, Renderer> where T: 'a + Copy + Into<f64> + num_traits::FromPrimitive, Message: 'a + Clone, Renderer: 'a + crate::Renderer, + Renderer::Theme: StyleSheet, { - fn from(slider: Slider<'a, T, Message>) -> Element<'a, Message, Renderer> { + fn from( + slider: Slider<'a, T, Message, Renderer>, + ) -> Element<'a, Message, Renderer> { Element::new(slider) } } diff --git a/native/src/widget/space.rs b/native/src/widget/space.rs index 4135d1b8..81338306 100644 --- a/native/src/widget/space.rs +++ b/native/src/widget/space.rs @@ -60,6 +60,7 @@ where fn draw( &self, _renderer: &mut Renderer, + _theme: &Renderer::Theme, _style: &renderer::Style, _layout: Layout<'_>, _cursor_position: Point, diff --git a/native/src/widget/svg.rs b/native/src/widget/svg.rs index 008ab356..76b3eb8b 100644 --- a/native/src/widget/svg.rs +++ b/native/src/widget/svg.rs @@ -110,6 +110,7 @@ where fn draw( &self, renderer: &mut Renderer, + _theme: &Renderer::Theme, _style: &renderer::Style, layout: Layout<'_>, _cursor_position: Point, diff --git a/native/src/widget/text.rs b/native/src/widget/text.rs index a7855c30..242247b0 100644 --- a/native/src/widget/text.rs +++ b/native/src/widget/text.rs @@ -3,45 +3,57 @@ use crate::alignment; use crate::layout; use crate::renderer; use crate::text; -use crate::{Color, Element, Layout, Length, Point, Rectangle, Size, Widget}; +use crate::{Element, Layout, Length, Point, Rectangle, Size, Widget}; + +pub use iced_style::text::{Appearance, StyleSheet}; /// A paragraph of text. /// /// # Example /// /// ``` +/// # use iced_native::Color; +/// # /// # type Text = iced_native::widget::Text<iced_native::renderer::Null>; /// # /// Text::new("I <3 iced!") -/// .color([0.0, 0.0, 1.0]) -/// .size(40); +/// .size(40) +/// .style(Color::from([0.0, 0.0, 1.0])); /// ``` /// ///  -#[derive(Debug)] -pub struct Text<Renderer: text::Renderer> { +#[allow(missing_debug_implementations)] +pub struct Text<Renderer> +where + Renderer: text::Renderer, + Renderer::Theme: StyleSheet, +{ content: String, size: Option<u16>, - color: Option<Color>, - font: Renderer::Font, width: Length, height: Length, horizontal_alignment: alignment::Horizontal, vertical_alignment: alignment::Vertical, + font: Renderer::Font, + style: <Renderer::Theme as StyleSheet>::Style, } -impl<Renderer: text::Renderer> Text<Renderer> { +impl<Renderer> Text<Renderer> +where + Renderer: text::Renderer, + Renderer::Theme: StyleSheet, +{ /// Create a new fragment of [`Text`] with the given contents. pub fn new<T: Into<String>>(label: T) -> Self { Text { content: label.into(), size: None, - color: None, font: Default::default(), width: Length::Shrink, height: Length::Shrink, horizontal_alignment: alignment::Horizontal::Left, vertical_alignment: alignment::Vertical::Top, + style: Default::default(), } } @@ -51,12 +63,6 @@ impl<Renderer: text::Renderer> Text<Renderer> { self } - /// Sets the [`Color`] of the [`Text`]. - pub fn color<C: Into<Color>>(mut self, color: C) -> Self { - self.color = Some(color.into()); - self - } - /// Sets the [`Font`] of the [`Text`]. /// /// [`Font`]: crate::text::Renderer::Font @@ -65,6 +71,15 @@ impl<Renderer: text::Renderer> Text<Renderer> { self } + /// Sets the [`Color`] of the [`Text`]. + pub fn style( + mut self, + style: impl Into<<Renderer::Theme as StyleSheet>::Style>, + ) -> Self { + self.style = style.into(); + self + } + /// Sets the width of the [`Text`] boundaries. pub fn width(mut self, width: Length) -> Self { self.width = width; @@ -99,6 +114,7 @@ impl<Renderer: text::Renderer> Text<Renderer> { impl<Message, Renderer> Widget<Message, Renderer> for Text<Renderer> where Renderer: text::Renderer, + Renderer::Theme: StyleSheet, { fn width(&self) -> Length { self.width @@ -130,6 +146,7 @@ where fn draw( &self, renderer: &mut Renderer, + theme: &Renderer::Theme, style: &renderer::Style, layout: Layout<'_>, _cursor_position: Point, @@ -140,9 +157,9 @@ where style, layout, &self.content, - self.font.clone(), self.size, - self.color, + self.font.clone(), + theme.appearance(self.style), self.horizontal_alignment, self.vertical_alignment, ); @@ -164,9 +181,9 @@ pub fn draw<Renderer>( style: &renderer::Style, layout: Layout<'_>, content: &str, - font: Renderer::Font, size: Option<u16>, - color: Option<Color>, + font: Renderer::Font, + appearance: Appearance, horizontal_alignment: alignment::Horizontal, vertical_alignment: alignment::Vertical, ) where @@ -190,7 +207,7 @@ pub fn draw<Renderer>( content, size: f32::from(size.unwrap_or(renderer.default_size())), bounds: Rectangle { x, y, ..bounds }, - color: color.unwrap_or(style.text_color), + color: appearance.color.unwrap_or(style.text_color), font, horizontal_alignment, vertical_alignment, @@ -201,23 +218,28 @@ impl<'a, Message, Renderer> From<Text<Renderer>> for Element<'a, Message, Renderer> where Renderer: text::Renderer + 'a, + Renderer::Theme: StyleSheet, { fn from(text: Text<Renderer>) -> Element<'a, Message, Renderer> { Element::new(text) } } -impl<Renderer: text::Renderer> Clone for Text<Renderer> { +impl<Renderer> Clone for Text<Renderer> +where + Renderer: text::Renderer, + Renderer::Theme: StyleSheet, +{ fn clone(&self) -> Self { Self { content: self.content.clone(), size: self.size, - color: self.color, - font: self.font.clone(), width: self.width, height: self.height, horizontal_alignment: self.horizontal_alignment, vertical_alignment: self.vertical_alignment, + font: self.font.clone(), + style: self.style, } } } diff --git a/native/src/widget/text_input.rs b/native/src/widget/text_input.rs index 5ecd68e9..d345cec3 100644 --- a/native/src/widget/text_input.rs +++ b/native/src/widget/text_input.rs @@ -24,7 +24,7 @@ use crate::{ Shell, Size, Vector, Widget, }; -pub use iced_style::text_input::{Style, StyleSheet}; +pub use iced_style::text_input::{Appearance, StyleSheet}; /// A field that can be filled with text. /// @@ -52,7 +52,11 @@ pub use iced_style::text_input::{Style, StyleSheet}; /// ``` ///  #[allow(missing_debug_implementations)] -pub struct TextInput<'a, Message, Renderer: text::Renderer> { +pub struct TextInput<'a, Message, Renderer> +where + Renderer: text::Renderer, + Renderer::Theme: StyleSheet, +{ state: &'a mut State, placeholder: String, value: Value, @@ -63,13 +67,14 @@ pub struct TextInput<'a, Message, Renderer: text::Renderer> { size: Option<u16>, on_change: Box<dyn Fn(String) -> Message + 'a>, on_submit: Option<Message>, - style_sheet: Box<dyn StyleSheet + 'a>, + style: <Renderer::Theme as StyleSheet>::Style, } impl<'a, Message, Renderer> TextInput<'a, Message, Renderer> where Message: Clone, Renderer: text::Renderer, + Renderer::Theme: StyleSheet, { /// Creates a new [`TextInput`]. /// @@ -98,7 +103,7 @@ where size: None, on_change: Box::new(on_change), on_submit: None, - style_sheet: Default::default(), + style: Default::default(), } } @@ -143,9 +148,9 @@ where /// Sets the style of the [`TextInput`]. pub fn style( mut self, - style_sheet: impl Into<Box<dyn StyleSheet + 'a>>, + style: impl Into<<Renderer::Theme as StyleSheet>::Style>, ) -> Self { - self.style_sheet = style_sheet.into(); + self.style = style.into(); self } @@ -161,12 +166,14 @@ where pub fn draw( &self, renderer: &mut Renderer, + theme: &Renderer::Theme, layout: Layout<'_>, cursor_position: Point, value: Option<&Value>, ) { draw( renderer, + theme, layout, cursor_position, &self.state, @@ -175,7 +182,7 @@ where self.size, &self.font, self.is_secure, - self.style_sheet.as_ref(), + self.style, ) } } @@ -575,6 +582,7 @@ where /// [`Renderer`]: text::Renderer pub fn draw<Renderer>( renderer: &mut Renderer, + theme: &Renderer::Theme, layout: Layout<'_>, cursor_position: Point, state: &State, @@ -583,9 +591,10 @@ pub fn draw<Renderer>( size: Option<u16>, font: &Renderer::Font, is_secure: bool, - style_sheet: &dyn StyleSheet, + style: <Renderer::Theme as StyleSheet>::Style, ) where Renderer: text::Renderer, + Renderer::Theme: StyleSheet, { let secure_value = is_secure.then(|| value.secure()); let value = secure_value.as_ref().unwrap_or(&value); @@ -595,22 +604,22 @@ pub fn draw<Renderer>( let is_mouse_over = bounds.contains(cursor_position); - let style = if state.is_focused() { - style_sheet.focused() + let appearance = if state.is_focused() { + theme.focused(style) } else if is_mouse_over { - style_sheet.hovered() + theme.hovered(style) } else { - style_sheet.active() + theme.active(style) }; renderer.fill_quad( renderer::Quad { bounds, - border_radius: style.border_radius, - border_width: style.border_width, - border_color: style.border_color, + border_radius: appearance.border_radius, + border_width: appearance.border_width, + border_color: appearance.border_color, }, - style.background, + appearance.background, ); let text = value.to_string(); @@ -642,7 +651,7 @@ pub fn draw<Renderer>( border_width: 0.0, border_color: Color::TRANSPARENT, }, - style_sheet.value_color(), + theme.value_color(style), )), offset, ) @@ -686,7 +695,7 @@ pub fn draw<Renderer>( border_width: 0.0, border_color: Color::TRANSPARENT, }, - style_sheet.selection_color(), + theme.selection_color(style), )), if end == right { right_offset @@ -714,9 +723,9 @@ pub fn draw<Renderer>( renderer.fill_text(Text { content: if text.is_empty() { placeholder } else { &text }, color: if text.is_empty() { - style_sheet.placeholder_color() + theme.placeholder_color(style) } else { - style_sheet.value_color() + theme.value_color(style) }, font: font.clone(), bounds: Rectangle { @@ -756,6 +765,7 @@ impl<'a, Message, Renderer> Widget<Message, Renderer> where Message: Clone, Renderer: text::Renderer, + Renderer::Theme: StyleSheet, { fn width(&self) -> Length { self.width @@ -812,12 +822,13 @@ where fn draw( &self, renderer: &mut Renderer, + theme: &Renderer::Theme, _style: &renderer::Style, layout: Layout<'_>, cursor_position: Point, _viewport: &Rectangle, ) { - self.draw(renderer, layout, cursor_position, None) + self.draw(renderer, theme, layout, cursor_position, None) } } @@ -826,6 +837,7 @@ impl<'a, Message, Renderer> From<TextInput<'a, Message, Renderer>> where Message: 'a + Clone, Renderer: 'a + text::Renderer, + Renderer::Theme: StyleSheet, { fn from( text_input: TextInput<'a, Message, Renderer>, diff --git a/native/src/widget/toggler.rs b/native/src/widget/toggler.rs index 6d7592f3..0936c271 100644 --- a/native/src/widget/toggler.rs +++ b/native/src/widget/toggler.rs @@ -5,13 +5,13 @@ use crate::layout; use crate::mouse; use crate::renderer; use crate::text; -use crate::widget::{Row, Text}; +use crate::widget::{self, Row, Text}; use crate::{ Alignment, Clipboard, Element, Event, Layout, Length, Point, Rectangle, Shell, Widget, }; -pub use iced_style::toggler::{Style, StyleSheet}; +pub use iced_style::toggler::{Appearance, StyleSheet}; /// A toggler widget. /// @@ -29,7 +29,11 @@ pub use iced_style::toggler::{Style, StyleSheet}; /// Toggler::new(is_active, String::from("Toggle me!"), |b| Message::TogglerToggled(b)); /// ``` #[allow(missing_debug_implementations)] -pub struct Toggler<'a, Message, Renderer: text::Renderer> { +pub struct Toggler<'a, Message, Renderer> +where + Renderer: text::Renderer, + Renderer::Theme: StyleSheet, +{ is_active: bool, on_toggle: Box<dyn Fn(bool) -> Message + 'a>, label: Option<String>, @@ -39,10 +43,14 @@ pub struct Toggler<'a, Message, Renderer: text::Renderer> { text_alignment: alignment::Horizontal, spacing: u16, font: Renderer::Font, - style_sheet: Box<dyn StyleSheet + 'a>, + style: <Renderer::Theme as StyleSheet>::Style, } -impl<'a, Message, Renderer: text::Renderer> Toggler<'a, Message, Renderer> { +impl<'a, Message, Renderer> Toggler<'a, Message, Renderer> +where + Renderer: text::Renderer, + Renderer::Theme: StyleSheet, +{ /// The default size of a [`Toggler`]. pub const DEFAULT_SIZE: u16 = 20; @@ -72,7 +80,7 @@ impl<'a, Message, Renderer: text::Renderer> Toggler<'a, Message, Renderer> { text_alignment: alignment::Horizontal::Left, spacing: 0, font: Renderer::Font::default(), - style_sheet: Default::default(), + style: Default::default(), } } @@ -117,9 +125,9 @@ impl<'a, Message, Renderer: text::Renderer> Toggler<'a, Message, Renderer> { /// Sets the style of the [`Toggler`]. pub fn style( mut self, - style_sheet: impl Into<Box<dyn StyleSheet + 'a>>, + style: impl Into<<Renderer::Theme as StyleSheet>::Style>, ) -> Self { - self.style_sheet = style_sheet.into(); + self.style = style.into(); self } } @@ -128,6 +136,7 @@ impl<'a, Message, Renderer> Widget<Message, Renderer> for Toggler<'a, Message, Renderer> where Renderer: text::Renderer, + Renderer::Theme: StyleSheet + widget::text::StyleSheet, { fn width(&self) -> Length { self.width @@ -208,6 +217,7 @@ where fn draw( &self, renderer: &mut Renderer, + theme: &Renderer::Theme, style: &renderer::Style, layout: Layout<'_>, cursor_position: Point, @@ -230,9 +240,9 @@ where style, label_layout, &label, - self.font.clone(), self.text_size, - None, + self.font.clone(), + Default::default(), self.text_alignment, alignment::Vertical::Center, ); @@ -244,9 +254,9 @@ where let is_mouse_over = bounds.contains(cursor_position); let style = if is_mouse_over { - self.style_sheet.hovered(self.is_active) + theme.hovered(self.style, self.is_active) } else { - self.style_sheet.active(self.is_active) + theme.active(self.style, self.is_active) }; let border_radius = bounds.height as f32 / BORDER_RADIUS_RATIO; @@ -300,8 +310,9 @@ where impl<'a, Message, Renderer> From<Toggler<'a, Message, Renderer>> for Element<'a, Message, Renderer> where - Renderer: 'a + text::Renderer, Message: 'a, + Renderer: 'a + text::Renderer, + Renderer::Theme: StyleSheet + widget::text::StyleSheet, { fn from( toggler: Toggler<'a, Message, Renderer>, diff --git a/native/src/widget/tooltip.rs b/native/src/widget/tooltip.rs index c929395f..0548e9da 100644 --- a/native/src/widget/tooltip.rs +++ b/native/src/widget/tooltip.rs @@ -4,6 +4,7 @@ use crate::layout; use crate::mouse; use crate::renderer; use crate::text; +use crate::widget; use crate::widget::container; use crate::widget::text::Text; use crate::{ @@ -13,18 +14,23 @@ use crate::{ /// An element to display a widget over another. #[allow(missing_debug_implementations)] -pub struct Tooltip<'a, Message, Renderer: text::Renderer> { +pub struct Tooltip<'a, Message, Renderer> +where + Renderer: text::Renderer, + Renderer::Theme: container::StyleSheet + widget::text::StyleSheet, +{ content: Element<'a, Message, Renderer>, tooltip: Text<Renderer>, position: Position, - style_sheet: Box<dyn container::StyleSheet + 'a>, gap: u16, padding: u16, + style: <Renderer::Theme as container::StyleSheet>::Style, } impl<'a, Message, Renderer> Tooltip<'a, Message, Renderer> where Renderer: text::Renderer, + Renderer::Theme: container::StyleSheet + widget::text::StyleSheet, { /// The default padding of a [`Tooltip`] drawn by this renderer. const DEFAULT_PADDING: u16 = 5; @@ -41,9 +47,9 @@ where content: content.into(), tooltip: Text::new(tooltip.to_string()), position, - style_sheet: Default::default(), gap: 0, padding: Self::DEFAULT_PADDING, + style: Default::default(), } } @@ -76,9 +82,9 @@ where /// Sets the style of the [`Tooltip`]. pub fn style( mut self, - style_sheet: impl Into<Box<dyn container::StyleSheet + 'a>>, + style: impl Into<<Renderer::Theme as container::StyleSheet>::Style>, ) -> Self { - self.style_sheet = style_sheet.into(); + self.style = style.into(); self } } @@ -99,8 +105,9 @@ pub enum Position { } /// Draws a [`Tooltip`]. -pub fn draw<Renderer: crate::Renderer>( +pub fn draw<Renderer>( renderer: &mut Renderer, + theme: &Renderer::Theme, inherited_style: &renderer::Style, layout: Layout<'_>, cursor_position: Point, @@ -108,7 +115,7 @@ pub fn draw<Renderer: crate::Renderer>( position: Position, gap: u16, padding: u16, - style_sheet: &dyn container::StyleSheet, + style: <Renderer::Theme as container::StyleSheet>::Style, layout_text: impl FnOnce(&Renderer, &layout::Limits) -> layout::Node, draw_text: impl FnOnce( &mut Renderer, @@ -117,12 +124,17 @@ pub fn draw<Renderer: crate::Renderer>( Point, &Rectangle, ), -) { +) where + Renderer: crate::Renderer, + Renderer::Theme: container::StyleSheet, +{ + use container::StyleSheet; + let bounds = layout.bounds(); if bounds.contains(cursor_position) { let gap = f32::from(gap); - let style = style_sheet.style(); + let style = theme.appearance(style); let defaults = renderer::Style { text_color: style.text_color.unwrap_or(inherited_style.text_color), @@ -213,6 +225,7 @@ impl<'a, Message, Renderer> Widget<Message, Renderer> for Tooltip<'a, Message, Renderer> where Renderer: text::Renderer, + Renderer::Theme: container::StyleSheet + widget::text::StyleSheet, { fn width(&self) -> Length { self.content.width() @@ -267,6 +280,7 @@ where fn draw( &self, renderer: &mut Renderer, + theme: &Renderer::Theme, inherited_style: &renderer::Style, layout: Layout<'_>, cursor_position: Point, @@ -274,6 +288,7 @@ where ) { self.content.draw( renderer, + theme, inherited_style, layout, cursor_position, @@ -284,6 +299,7 @@ where draw( renderer, + theme, inherited_style, layout, cursor_position, @@ -291,7 +307,7 @@ where self.position, self.gap, self.padding, - self.style_sheet.as_ref(), + self.style, |renderer, limits| { Widget::<(), Renderer>::layout(tooltip, renderer, limits) }, @@ -299,6 +315,7 @@ where Widget::<(), Renderer>::draw( tooltip, renderer, + theme, defaults, layout, cursor_position, @@ -312,8 +329,9 @@ where impl<'a, Message, Renderer> From<Tooltip<'a, Message, Renderer>> for Element<'a, Message, Renderer> where - Renderer: 'a + text::Renderer, Message: 'a, + Renderer: 'a + text::Renderer, + Renderer::Theme: container::StyleSheet + widget::text::StyleSheet, { fn from( tooltip: Tooltip<'a, Message, Renderer>, |