use std::collections::VecDeque;
use egui::Widget;
use crate::Toast;
pub struct ToastManager<'a> {
unique_key: String,
toasts: &'a mut VecDeque<Toast>,
max_toasts: usize,
inner_margin: i8,
outer_margin: i8,
corner_radius: u8,
width: f32,
anchor: egui::Align2,
anchor_offset: egui::Vec2,
}
impl<'a> ToastManager<'a> {
pub fn new(toasts: &'a mut VecDeque<Toast>, unique_key: &str) -> Self {
Self {
unique_key: format!("toast_manager_{}", unique_key),
toasts,
max_toasts: 1,
inner_margin: 5,
outer_margin: 1,
corner_radius: 4,
width: 200.0,
anchor: egui::Align2::RIGHT_BOTTOM,
anchor_offset: egui::Vec2::ZERO,
}
}
pub fn max_toasts(mut self, max: usize) -> Self {
self.max_toasts = max;
self
}
pub fn inner_margin(mut self, margin: i8) -> Self {
self.inner_margin = margin;
self
}
pub fn outer_margin(mut self, margin: i8) -> Self {
self.outer_margin = margin;
self
}
pub fn corner_radius(mut self, radius: u8) -> Self {
self.corner_radius = radius;
self
}
pub fn width(mut self, width: f32) -> Self {
self.width = width;
self
}
pub fn anchor(mut self, anchor: egui::Align2) -> Self {
assert!(
anchor == egui::Align2::RIGHT_BOTTOM
|| anchor == egui::Align2::LEFT_BOTTOM
|| anchor == egui::Align2::CENTER_BOTTOM
|| anchor == egui::Align2::RIGHT_TOP
|| anchor == egui::Align2::LEFT_TOP
|| anchor == egui::Align2::CENTER_TOP,
"Invalid anchor position for ToastManager. Must be one of: RIGHT_BOTTOM, LEFT_BOTTOM,\
CENTER_BOTTOM, RIGHT_TOP, LEFT_TOP, CENTER_TOP."
);
self.anchor = anchor;
self
}
pub fn anchor_offset(mut self, offset: egui::Vec2) -> Self {
self.anchor_offset = offset;
self
}
}
impl<'a> Widget for ToastManager<'a> {
fn ui(self, ui: &mut egui::Ui) -> egui::Response {
self.toasts.retain(|toast| !toast.has_expired());
while self.toasts.len() > self.max_toasts {
self.toasts.pop_front();
}
let parent_area = ui.max_rect();
let width = self.width.clamp(1.0, parent_area.width());
let is_bottom = self.anchor == egui::Align2::RIGHT_BOTTOM
|| self.anchor == egui::Align2::LEFT_BOTTOM
|| self.anchor == egui::Align2::CENTER_BOTTOM;
let toast_iter: Box<dyn Iterator<Item = &Toast>> = if is_bottom {
Box::new(self.toasts.iter())
} else {
Box::new(self.toasts.iter().rev())
};
egui::Area::new(egui::Id::new(self.unique_key))
.anchor(self.anchor, self.anchor_offset)
.show(ui.ctx(), |ui| {
ui.vertical(|ui| {
for toast in toast_iter {
let toast = toast
.clone()
.inner_margin(self.inner_margin)
.outer_margin(self.outer_margin)
.corner_radius(self.corner_radius)
.width(width);
toast.ui(ui);
}
});
})
.response
}
}
pub fn toast_manager<'a>(toasts: &'a mut VecDeque<Toast>, unique_key: &str) -> ToastManager<'a> {
ToastManager::new(toasts, unique_key)
}