diff options
Diffstat (limited to 'core/src')
-rw-r--r-- | core/src/element.rs | 4 | ||||
-rw-r--r-- | core/src/image.rs | 4 | ||||
-rw-r--r-- | core/src/renderer.rs | 33 | ||||
-rw-r--r-- | core/src/renderer/null.rs | 58 | ||||
-rw-r--r-- | core/src/size.rs | 2 | ||||
-rw-r--r-- | core/src/svg.rs | 9 | ||||
-rw-r--r-- | core/src/widget/text.rs | 117 |
7 files changed, 148 insertions, 79 deletions
diff --git a/core/src/element.rs b/core/src/element.rs index 989eaa3b..7d918a2e 100644 --- a/core/src/element.rs +++ b/core/src/element.rs @@ -95,7 +95,7 @@ impl<'a, Message, Theme, Renderer> Element<'a, Message, Theme, Renderer> { /// /// ```no_run /// # mod iced { - /// # pub type Element<'a, Message> = iced_core::Element<'a, Message, iced_core::Theme, iced_core::renderer::Null>; + /// # pub type Element<'a, Message> = iced_core::Element<'a, Message, iced_core::Theme, ()>; /// # /// # pub mod widget { /// # pub fn row<'a, Message>(iter: impl IntoIterator<Item = super::Element<'a, Message>>) -> super::Element<'a, Message> { @@ -109,7 +109,7 @@ impl<'a, Message, Theme, Renderer> Element<'a, Message, Theme, Renderer> { /// # pub enum Message {} /// # pub struct Counter; /// # - /// # pub type Element<'a, Message> = iced_core::Element<'a, Message, iced_core::Theme, iced_core::renderer::Null>; + /// # pub type Element<'a, Message> = iced_core::Element<'a, Message, iced_core::Theme, ()>; /// # /// # impl Counter { /// # pub fn view(&self) -> Element<Message> { diff --git a/core/src/image.rs b/core/src/image.rs index e5fdcd83..32b95f03 100644 --- a/core/src/image.rs +++ b/core/src/image.rs @@ -186,11 +186,11 @@ pub trait Renderer: crate::Renderer { type Handle: Clone + Hash; /// Returns the dimensions of an image for the given [`Handle`]. - fn dimensions(&self, handle: &Self::Handle) -> Size<u32>; + fn measure_image(&self, handle: &Self::Handle) -> Size<u32>; /// Draws an image with the given [`Handle`] and inside the provided /// `bounds`. - fn draw( + fn draw_image( &mut self, handle: Self::Handle, filter_method: FilterMethod, diff --git a/core/src/renderer.rs b/core/src/renderer.rs index 1139b41c..6712314e 100644 --- a/core/src/renderer.rs +++ b/core/src/renderer.rs @@ -2,26 +2,47 @@ #[cfg(debug_assertions)] mod null; -#[cfg(debug_assertions)] -pub use null::Null; - use crate::{ Background, Border, Color, Rectangle, Shadow, Size, Transformation, Vector, }; /// A component that can be used by widgets to draw themselves on a screen. -pub trait Renderer: Sized { +pub trait Renderer { + /// Starts recording a new layer. + fn start_layer(&mut self); + + /// Ends recording a new layer. + /// + /// The new layer will clip its contents to the provided `bounds`. + fn end_layer(&mut self, bounds: Rectangle); + /// Draws the primitives recorded in the given closure in a new layer. /// /// The layer will clip its contents to the provided `bounds`. - fn with_layer(&mut self, bounds: Rectangle, f: impl FnOnce(&mut Self)); + fn with_layer(&mut self, bounds: Rectangle, f: impl FnOnce(&mut Self)) { + self.start_layer(); + f(self); + self.end_layer(bounds); + } + + /// Starts recording with a new [`Transformation`]. + fn start_transformation(&mut self); + + /// Ends recording a new layer. + /// + /// The new layer will clip its contents to the provided `bounds`. + fn end_transformation(&mut self, transformation: Transformation); /// Applies a [`Transformation`] to the primitives recorded in the given closure. fn with_transformation( &mut self, transformation: Transformation, f: impl FnOnce(&mut Self), - ); + ) { + self.start_transformation(); + f(self); + self.end_transformation(transformation); + } /// Applies a translation to the primitives recorded in the given closure. fn with_translation( diff --git a/core/src/renderer/null.rs b/core/src/renderer/null.rs index 83688ff7..c26ce1a5 100644 --- a/core/src/renderer/null.rs +++ b/core/src/renderer/null.rs @@ -1,5 +1,7 @@ use crate::alignment; +use crate::image; use crate::renderer::{self, Renderer}; +use crate::svg; use crate::text::{self, Text}; use crate::{ Background, Color, Font, Pixels, Point, Rectangle, Size, Transformation, @@ -7,28 +9,14 @@ use crate::{ use std::borrow::Cow; -/// A renderer that does nothing. -/// -/// It can be useful if you are writing tests! -#[derive(Debug, Clone, Copy, Default)] -pub struct Null; +impl Renderer for () { + fn start_layer(&mut self) {} -impl Null { - /// Creates a new [`Null`] renderer. - pub fn new() -> Null { - Null - } -} + fn end_layer(&mut self, _bounds: Rectangle) {} -impl Renderer for Null { - fn with_layer(&mut self, _bounds: Rectangle, _f: impl FnOnce(&mut Self)) {} + fn start_transformation(&mut self) {} - fn with_transformation( - &mut self, - _transformation: Transformation, - _f: impl FnOnce(&mut Self), - ) { - } + fn end_transformation(&mut self, _transformation: Transformation) {} fn clear(&mut self) {} @@ -40,7 +28,7 @@ impl Renderer for Null { } } -impl text::Renderer for Null { +impl text::Renderer for () { type Font = Font; type Paragraph = (); type Editor = (); @@ -174,3 +162,33 @@ impl text::Editor for () { ) { } } + +impl image::Renderer for () { + type Handle = (); + + fn measure_image(&self, _handle: &Self::Handle) -> Size<u32> { + Size::default() + } + + fn draw_image( + &mut self, + _handle: Self::Handle, + _filter_method: image::FilterMethod, + _bounds: Rectangle, + ) { + } +} + +impl svg::Renderer for () { + fn measure_svg(&self, _handle: &svg::Handle) -> Size<u32> { + Size::default() + } + + fn draw_svg( + &mut self, + _handle: svg::Handle, + _color: Option<Color>, + _bounds: Rectangle, + ) { + } +} diff --git a/core/src/size.rs b/core/src/size.rs index 267fc90e..55db759d 100644 --- a/core/src/size.rs +++ b/core/src/size.rs @@ -1,7 +1,7 @@ use crate::Vector; /// An amount of space in 2 dimensions. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] pub struct Size<T = f32> { /// The width. pub width: T, diff --git a/core/src/svg.rs b/core/src/svg.rs index d63e3c95..ab207cca 100644 --- a/core/src/svg.rs +++ b/core/src/svg.rs @@ -91,8 +91,13 @@ impl std::fmt::Debug for Data { /// [renderer]: crate::renderer pub trait Renderer: crate::Renderer { /// Returns the default dimensions of an SVG for the given [`Handle`]. - fn dimensions(&self, handle: &Handle) -> Size<u32>; + fn measure_svg(&self, handle: &Handle) -> Size<u32>; /// Draws an SVG with the given [`Handle`], an optional [`Color`] filter, and inside the provided `bounds`. - fn draw(&mut self, handle: Handle, color: Option<Color>, bounds: Rectangle); + fn draw_svg( + &mut self, + handle: Handle, + color: Option<Color>, + bounds: Rectangle, + ); } diff --git a/core/src/widget/text.rs b/core/src/widget/text.rs index 66e2d066..12f6956a 100644 --- a/core/src/widget/text.rs +++ b/core/src/widget/text.rs @@ -18,6 +18,7 @@ pub use text::{LineHeight, Shaping}; #[allow(missing_debug_implementations)] pub struct Text<'a, Theme, Renderer> where + Theme: Catalog, Renderer: text::Renderer, { content: Cow<'a, str>, @@ -29,18 +30,16 @@ where vertical_alignment: alignment::Vertical, font: Option<Renderer::Font>, shaping: Shaping, - style: Style<'a, Theme>, + class: Theme::Class<'a>, } impl<'a, Theme, Renderer> Text<'a, Theme, Renderer> where + Theme: Catalog, Renderer: text::Renderer, { /// Create a new fragment of [`Text`] with the given contents. - pub fn new(content: impl Into<Cow<'a, str>>) -> Self - where - Theme: DefaultStyle + 'a, - { + pub fn new(content: impl Into<Cow<'a, str>>) -> Self { Text { content: content.into(), size: None, @@ -51,7 +50,7 @@ where horizontal_alignment: alignment::Horizontal::Left, vertical_alignment: alignment::Vertical::Top, shaping: Shaping::Basic, - style: Box::new(Theme::default_style), + class: Theme::default(), } } @@ -75,25 +74,6 @@ where self } - /// Sets the style of the [`Text`]. - pub fn style(mut self, style: impl Fn(&Theme) -> Appearance + 'a) -> Self { - self.style = Box::new(style); - self - } - - /// Sets the [`Color`] of the [`Text`]. - pub fn color(self, color: impl Into<Color>) -> Self { - self.color_maybe(Some(color)) - } - - /// Sets the [`Color`] of the [`Text`], if `Some`. - pub fn color_maybe(mut self, color: Option<impl Into<Color>>) -> Self { - let color = color.map(Into::into); - - self.style = Box::new(move |_theme| Appearance { color }); - self - } - /// Sets the width of the [`Text`] boundaries. pub fn width(mut self, width: impl Into<Length>) -> Self { self.width = width.into(); @@ -129,6 +109,42 @@ where self.shaping = shaping; self } + + /// Sets the style of the [`Text`]. + #[must_use] + pub fn style(mut self, style: impl Fn(&Theme) -> Style + 'a) -> Self + where + Theme::Class<'a>: From<StyleFn<'a, Theme>>, + { + self.class = (Box::new(style) as StyleFn<'a, Theme>).into(); + self + } + + /// Sets the [`Color`] of the [`Text`]. + pub fn color(self, color: impl Into<Color>) -> Self + where + Theme::Class<'a>: From<StyleFn<'a, Theme>>, + { + self.color_maybe(Some(color)) + } + + /// Sets the [`Color`] of the [`Text`], if `Some`. + pub fn color_maybe(self, color: Option<impl Into<Color>>) -> Self + where + Theme::Class<'a>: From<StyleFn<'a, Theme>>, + { + let color = color.map(Into::into); + + self.style(move |_theme| Style { color }) + } + + /// Sets the style class of the [`Text`]. + #[cfg(feature = "advanced")] + #[must_use] + pub fn class(mut self, class: impl Into<Theme::Class<'a>>) -> Self { + self.class = class.into(); + self + } } /// The internal state of a [`Text`] widget. @@ -138,6 +154,7 @@ pub struct State<P: Paragraph>(P); impl<'a, Message, Theme, Renderer> Widget<Message, Theme, Renderer> for Text<'a, Theme, Renderer> where + Theme: Catalog, Renderer: text::Renderer, { fn tag(&self) -> tree::Tag { @@ -182,15 +199,15 @@ where tree: &Tree, renderer: &mut Renderer, theme: &Theme, - style: &renderer::Style, + defaults: &renderer::Style, layout: Layout<'_>, _cursor_position: mouse::Cursor, viewport: &Rectangle, ) { let state = tree.state.downcast_ref::<State<Renderer::Paragraph>>(); - let appearance = (self.style)(theme); + let style = theme.style(&self.class); - draw(renderer, style, layout, state, appearance, viewport); + draw(renderer, defaults, layout, state, style, viewport); } } @@ -250,7 +267,7 @@ pub fn draw<Renderer>( style: &renderer::Style, layout: Layout<'_>, state: &State<Renderer::Paragraph>, - appearance: Appearance, + appearance: Style, viewport: &Rectangle, ) where Renderer: text::Renderer, @@ -281,7 +298,7 @@ pub fn draw<Renderer>( impl<'a, Message, Theme, Renderer> From<Text<'a, Theme, Renderer>> for Element<'a, Message, Theme, Renderer> where - Theme: 'a, + Theme: Catalog + 'a, Renderer: text::Renderer + 'a, { fn from( @@ -293,7 +310,7 @@ where impl<'a, Theme, Renderer> From<&'a str> for Text<'a, Theme, Renderer> where - Theme: DefaultStyle + 'a, + Theme: Catalog + 'a, Renderer: text::Renderer, { fn from(content: &'a str) -> Self { @@ -304,7 +321,7 @@ where impl<'a, Message, Theme, Renderer> From<&'a str> for Element<'a, Message, Theme, Renderer> where - Theme: DefaultStyle + 'a, + Theme: Catalog + 'a, Renderer: text::Renderer + 'a, { fn from(content: &'a str) -> Self { @@ -314,30 +331,38 @@ where /// The appearance of some text. #[derive(Debug, Clone, Copy, Default)] -pub struct Appearance { +pub struct Style { /// The [`Color`] of the text. /// /// The default, `None`, means using the inherited color. pub color: Option<Color>, } -/// The style of some [`Text`]. -pub type Style<'a, Theme> = Box<dyn Fn(&Theme) -> Appearance + 'a>; +/// The theme catalog of a [`Text`]. +pub trait Catalog: Sized { + /// The item class of this [`Catalog`]. + type Class<'a>; -/// The default style of some [`Text`]. -pub trait DefaultStyle { - /// Returns the default style of some [`Text`]. - fn default_style(&self) -> Appearance; + /// The default class produced by this [`Catalog`]. + fn default<'a>() -> Self::Class<'a>; + + /// The [`Style`] of a class with the given status. + fn style(&self, item: &Self::Class<'_>) -> Style; } -impl DefaultStyle for Theme { - fn default_style(&self) -> Appearance { - Appearance::default() +/// A styling function for a [`Text`]. +/// +/// This is just a boxed closure: `Fn(&Theme, Status) -> Style`. +pub type StyleFn<'a, Theme> = Box<dyn Fn(&Theme) -> Style + 'a>; + +impl Catalog for Theme { + type Class<'a> = StyleFn<'a, Self>; + + fn default<'a>() -> Self::Class<'a> { + Box::new(|_theme| Style::default()) } -} -impl DefaultStyle for Color { - fn default_style(&self) -> Appearance { - Appearance { color: Some(*self) } + fn style(&self, class: &Self::Class<'_>) -> Style { + class(self) } } |