From 488f4fdaa3a6da8114dc287ca778a76773c693e3 Mon Sep 17 00:00:00 2001 From: Urho Laukkarinen Date: Sun, 14 Jul 2024 14:00:20 +0300 Subject: [PATCH] Toasts have a customizable style --- README.md | 8 ++++--- demo/src/main.rs | 28 ++++++++++++++---------- src/lib.rs | 28 ++++++++++-------------- src/toast.rs | 55 ++++++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 84 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 6f39364..2947548 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,8 @@ if ui.button("Add toast").clicked() { kind: ToastKind::Error, options: ToastOptions::default() .duration_in_seconds(5.0) - .show_progress(true) + .show_progress(true), + ..Default::default() }); } @@ -41,7 +42,7 @@ toasts.show(ctx); ## Customization Look of the notifications can be fully customized. - + ```rust const MY_CUSTOM_TOAST: u32 = 0; @@ -66,7 +67,8 @@ if ui.button("Add toast").clicked() { toasts.add(Toast { text: "Hello, World!".into(), kind: ToastKind::Custom(MY_CUSTOM_TOAST), - options: ToastOptions::default() + options: ToastOptions::default(), + ..Default::default() }); } diff --git a/demo/src/main.rs b/demo/src/main.rs index d21b14f..4a7ef99 100644 --- a/demo/src/main.rs +++ b/demo/src/main.rs @@ -4,7 +4,7 @@ use eframe::egui; use eframe::epaint::Margin; use egui::{Align2, Color32, Direction, Frame, Pos2, RichText, Widget}; -use egui_toast::{Toast, ToastKind, ToastOptions, Toasts}; +use egui_toast::{Toast, ToastKind, ToastOptions, ToastStyle, Toasts}; /// Identifier for a custom toast kind const MY_CUSTOM_TOAST: u32 = 0; @@ -169,22 +169,28 @@ impl Demo { .show_progress(*show_progress) .duration(duration); + let style = ToastStyle::default(); + if ui.button("Give me a toast").clicked() { - toasts.add(Toast { - kind: *kind, - text: format!("Hello, I am a toast {}", i).into(), - options, - }); + toasts.add( + Toast::default() + .kind(*kind) + .text(format!("Hello, I am a toast {}", i)) + .options(options) + .style(style.clone()), + ); *i += 1; } if ui.button("Give me a custom toast").clicked() { - toasts.add(Toast { - text: format!("Hello, I am a custom toast {}", i).into(), - kind: ToastKind::Custom(MY_CUSTOM_TOAST), - options, - }); + toasts.add( + Toast::default() + .kind(ToastKind::Custom(MY_CUSTOM_TOAST)) + .text(format!("Hello, I am a custom toast {}", i)) + .options(options) + .style(style.clone()), + ); *i += 1; } diff --git a/src/lib.rs b/src/lib.rs index cdc0657..7e0f7a8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,7 +23,8 @@ //! options: ToastOptions::default() //! .duration_in_seconds(3.0) //! .show_progress(true) -//! .show_icon(true) +//! .show_icon(true), +//! ..Default::default() //! }); //! @@ -56,6 +57,7 @@ //! text: "Hello, World".into(), //! kind: ToastKind::Custom(MY_CUSTOM_TOAST), //! options: ToastOptions::default(), +//! ..Default::default() //! }); //! //! # }) @@ -72,15 +74,9 @@ use std::time::Duration; use egui::epaint::RectShape; use egui::{ - Align2, Area, Color32, Context, Direction, Frame, Id, Order, Pos2, Response, RichText, - Rounding, Shape, Stroke, Ui, + Align2, Area, Context, Direction, Frame, Id, Order, Pos2, Response, Rounding, Shape, Stroke, Ui, }; -pub const INFO_COLOR: Color32 = Color32::from_rgb(0, 155, 255); -pub const WARNING_COLOR: Color32 = Color32::from_rgb(255, 212, 0); -pub const ERROR_COLOR: Color32 = Color32::from_rgb(255, 32, 0); -pub const SUCCESS_COLOR: Color32 = Color32::from_rgb(0, 255, 32); - pub type ToastContents = dyn Fn(&mut Ui, &mut Toast) -> Response + Send + Sync; pub struct Toasts { @@ -225,21 +221,19 @@ fn default_toast_contents(ui: &mut Ui, toast: &mut Toast) -> Response { .stroke(Stroke::NONE) .show(ui, |ui| { ui.horizontal(|ui| { - let (icon, color) = match toast.kind { - ToastKind::Warning => ("⚠", WARNING_COLOR), - ToastKind::Error => ("❗", ERROR_COLOR), - ToastKind::Success => ("✔", SUCCESS_COLOR), - _ => ("ℹ", INFO_COLOR), - }; - let a = |ui: &mut Ui, toast: &mut Toast| { if toast.options.show_icon { - ui.label(RichText::new(icon).color(color)); + ui.label(match toast.kind { + ToastKind::Warning => toast.style.warning_icon.clone(), + ToastKind::Error => toast.style.error_icon.clone(), + ToastKind::Success => toast.style.success_icon.clone(), + _ => toast.style.info_icon.clone(), + }); } }; let b = |ui: &mut Ui, toast: &mut Toast| ui.label(toast.text.clone()); let c = |ui: &mut Ui, toast: &mut Toast| { - if ui.button("🗙").clicked() { + if ui.button(toast.style.close_button_text.clone()).clicked() { toast.close(); } }; diff --git a/src/toast.rs b/src/toast.rs index 02e6bcf..bae9f8f 100644 --- a/src/toast.rs +++ b/src/toast.rs @@ -1,8 +1,9 @@ -use egui::WidgetText; +use egui::{Color32, WidgetText}; use std::time::Duration; -#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] +#[derive(Default, Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] pub enum ToastKind { + #[default] Info, Warning, Error, @@ -16,21 +17,67 @@ impl From for ToastKind { } } -#[derive(Clone)] +#[derive(Clone, Default)] pub struct Toast { pub kind: ToastKind, pub text: WidgetText, pub options: ToastOptions, + pub style: ToastStyle, } impl Toast { + pub fn new() -> Self { + Self::default() + } + + pub fn kind(mut self, kind: ToastKind) -> Self { + self.kind = kind; + self + } + + pub fn text(mut self, text: impl Into) -> Self { + self.text = text.into(); + self + } + + pub fn options(mut self, options: ToastOptions) -> Self { + self.options = options; + self + } + + pub fn style(mut self, style: ToastStyle) -> Self { + self.style = style; + self + } + /// Close the toast immediately pub fn close(&mut self) { self.options.ttl_sec = 0.0; } } -#[derive(Copy, Clone)] +#[derive(Clone)] +pub struct ToastStyle { + pub info_icon: WidgetText, + pub warning_icon: WidgetText, + pub error_icon: WidgetText, + pub success_icon: WidgetText, + pub close_button_text: WidgetText, +} + +impl Default for ToastStyle { + fn default() -> Self { + Self { + info_icon: WidgetText::from("ℹ").color(Color32::from_rgb(0, 155, 255)), + warning_icon: WidgetText::from("⚠").color(Color32::from_rgb(255, 212, 0)), + error_icon: WidgetText::from("❗").color(Color32::from_rgb(255, 32, 0)), + success_icon: WidgetText::from("✔").color(Color32::from_rgb(0, 255, 32)), + close_button_text: WidgetText::from("🗙"), + } + } +} + +#[derive(Debug, Copy, Clone)] pub struct ToastOptions { /// Whether the toast should include an icon. pub show_icon: bool,