#![deny(missing_docs)]
#![deny(clippy::cargo)]
use std::marker::PhantomData;
use windows_sys::{
core::PCWSTR,
Win32::{
Foundation::{GetLastError, HWND},
UI::WindowsAndMessaging::{
MessageBoxW, MB_DEFAULT_DESKTOP_ONLY, MB_HELP, MB_RIGHT, MB_RTLREADING,
MB_SERVICE_NOTIFICATION, MB_SETFOREGROUND, MB_TOPMOST, MESSAGEBOX_STYLE,
},
},
};
use crate::{DefaultButton, Icon, Modal, Options, Result};
pub use windows_sys::w;
pub struct MessageBox<T> {
icon: Icon,
text: PCWSTR,
title: PCWSTR,
hwnd: HWND,
flags: MESSAGEBOX_STYLE,
_response: PhantomData<T>,
}
impl<T> std::fmt::Debug for MessageBox<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("MessageBox")
.field("icon", &self.icon)
.field("hwnd", &self.hwnd)
.finish()
}
}
macro_rules! ctors {
($($name:ident => $icon:ident),*) => {
impl <T> MessageBox<T> {
$(
#[doc = concat!("Creates a new message box where its icon is set to [", stringify!($icon), "](Icon::", stringify!($icon),").")]
pub fn $name(text: impl Into<PCWSTR>) -> Self {
Self::new(text).icon(Icon::$icon)
}
)*
}
$(
#[doc = concat!("Creates a new message box where its icon is set to [", stringify!($icon), "](Icon::", stringify!($icon),").")]
pub fn $name<T>(text: impl Into<PCWSTR>) -> MessageBox<T> {
MessageBox::<T>::$name(text)
})*
};
}
impl<T> MessageBox<T> {
pub fn new(text: impl Into<PCWSTR>) -> Self {
Self {
icon: Icon::Information,
text: text.into(),
title: std::ptr::null(),
hwnd: std::ptr::null_mut(),
flags: 0,
_response: PhantomData,
}
}
pub fn icon(mut self, icon: Icon) -> Self {
self.icon = icon;
self
}
pub fn title(mut self, title: impl Into<PCWSTR>) -> Self {
self.title = title.into();
self
}
pub fn hwnd(mut self, hwnd: HWND) -> Self {
self.hwnd = hwnd;
self
}
pub fn modal(mut self, modal: Modal) -> Self {
self.flags |= modal as u32;
self
}
pub fn default_button(mut self, btn: DefaultButton) -> Self {
self.flags |= btn as u32;
self
}
pub fn default_desktop_only(mut self) -> Self {
self.flags |= MB_DEFAULT_DESKTOP_ONLY;
self
}
pub fn right(mut self) -> Self {
self.flags |= MB_RIGHT;
self
}
pub fn rtl_reading(mut self) -> Self {
self.flags |= MB_RTLREADING;
self
}
pub fn set_foreground(mut self) -> Self {
self.flags |= MB_SETFOREGROUND;
self
}
pub fn topmost(mut self) -> Self {
self.flags |= MB_TOPMOST;
self
}
pub fn service_notification(mut self) -> Self {
self.flags |= MB_SERVICE_NOTIFICATION;
self
}
pub fn with_help(mut self) -> Self {
self.flags |= MB_HELP;
self
}
}
impl<T: Options> MessageBox<T> {
pub unsafe fn show(self) -> Result<T> {
let return_code = MessageBoxW(
self.hwnd,
self.text,
self.title,
T::flags() | self.icon.style() | self.flags,
);
match return_code {
0 => Err(GetLastError()),
x => Ok(T::from(x)),
}
}
}
ctors! {
exclamation => Exclamation,
warning => Warning,
information => Information,
asterisk => Asterisk,
question => Question,
stop => Stop,
error => Error,
hand => Hand
}
pub unsafe fn show<T: Options>(text: impl Into<PCWSTR>) -> Result<T> {
MessageBox::new(text).show()
}