windows_win/ui/
msg_box.rs

1//! Message boxes APIs
2
3use crate::sys::{HWND, MessageBoxW};
4use crate::utils::Result;
5
6use std::os::windows::ffi::OsStrExt;
7use std::ffi;
8use std::ptr;
9use std::os::raw::{c_int, c_uint};
10
11use crate::utils;
12
13///Re-export WinAPI flags for `MessageBox`
14pub mod flags {
15    pub use crate::sys::{
16        //Buttons
17        MB_ABORTRETRYIGNORE,
18        MB_CANCELTRYCONTINUE,
19        MB_HELP,
20        MB_OK,
21        MB_OKCANCEL,
22        MB_RETRYCANCEL,
23        MB_YESNO,
24        MB_YESNOCANCEL,
25        //Icons
26        MB_ICONEXCLAMATION,
27        MB_ICONWARNING,
28        MB_ICONINFORMATION,
29        MB_ICONASTERISK,
30        MB_ICONQUESTION,
31        MB_ICONSTOP,
32        MB_ICONERROR,
33        MB_ICONHAND,
34        //Modiality
35        MB_APPLMODAL,
36        MB_SYSTEMMODAL,
37        MB_TASKMODAL,
38    };
39}
40
41#[derive(Debug, PartialEq, Eq)]
42///Result of user's interaction with message box
43pub enum MsgBoxResult {
44    ///Abort button is selected
45    Abort,
46    ///Cancel button is selected
47    Cancel,
48    ///Continue button is selected
49    Continue,
50    ///Ignore button is selected
51    Ignore,
52    ///No button is selected
53    No,
54    ///Ok button is selected
55    Ok,
56    ///Retry button is selected
57    Retry,
58    ///Try Again button is selected
59    TryAgain,
60    ///Yes button is selected
61    Yes,
62    ///Unknown result code. Non zero
63    Ext(c_int),
64}
65
66impl From<c_int> for MsgBoxResult {
67    fn from(value: c_int) -> MsgBoxResult {
68        match value {
69            1 => MsgBoxResult::Ok,
70            2 => MsgBoxResult::Cancel,
71            3 => MsgBoxResult::Abort,
72            4 => MsgBoxResult::Retry,
73            5 => MsgBoxResult::Ignore,
74            6 => MsgBoxResult::Yes,
75            7 => MsgBoxResult::No,
76            10 => MsgBoxResult::TryAgain,
77            11 => MsgBoxResult::Continue,
78            value => MsgBoxResult::Ext(value),
79        }
80    }
81}
82
83///Message box modal dialogue
84///
85///If title is not specified, then Default is `Error`
86///
87///The default type is `flags::MB_OK`
88pub struct MessageBox {
89    parent: HWND,
90    text: Vec<u16>,
91    caption: Option<Vec<u16>>,
92    flags: c_uint,
93}
94
95impl MessageBox {
96    ///Creates new instance with provided text message.
97    ///
98    ///For multi-line text messages, just use \n
99    pub fn new(text: &ffi::OsStr) -> Self {
100        let mut text: Vec<u16> = text.encode_wide().collect();
101        text.push(0);
102
103        Self {
104            parent: ptr::null_mut(),
105            text,
106            caption: None,
107            flags: flags::MB_OK,
108        }
109    }
110
111    #[inline]
112    ///Creates informational message box with Ok button
113    pub fn info<T: AsRef<ffi::OsStr>>(text: T) -> Self {
114        let mut res = Self::new(text.as_ref());
115        res.flags |= flags::MB_ICONINFORMATION;
116        res
117    }
118
119    #[inline]
120    ///Creates error message box with Ok button
121    pub fn error<T: AsRef<ffi::OsStr>>(text: T) -> Self {
122        let mut res = Self::new(text.as_ref());
123        res.flags |= flags::MB_ICONERROR;
124        res
125    }
126
127    ///Sets parent's window handle.
128    pub fn parent(&mut self, parent: HWND) -> &mut Self {
129        self.parent = parent;
130        self
131    }
132
133    ///Sets flags value.
134    pub fn set_flags(&mut self, flags: c_uint) -> &mut Self {
135        self.flags = flags;
136        self
137    }
138
139    ///Adds flags to existing ones.
140    pub fn flags(&mut self, flags: c_uint) -> &mut Self {
141        self.flags |= flags;
142        self
143    }
144
145    ///Sets new text of message box
146    pub fn text<T: AsRef<ffi::OsStr>>(&mut self, text: T) -> &mut Self {
147        let text = text.as_ref();
148
149        self.text.truncate(0);
150        for ch in text.encode_wide() {
151            self.text.push(ch);
152        }
153        self.text.push(0);
154
155        self
156    }
157
158    ///Sets caption for message box.
159    pub fn title<T: AsRef<ffi::OsStr>>(&mut self, text: T) -> &mut Self {
160        let title = text.as_ref();
161
162        self.caption = match self.caption.take() {
163            Some(mut caption) => {
164                caption.truncate(0);
165                for ch in title.encode_wide() {
166                    caption.push(ch);
167                }
168                caption.push(0);
169                Some(caption)
170            },
171            None => {
172                let mut title: Vec<u16> = title.encode_wide().collect();
173                title.push(0);
174                Some(title)
175            },
176        };
177
178        self
179    }
180
181    ///Shows message box and returns once user closes it
182    pub fn show(&self) -> Result<MsgBoxResult> {
183        let caption = self.caption.as_ref().map(|caption| caption.as_ptr()).unwrap_or_else(|| ptr::null());
184
185        match unsafe { MessageBoxW(self.parent, self.text.as_ptr(), caption, self.flags) } {
186            0 => Err(utils::get_last_error()),
187            n => Ok(MsgBoxResult::from(n)),
188        }
189    }
190}