1use std::error;
2use std::ffi::{CString, NulError};
3use std::fmt;
4use std::os::raw::{c_char, c_int};
5use std::ptr;
6
7use crate::get_error;
8use crate::video::Window;
9use crate::Error;
10
11use crate::sys;
12
13bitflags! {
14 #[derive(Debug, Copy, Clone)]
15 pub struct MessageBoxFlag: u32 {
16 const ERROR =
17 sys::messagebox::SDL_MESSAGEBOX_ERROR.0;
18 const WARNING =
19 sys::messagebox::SDL_MESSAGEBOX_WARNING.0;
20 const INFORMATION =
21 sys::messagebox::SDL_MESSAGEBOX_INFORMATION.0;
22 }
23}
24
25impl From<MessageBoxFlag> for sys::messagebox::SDL_MessageBoxFlags {
26 fn from(flags: MessageBoxFlag) -> Self {
27 sys::messagebox::SDL_MessageBoxFlags(flags.bits() as sys::stdinc::Uint32)
28 }
29}
30
31impl From<sys::messagebox::SDL_MessageBoxFlags> for MessageBoxFlag {
32 fn from(flags: sys::messagebox::SDL_MessageBoxFlags) -> Self {
33 MessageBoxFlag::from_bits_truncate(flags.0)
34 }
35}
36
37bitflags! {
38 #[derive(Debug, Copy, Clone)]
39 pub struct MessageBoxButtonFlag: u32 {
40 const ESCAPEKEY_DEFAULT =
41 sys::messagebox::SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT.0;
42 const RETURNKEY_DEFAULT =
43 sys::messagebox::SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT.0;
44 const NOTHING = 0;
45 }
46}
47
48impl From<MessageBoxButtonFlag> for sys::messagebox::SDL_MessageBoxButtonFlags {
49 fn from(flags: MessageBoxButtonFlag) -> Self {
50 sys::messagebox::SDL_MessageBoxButtonFlags(flags.bits() as sys::stdinc::Uint32)
51 }
52}
53
54impl From<sys::messagebox::SDL_MessageBoxButtonFlags> for MessageBoxButtonFlag {
55 fn from(flags: sys::messagebox::SDL_MessageBoxButtonFlags) -> Self {
56 MessageBoxButtonFlag::from_bits_truncate(flags.0)
57 }
58}
59
60#[derive(Debug)]
61pub struct MessageBoxColorScheme {
62 pub background: (u8, u8, u8),
63 pub text: (u8, u8, u8),
64 pub button_border: (u8, u8, u8),
65 pub button_background: (u8, u8, u8),
66 pub button_selected: (u8, u8, u8),
67}
68
69impl From<MessageBoxColorScheme> for sys::messagebox::SDL_MessageBoxColorScheme {
70 fn from(val: MessageBoxColorScheme) -> Self {
71 sys::messagebox::SDL_MessageBoxColorScheme { colors: val.into() }
72 }
73}
74
75impl From<sys::messagebox::SDL_MessageBoxColorScheme> for MessageBoxColorScheme {
76 fn from(prim: sys::messagebox::SDL_MessageBoxColorScheme) -> MessageBoxColorScheme {
77 prim.colors.into()
78 }
79}
80
81#[derive(Debug)]
85pub struct ButtonData<'a> {
86 pub flags: MessageBoxButtonFlag,
87 pub button_id: i32,
88 pub text: &'a str,
89}
90
91#[derive(Debug)]
92pub enum ClickedButton<'a> {
93 CloseButton,
94 CustomButton(&'a ButtonData<'a>),
95}
96
97impl From<MessageBoxColorScheme> for [sys::messagebox::SDL_MessageBoxColor; 5] {
98 fn from(scheme: MessageBoxColorScheme) -> [sys::messagebox::SDL_MessageBoxColor; 5] {
99 fn to_message_box_color(t: (u8, u8, u8)) -> sys::messagebox::SDL_MessageBoxColor {
100 sys::messagebox::SDL_MessageBoxColor {
101 r: t.0,
102 g: t.1,
103 b: t.2,
104 }
105 }
106 [
107 to_message_box_color(scheme.background),
108 to_message_box_color(scheme.text),
109 to_message_box_color(scheme.button_border),
110 to_message_box_color(scheme.button_background),
111 to_message_box_color(scheme.button_selected),
112 ]
113 }
114}
115
116impl From<[sys::messagebox::SDL_MessageBoxColor; 5]> for MessageBoxColorScheme {
117 fn from(val: [sys::messagebox::SDL_MessageBoxColor; 5]) -> Self {
118 fn from_message_box_color(
119 prim_color: sys::messagebox::SDL_MessageBoxColor,
120 ) -> (u8, u8, u8) {
121 (prim_color.r, prim_color.g, prim_color.b)
122 }
123 MessageBoxColorScheme {
124 background: from_message_box_color(val[0]),
125 text: from_message_box_color(val[1]),
126 button_border: from_message_box_color(val[2]),
127 button_background: from_message_box_color(val[3]),
128 button_selected: from_message_box_color(val[4]),
129 }
130 }
131}
132
133#[derive(Debug, Clone)]
134pub enum ShowMessageError {
135 InvalidTitle(NulError),
136 InvalidMessage(NulError),
137 InvalidButton(NulError, i32),
140 SdlError(Error),
141}
142
143impl fmt::Display for ShowMessageError {
144 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
145 use self::ShowMessageError::*;
146
147 match *self {
148 InvalidTitle(ref e) => write!(f, "Invalid title: {e}"),
149 InvalidMessage(ref e) => write!(f, "Invalid message: {e}"),
150 InvalidButton(ref e, value) => write!(f, "Invalid button ({value}): {e}"),
151 SdlError(ref e) => write!(f, "SDL error: {e}"),
152 }
153 }
154}
155
156impl error::Error for ShowMessageError {
157 fn description(&self) -> &str {
158 use self::ShowMessageError::*;
159
160 match *self {
161 InvalidTitle(_) => "invalid title",
162 InvalidMessage(_) => "invalid message",
163 InvalidButton(..) => "invalid button",
164 SdlError(ref e) => &e.0,
165 }
166 }
167}
168
169#[doc(alias = "SDL_ShowSimpleMessageBox")]
175pub fn show_simple_message_box<'a, W>(
176 flags: MessageBoxFlag,
177 title: &str,
178 message: &str,
179 window: W,
180) -> Result<(), ShowMessageError>
181where
182 W: Into<Option<&'a Window>>,
183{
184 use self::ShowMessageError::*;
185 let result = unsafe {
186 let title = match CString::new(title) {
187 Ok(s) => s,
188 Err(err) => return Err(InvalidTitle(err)),
189 };
190 let message = match CString::new(message) {
191 Ok(s) => s,
192 Err(err) => return Err(InvalidMessage(err)),
193 };
194 let sys_flags: sys::messagebox::SDL_MessageBoxFlags = flags.into();
195 sys::messagebox::SDL_ShowSimpleMessageBox(
196 sys_flags,
197 title.as_ptr() as *const c_char,
198 message.as_ptr() as *const c_char,
199 window.into().map_or(ptr::null_mut(), |win| win.raw()),
200 )
201 };
202
203 if result {
204 Ok(())
205 } else {
206 Err(SdlError(get_error()))
207 }
208}
209
210#[doc(alias = "SDL_ShowMessageBox")]
220pub fn show_message_box<'a, 'b, W, M>(
221 flags: MessageBoxFlag,
222 buttons: &'a [ButtonData],
223 title: &str,
224 message: &str,
225 window: W,
226 scheme: M,
227) -> Result<ClickedButton<'a>, ShowMessageError>
228where
229 W: Into<Option<&'b Window>>,
230 M: Into<Option<MessageBoxColorScheme>>,
231{
232 let window = window.into();
233 let scheme = scheme.into();
234
235 use self::ShowMessageError::*;
236 let mut button_id: c_int = 0;
237 let title = match CString::new(title) {
238 Ok(s) => s,
239 Err(err) => return Err(InvalidTitle(err)),
240 };
241 let message = match CString::new(message) {
242 Ok(s) => s,
243 Err(err) => return Err(InvalidMessage(err)),
244 };
245 let button_texts: Result<Vec<_>, (_, i32)> = buttons
246 .iter()
247 .map(|b| CString::new(b.text).map_err(|e| (e, b.button_id)))
248 .collect(); let button_texts = match button_texts {
250 Ok(b) => b,
251 Err(e) => return Err(InvalidButton(e.0, e.1)),
252 };
253 let raw_buttons: Vec<sys::messagebox::SDL_MessageBoxButtonData> = buttons
254 .iter()
255 .zip(button_texts.iter())
256 .map(|(b, b_text)| sys::messagebox::SDL_MessageBoxButtonData {
257 flags: b.flags.into(),
258 buttonID: b.button_id as c_int,
259 text: b_text.as_ptr(),
260 })
261 .collect();
262 let result = unsafe {
263 let msg_box_data = sys::messagebox::SDL_MessageBoxData {
264 flags: flags.into(),
265 window: window.map_or(ptr::null_mut(), |win| win.raw()),
266 title: title.as_ptr() as *const c_char,
267 message: message.as_ptr() as *const c_char,
268 numbuttons: raw_buttons.len() as c_int,
269 buttons: raw_buttons.as_ptr(),
270 colorScheme: if let Some(scheme) = scheme {
271 &sys::messagebox::SDL_MessageBoxColorScheme {
272 colors: From::from(scheme),
273 } as *const _
274 } else {
275 ptr::null()
276 },
277 };
278 sys::messagebox::SDL_ShowMessageBox(&msg_box_data as *const _, &mut button_id as &mut _)
279 };
280 if result {
281 match button_id {
282 -1 => Ok(ClickedButton::CloseButton),
283 id => {
284 let button = buttons.iter().find(|b| b.button_id == id);
285 Ok(ClickedButton::CustomButton(button.unwrap()))
286 }
287 }
288 } else {
289 Err(SdlError(get_error()))
290 }
291}