diff options
Diffstat (limited to '')
| -rw-r--r-- | core/Cargo.toml | 1 | ||||
| -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 | 
8 files changed, 149 insertions, 79 deletions
| diff --git a/core/Cargo.toml b/core/Cargo.toml index 29a95ad7..32d233ee 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -12,6 +12,7 @@ keywords.workspace = true  [features]  auto-detect-theme = ["dep:dark-light"] +advanced = []  [dependencies]  bitflags.workspace = true 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)      }  } | 
