Skip to content

Add Borrow trait bound on QRCode Data parameter, to allow smart pointers to be owned by QRCode instance #2629

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Add Borrow trait bound on QRCode data, to allow smart pointers to be …
…owned by the QRCode instance
  • Loading branch information
boondocklabs committed Oct 5, 2024
commit 9d47d99e207280248982daa508bde2395c4c2069
5 changes: 2 additions & 3 deletions widget/src/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1788,11 +1788,10 @@ where
/// }
/// ```
#[cfg(feature = "qr_code")]
pub fn qr_code<'a, Theme>(
data: &'a crate::qr_code::Data,
) -> crate::QRCode<'a, Theme>
pub fn qr_code<'a, D, Theme>(data: D) -> crate::QRCode<'a, D, Theme>
where
Theme: crate::qr_code::Catalog + 'a,
D: Borrow<crate::qr_code::Data> + 'a,
{
crate::QRCode::new(data)
}
Expand Down
90 changes: 52 additions & 38 deletions widget/src/qr_code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ use crate::core::{
};
use crate::Renderer;

use std::borrow::Borrow;
use std::cell::RefCell;
use thiserror::Error;

Expand Down Expand Up @@ -61,21 +62,23 @@ const QUIET_ZONE: usize = 2;
/// }
/// ```
#[allow(missing_debug_implementations)]
pub struct QRCode<'a, Theme = crate::Theme>
pub struct QRCode<'a, D, Theme = crate::Theme>
where
Theme: Catalog,
D: Borrow<Data>,
{
data: &'a Data,
data: D,
cell_size: f32,
class: Theme::Class<'a>,
}

impl<'a, Theme> QRCode<'a, Theme>
impl<'a, D, Theme> QRCode<'a, D, Theme>
where
Theme: Catalog,
D: Borrow<Data>,
{
/// Creates a new [`QRCode`] with the provided [`Data`].
pub fn new(data: &'a Data) -> Self {
pub fn new(data: D) -> Self {
Self {
data,
cell_size: DEFAULT_CELL_SIZE,
Expand All @@ -91,8 +94,8 @@ where

/// Sets the size of the entire [`QRCode`].
pub fn total_size(mut self, total_size: impl Into<Pixels>) -> Self {
self.cell_size =
total_size.into().0 / (self.data.width + 2 * QUIET_ZONE) as f32;
self.cell_size = total_size.into().0
/ (self.data.borrow().width + 2 * QUIET_ZONE) as f32;

self
}
Expand All @@ -116,9 +119,11 @@ where
}
}

impl<'a, Message, Theme> Widget<Message, Theme, Renderer> for QRCode<'a, Theme>
impl<'a, D, Message, Theme> Widget<Message, Theme, Renderer>
for QRCode<'a, D, Theme>
where
Theme: Catalog,
D: Borrow<Data>,
{
fn tag(&self) -> tree::Tag {
tree::Tag::of::<State>()
Expand All @@ -142,7 +147,7 @@ where
_limits: &layout::Limits,
) -> layout::Node {
let side_length =
(self.data.width + 2 * QUIET_ZONE) as f32 * self.cell_size;
(self.data.borrow().width + 2 * QUIET_ZONE) as f32 * self.cell_size;

layout::Node::new(Size::new(side_length, side_length))
}
Expand All @@ -160,49 +165,57 @@ where
let state = tree.state.downcast_ref::<State>();

let bounds = layout.bounds();
let side_length = self.data.width + 2 * QUIET_ZONE;
let side_length = self.data.borrow().width + 2 * QUIET_ZONE;

let style = theme.style(&self.class);
let mut last_style = state.last_style.borrow_mut();

if Some(style) != *last_style {
self.data.cache.clear();
self.data.borrow().cache.clear();

*last_style = Some(style);
}

// Reuse cache if possible
let geometry = self.data.cache.draw(renderer, bounds.size(), |frame| {
// Scale units to cell size
frame.scale(self.cell_size);

// Draw background
frame.fill_rectangle(
Point::ORIGIN,
Size::new(side_length as f32, side_length as f32),
style.background,
);

// Avoid drawing on the quiet zone
frame.translate(Vector::new(QUIET_ZONE as f32, QUIET_ZONE as f32));

// Draw contents
let geometry =
self.data
.contents
.iter()
.enumerate()
.filter(|(_, value)| **value == qrcode::Color::Dark)
.for_each(|(index, _)| {
let row = index / self.data.width;
let column = index % self.data.width;
.borrow()
.cache
.draw(renderer, bounds.size(), |frame| {
// Scale units to cell size
frame.scale(self.cell_size);

// Draw background
frame.fill_rectangle(
Point::new(column as f32, row as f32),
Size::UNIT,
style.cell,
Point::ORIGIN,
Size::new(side_length as f32, side_length as f32),
style.background,
);

// Avoid drawing on the quiet zone
frame.translate(Vector::new(
QUIET_ZONE as f32,
QUIET_ZONE as f32,
));

// Draw contents
self.data
.borrow()
.contents
.iter()
.enumerate()
.filter(|(_, value)| **value == qrcode::Color::Dark)
.for_each(|(index, _)| {
let row = index / self.data.borrow().width;
let column = index % self.data.borrow().width;

frame.fill_rectangle(
Point::new(column as f32, row as f32),
Size::UNIT,
style.cell,
);
});
});
});

renderer.with_translation(
bounds.position() - Point::ORIGIN,
Expand All @@ -215,12 +228,13 @@ where
}
}

impl<'a, Message, Theme> From<QRCode<'a, Theme>>
impl<'a, D, Message, Theme> From<QRCode<'a, D, Theme>>
for Element<'a, Message, Theme, Renderer>
where
Theme: Catalog + 'a,
D: Borrow<Data> + 'a,
{
fn from(qr_code: QRCode<'a, Theme>) -> Self {
fn from(qr_code: QRCode<'a, D, Theme>) -> Self {
Self::new(qr_code)
}
}
Expand Down
Loading