diff options
| -rw-r--r-- | style/src/lib.rs | 1 | ||||
| -rw-r--r-- | style/src/qr_code.rs | 20 | ||||
| -rw-r--r-- | style/src/theme.rs | 41 | ||||
| -rw-r--r-- | widget/src/qr_code.rs | 52 | 
4 files changed, 94 insertions, 20 deletions
diff --git a/style/src/lib.rs b/style/src/lib.rs index e4097434..3c2865eb 100644 --- a/style/src/lib.rs +++ b/style/src/lib.rs @@ -24,6 +24,7 @@ pub mod menu;  pub mod pane_grid;  pub mod pick_list;  pub mod progress_bar; +pub mod qr_code;  pub mod radio;  pub mod rule;  pub mod scrollable; diff --git a/style/src/qr_code.rs b/style/src/qr_code.rs new file mode 100644 index 00000000..a024506c --- /dev/null +++ b/style/src/qr_code.rs @@ -0,0 +1,20 @@ +//! Change the appearance of a QR code. +use crate::core::Color; + +/// The appearance of a QR code. +#[derive(Debug, Clone, Copy)] +pub struct Appearance { +    /// The color of the QR code data cells +    pub cell: Color, +    /// The color of the QR code background +    pub background: Color, +} + +/// A set of rules that dictate the style of a QR code. +pub trait StyleSheet { +    /// The supported style of the [`StyleSheet`]. +    type Style: Default; + +    /// Produces the style of a QR code. +    fn appearance(&self, style: &Self::Style) -> Appearance; +} diff --git a/style/src/theme.rs b/style/src/theme.rs index e579a1c2..afb4d027 100644 --- a/style/src/theme.rs +++ b/style/src/theme.rs @@ -12,6 +12,7 @@ use crate::menu;  use crate::pane_grid;  use crate::pick_list;  use crate::progress_bar; +use crate::qr_code;  use crate::radio;  use crate::rule;  use crate::scrollable; @@ -956,6 +957,46 @@ impl<T: Fn(&Theme) -> progress_bar::Appearance> progress_bar::StyleSheet for T {      }  } +/// The style of a QR Code. +#[derive(Default)] +pub enum QRCode { +    /// The default style. +    #[default] +    Default, +    /// A custom style. +    Custom(Box<dyn qr_code::StyleSheet<Style = Theme>>), +} + +impl<T: Fn(&Theme) -> qr_code::Appearance + 'static> From<T> for QRCode { +    fn from(f: T) -> Self { +        Self::Custom(Box::new(f)) +    } +} + +impl qr_code::StyleSheet for Theme { +    type Style = QRCode; + +    fn appearance(&self, style: &Self::Style) -> qr_code::Appearance { +        let palette = self.palette(); + +        match style { +            QRCode::Default => qr_code::Appearance { +                cell: palette.text, +                background: palette.background, +            }, +            QRCode::Custom(custom) => custom.appearance(self), +        } +    } +} + +impl<T: Fn(&Theme) -> qr_code::Appearance> qr_code::StyleSheet for T { +    type Style = Theme; + +    fn appearance(&self, style: &Self::Style) -> qr_code::Appearance { +        (self)(style) +    } +} +  /// The style of a rule.  #[derive(Default)]  pub enum Rule { diff --git a/widget/src/qr_code.rs b/widget/src/qr_code.rs index 6a748e63..b6c60bf6 100644 --- a/widget/src/qr_code.rs +++ b/widget/src/qr_code.rs @@ -5,51 +5,59 @@ use crate::core::mouse;  use crate::core::renderer::{self, Renderer as _};  use crate::core::widget::Tree;  use crate::core::{ -    Color, Element, Layout, Length, Point, Rectangle, Size, Vector, Widget, +    Element, Layout, Length, Point, Rectangle, Size, Vector, Widget,  };  use crate::graphics::geometry::Renderer as _;  use crate::Renderer;  use thiserror::Error; +pub use crate::style::qr_code::StyleSheet; +  const DEFAULT_CELL_SIZE: u16 = 4;  const QUIET_ZONE: usize = 2;  /// A type of matrix barcode consisting of squares arranged in a grid which  /// can be read by an imaging device, such as a camera.  #[derive(Debug)] -pub struct QRCode<'a> { +pub struct QRCode<'a, Theme = crate::Theme> +where +    Theme: StyleSheet, +{      state: &'a State, -    dark: Color, -    light: Color,      cell_size: u16, +    style: Theme::Style,  } -impl<'a> QRCode<'a> { +impl<'a, Theme> QRCode<'a, Theme> +where +    Theme: StyleSheet, +{      /// Creates a new [`QRCode`] with the provided [`State`].      pub fn new(state: &'a State) -> Self {          Self {              cell_size: DEFAULT_CELL_SIZE, -            dark: Color::BLACK, -            light: Color::WHITE,              state, +            style: Default::default(),          }      } -    /// Sets both the dark and light [`Color`]s of the [`QRCode`]. -    pub fn color(mut self, dark: Color, light: Color) -> Self { -        self.dark = dark; -        self.light = light; -        self -    } -      /// Sets the size of the squares of the grid cell of the [`QRCode`].      pub fn cell_size(mut self, cell_size: u16) -> Self {          self.cell_size = cell_size;          self      } + +    /// Sets the style of the [`QRCode`]. +    pub fn style(mut self, style: impl Into<Theme::Style>) -> Self { +        self.style = style.into(); +        self +    }  } -impl<'a, Message, Theme> Widget<Message, Theme, Renderer> for QRCode<'a> { +impl<'a, Message, Theme> Widget<Message, Theme, Renderer> for QRCode<'a, Theme> +where +    Theme: StyleSheet, +{      fn size(&self) -> Size<Length> {          Size {              width: Length::Shrink, @@ -73,7 +81,7 @@ impl<'a, Message, Theme> Widget<Message, Theme, Renderer> for QRCode<'a> {          &self,          _state: &Tree,          renderer: &mut Renderer, -        _theme: &Theme, +        theme: &Theme,          _style: &renderer::Style,          layout: Layout<'_>,          _cursor: mouse::Cursor, @@ -82,6 +90,8 @@ impl<'a, Message, Theme> Widget<Message, Theme, Renderer> for QRCode<'a> {          let bounds = layout.bounds();          let side_length = self.state.width + 2 * QUIET_ZONE; +        let style = theme.appearance(&self.style); +          // Reuse cache if possible          let geometry =              self.state.cache.draw(renderer, bounds.size(), |frame| { @@ -92,7 +102,7 @@ impl<'a, Message, Theme> Widget<Message, Theme, Renderer> for QRCode<'a> {                  frame.fill_rectangle(                      Point::ORIGIN,                      Size::new(side_length as f32, side_length as f32), -                    self.light, +                    style.background,                  );                  // Avoid drawing on the quiet zone @@ -114,7 +124,7 @@ impl<'a, Message, Theme> Widget<Message, Theme, Renderer> for QRCode<'a> {                          frame.fill_rectangle(                              Point::new(column as f32, row as f32),                              Size::UNIT, -                            self.dark, +                            style.cell,                          );                      });              }); @@ -128,10 +138,12 @@ impl<'a, Message, Theme> Widget<Message, Theme, Renderer> for QRCode<'a> {      }  } -impl<'a, Message, Theme> From<QRCode<'a>> +impl<'a, Message, Theme> From<QRCode<'a, Theme>>      for Element<'a, Message, Theme, Renderer> +where +    Theme: StyleSheet + 'a,  { -    fn from(qr_code: QRCode<'a>) -> Self { +    fn from(qr_code: QRCode<'a, Theme>) -> Self {          Self::new(qr_code)      }  }  | 
