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