mod presented;
use embedded_graphics::primitives::Rectangle;
use crate::{AlertSpec, FsTheme, I18n, Localized, ModalHost, ModalLayer, TouchEvent, UiCanvas};
use presented::PresentedAlert;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct AlertHostResponse<Modal> {
pub action: Option<(Modal, u8)>,
pub captured: bool,
pub redraw: bool,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum AlertHostError {
TooManyActions,
}
pub struct AlertHost<'a, Modal, const MAX_ACTIONS: usize> {
host: ModalHost<Modal>,
alert: Option<PresentedAlert<'a, Modal, MAX_ACTIONS>>,
}
impl<'a, Modal, const MAX_ACTIONS: usize> AlertHost<'a, Modal, MAX_ACTIONS>
where
Modal: Copy + Eq,
{
pub const fn new() -> Self {
Self {
host: ModalHost::new(),
alert: None,
}
}
pub fn present<const N: usize>(
&mut self,
key: Modal,
spec: AlertSpec<'a, N>,
) -> Result<(), AlertHostError> {
self.alert = Some(PresentedAlert::new(key, spec)?);
self.host.show(key);
Ok(())
}
pub fn dismiss_presented(&mut self) {
self.host.dismiss();
}
pub fn dismiss(&mut self) {
self.dismiss_presented();
}
pub fn clear_touch_state(&mut self) {
if let Some(alert) = self.alert.as_mut() {
alert.clear_touch_state();
}
}
pub const fn is_animating(&self) -> bool {
self.host.is_animating()
}
pub fn advance(&mut self, dt_ms: u32) -> bool {
let changed = self.host.advance(dt_ms);
if !self.host.has_modal() {
self.alert = None;
}
changed
}
pub fn presented_key(&self) -> Option<Modal> {
self.alert.as_ref().map(PresentedAlert::key)
}
pub fn presented_title(&self) -> Option<Localized<'a>> {
self.alert.as_ref().map(PresentedAlert::title)
}
pub fn layer(
&self,
bounds: Rectangle,
theme: &FsTheme,
i18n: &I18n<'a>,
) -> Option<ModalLayer<Modal>> {
let alert = self.alert.as_ref()?;
let panel = alert.panel(bounds, theme, i18n);
self.host.current_with_panel(bounds, panel)
}
pub fn handle_touch(
&mut self,
touch: TouchEvent,
bounds: Rectangle,
theme: &FsTheme,
i18n: &I18n<'a>,
) -> AlertHostResponse<Modal> {
let Some(alert) = self.alert.as_mut() else {
return AlertHostResponse {
action: None,
captured: false,
redraw: false,
};
};
let panel = alert.panel(bounds, theme, i18n);
let Some(layer) = self.host.current_with_panel(bounds, panel) else {
return AlertHostResponse {
action: None,
captured: false,
redraw: false,
};
};
let response = alert.handle_touch(touch, layer.translated_panel());
if let Some(action) = response.action {
self.host.dismiss();
return AlertHostResponse {
action: Some((alert.key(), action)),
captured: true,
redraw: true,
};
}
AlertHostResponse {
action: None,
captured: true,
redraw: response.redraw,
}
}
pub fn draw<D>(&self, display: &mut D, bounds: Rectangle, theme: &FsTheme, i18n: &I18n<'a>)
where
D: UiCanvas,
{
let Some(alert) = self.alert.as_ref() else {
return;
};
let Some(layer) = self.layer(bounds, theme, i18n) else {
return;
};
display.dim_rect(bounds, layer.dim_alpha);
alert.draw(display, layer.translated_panel(), theme, i18n);
}
}