summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--style/src/lib.rs1
-rw-r--r--style/src/qr_code.rs20
-rw-r--r--style/src/theme.rs41
-rw-r--r--widget/src/qr_code.rs52
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)
}
}