use super::thread_future::ThreadFuture;
use crate::dialog::{MessageButtons, MessageDialog, MessageLevel};
use windows::Win32::{
Foundation::{HWND, PWSTR},
UI::WindowsAndMessaging::{
MessageBoxW, IDOK, IDYES, MB_ICONERROR, MB_ICONINFORMATION, MB_ICONWARNING, MB_OK,
MB_OKCANCEL, MB_YESNO, MESSAGEBOX_STYLE,
},
};
#[cfg(feature = "parent")]
use raw_window_handle::RawWindowHandle;
use std::{ffi::OsStr, iter::once, os::windows::ffi::OsStrExt};
pub struct WinMessageDialog {
parent: Option<HWND>,
text: Vec<u16>,
caption: Vec<u16>,
flags: MESSAGEBOX_STYLE,
}
unsafe impl Send for WinMessageDialog {}
impl WinMessageDialog {
pub fn new(opt: MessageDialog) -> Self {
let text: Vec<u16> = OsStr::new(&opt.description)
.encode_wide()
.chain(once(0))
.collect();
let caption: Vec<u16> = OsStr::new(&opt.title)
.encode_wide()
.chain(once(0))
.collect();
let level = match opt.level {
MessageLevel::Info => MB_ICONINFORMATION,
MessageLevel::Warning => MB_ICONWARNING,
MessageLevel::Error => MB_ICONERROR,
};
let buttons = match opt.buttons {
MessageButtons::Ok => MB_OK,
MessageButtons::OkCancel => MB_OKCANCEL,
MessageButtons::YesNo => MB_YESNO,
};
#[cfg(feature = "parent")]
let parent = match opt.parent {
Some(RawWindowHandle::Win32(handle)) => Some(HWND(handle.hwnd as isize)),
None => None,
_ => unreachable!("unsupported window handle, expected: Windows"),
};
#[cfg(not(feature = "parent"))]
let parent = None;
Self {
parent,
text,
caption,
flags: level | buttons,
}
}
pub fn run(mut self) -> bool {
let ret = unsafe {
MessageBoxW(
self.parent,
PWSTR(self.text.as_mut_ptr()),
PWSTR(self.caption.as_mut_ptr()),
self.flags,
)
};
ret == IDOK || ret == IDYES
}
pub fn run_async(self) -> ThreadFuture<bool> {
ThreadFuture::new(move |data| *data = Some(self.run()))
}
}
use crate::backend::MessageDialogImpl;
impl MessageDialogImpl for MessageDialog {
fn show(self) -> bool {
let dialog = WinMessageDialog::new(self);
dialog.run()
}
}
use crate::backend::AsyncMessageDialogImpl;
use crate::backend::DialogFutureType;
impl AsyncMessageDialogImpl for MessageDialog {
fn show_async(self) -> DialogFutureType<bool> {
let dialog = WinMessageDialog::new(self);
Box::pin(dialog.run_async())
}
}