diff --git a/examples/main.rs b/examples/main.rs index d43eb7d..02c55cc 100644 --- a/examples/main.rs +++ b/examples/main.rs @@ -1,23 +1,36 @@ use eframe::{Frame, NativeOptions}; -use egui::{CentralPanel, Context, Widget}; +use egui::{CentralPanel, Context, TextEdit, TopBottomPanel, Widget}; use egui_qr::QrCodeWidget; -use qrcode::QrCode; fn main() { let _ = eframe::run_native( "egui_qr", NativeOptions::default(), - Box::new(|_| Box::new(App)), + Box::new(|_| Box::new(App::new())), ); } -struct App; +struct App { + data: String, +} + +impl App { + pub fn new() -> Self { + Self { + data: String::new(), + } + } +} impl eframe::App for App { - fn update(&mut self, ctx: &Context, frame: &mut Frame) { - let code = QrCode::new(b"hello").unwrap(); + fn update(&mut self, ctx: &Context, _frame: &mut Frame) { + TopBottomPanel::top("main").show(ctx, |ui| TextEdit::singleline(&mut self.data).ui(ui)); CentralPanel::default().show(ctx, |ui| { - QrCodeWidget::new(&code).ui(ui); + if let Ok(q) = QrCodeWidget::from_data(self.data.as_bytes()) { + q.ui(ui) + } else { + ui.label("Invalid data") + } }); } } diff --git a/src/lib.rs b/src/lib.rs index bb78323..b1b9163 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,13 +1,28 @@ use egui::{vec2, Color32, Rect, Response, Rounding, Sense, Stroke, Ui, Widget}; +use qrcode::types::QrError; use qrcode::{Color, QrCode}; +enum CodeSrc<'a> { + Ref(&'a QrCode), + Owned(QrCode), +} + pub struct QrCodeWidget<'a> { - code: &'a QrCode, + code: CodeSrc<'a>, } impl<'a> QrCodeWidget<'a> { pub fn new(code: &'a QrCode) -> Self { - QrCodeWidget { code } + QrCodeWidget { + code: CodeSrc::Ref(code), + } + } + + pub fn from_data(data: &[u8]) -> Result { + let code = QrCode::new(data)?; + Ok(QrCodeWidget { + code: CodeSrc::Owned(code), + }) } } @@ -15,25 +30,39 @@ impl Widget for QrCodeWidget<'_> { fn ui(self, ui: &mut Ui) -> Response { let size = ui.available_size(); - let (response, painter) = ui.allocate_painter(size, Sense::click()); - let w = self.code.width(); - let start = response.rect.min; + let code_ref = match &self.code { + CodeSrc::Ref(code) => code, + CodeSrc::Owned(q) => q, + }; + let w = code_ref.width(); + let scale = (size.x.min(size.y) / w as f32).floor(); + let start = ui.cursor().min; + let (response, painter) = + ui.allocate_painter(vec2(w as f32 * scale, w as f32 * scale), Sense::click()); + + painter.rect( + response.rect, + Rounding::none(), + Color32::WHITE, + Stroke::NONE, + ); let mut ctr = 0; - let scale = (size.x / w as f32).floor(); - for c in self.code.to_colors() { + for c in code_ref.to_colors() { let row = ctr / w; let col = ctr % w; let c_start = start + vec2(col as f32 * scale, row as f32 * scale); let c_end = c_start + vec2(scale, scale); - painter.rect( - Rect::from_min_max(c_start, c_end), - Rounding::none(), - match c { - Color::Light => Color32::WHITE, - Color::Dark => Color32::BLACK, - }, - Stroke::NONE, - ); + if matches!(c, Color::Dark) { + painter.rect( + Rect::from_min_max(c_start, c_end), + Rounding::none(), + match c { + Color::Light => Color32::WHITE, + Color::Dark => Color32::BLACK, + }, + Stroke::NONE, + ); + } ctr += 1; } response