use core::ffi::c_void;
use crate::abi::{Header, Str, UiDialog};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum Response {
Retry,
Disable,
Erase,
Reset,
Overwrite,
Cancel,
Ok,
Ignore,
}
impl Response {
#[must_use]
pub fn to_raw(self) -> u32 {
self.bit()
}
pub(super) fn bit(self) -> u32 {
match self {
Self::Retry => UiDialog::RETRY,
Self::Disable => UiDialog::DISABLE,
Self::Erase => UiDialog::ERASE,
Self::Reset => UiDialog::RESET,
Self::Overwrite => UiDialog::OVERWRITE,
Self::Cancel => UiDialog::CANCEL,
Self::Ok => UiDialog::OK,
Self::Ignore => UiDialog::IGNORE,
}
}
#[must_use]
pub fn from_raw(raw: u32) -> Option<Self> {
Some(match raw {
UiDialog::RETRY => Self::Retry,
UiDialog::DISABLE => Self::Disable,
UiDialog::ERASE => Self::Erase,
UiDialog::RESET => Self::Reset,
UiDialog::OVERWRITE => Self::Overwrite,
UiDialog::CANCEL => Self::Cancel,
UiDialog::OK => Self::Ok,
UiDialog::IGNORE => Self::Ignore,
_ => return None,
})
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Dialog<'a> {
pub(super) title: &'a str,
pub(super) message: &'a str,
pub(super) detail: &'a str,
pub(super) buttons: u32,
}
impl<'a> Dialog<'a> {
#[must_use]
pub const fn new(title: &'a str, message: &'a str) -> Self {
Self {
title,
message,
detail: "",
buttons: 1 << UiDialog::OK,
}
}
#[must_use]
pub const fn detail(mut self, detail: &'a str) -> Self {
self.detail = detail;
self
}
#[must_use]
pub fn buttons(mut self, buttons: &[Response]) -> Self {
let bits = buttons.iter().fold(0, |bits, r| bits | 1 << r.bit());
if bits != 0 {
self.buttons = bits;
}
self
}
#[must_use]
pub const fn title(&self) -> &'a str {
self.title
}
pub(super) fn to_raw(self, flags: u32) -> UiDialog {
UiDialog {
header: Header::of::<UiDialog>(),
title: Str::new(self.title),
message: Str::new(self.message),
detail: Str::new(self.detail),
buttons: self.buttons,
flags,
}
}
}
pub(super) struct Answer<F> {
pub(super) on_answer: F,
}
pub(super) unsafe extern "system" fn answered<F>(answer: u32, user: *mut c_void)
where
F: FnOnce(Option<Response>),
{
let answer_box = unsafe { Box::from_raw(user.cast::<Answer<F>>()) };
crate::host::guard(
"panic in a dialog's answer",
|| (),
move || (answer_box.on_answer)(Response::from_raw(answer)),
);
}