Merge pull request #537 from Cobrand/master

Added show_message_box
This commit is contained in:
Tony Aldridge
2016-11-05 11:54:56 +00:00
committed by GitHub
3 changed files with 284 additions and 10 deletions
+72
View File
@@ -0,0 +1,72 @@
extern crate sdl2;
use sdl2::pixels::Color;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use ::sdl2::messagebox::*;
pub fn main() {
let sdl_context = sdl2::init().unwrap();
let video_subsystem = sdl_context.video().unwrap();
let window = video_subsystem.window("rust-sdl2 demo: Video", 800, 600)
.position_centered()
.opengl()
.build()
.unwrap();
let mut renderer = window.renderer().build().unwrap();
renderer.set_draw_color(Color::RGB(255, 0, 0));
renderer.clear();
renderer.present();
let mut event_pump = sdl_context.event_pump().unwrap();
'running: loop {
for event in event_pump.poll_iter() {
match event {
Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
let res =
show_simple_message_box(MESSAGEBOX_ERROR,
"Some title",
"Some information inside the window",
renderer.window());
match res {
Ok(_) => {}
Err(ShowMessageError::SdlError(string)) => {
println!("An error occured : {}",string);
}
Err(_) => println!("Unexpected error occured !"),
};
break 'running
},
_ => {}
}
}
// The rest of the game loop goes here...
}
let buttons : Vec<_> = vec![
ButtonData {
flags:MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT,
button_id:1,
text:"Ok"
},
ButtonData {
flags:MESSAGEBOX_BUTTON_NOTHING,
button_id:2,
text:"No"
},
ButtonData {
flags:MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT,
button_id:3,
text:"Cancel"
},
];
let res = show_message_box(MESSAGEBOX_WARNING,
buttons.as_slice(),
"Some warning",
"You forget to do something, do it anyway ?",
None,
None);
println!("{:?}",res);
}
+72 -6
View File
@@ -1,11 +1,77 @@
use libc::{c_int, c_char, uint32_t};
use std::os::raw::{c_int,c_char};
use video::SDL_Window;
pub type SDL_MessageBoxFlags = u32;
pub const SDL_MESSAGEBOX_ERROR : SDL_MessageBoxFlags = 0x00000010;
pub const SDL_MESSAGEBOX_WARNING : SDL_MessageBoxFlags = 0x00000020;
pub const SDL_MESSAGEBOX_INFORMATION : SDL_MessageBoxFlags = 0x00000040;
#[derive(Debug, Copy, Clone)]
#[repr(u32)]
pub enum SDL_MessageBoxFlags {
SDL_MESSAGEBOX_ERROR = 16,
SDL_MESSAGEBOX_WARNING = 32,
SDL_MESSAGEBOX_INFORMATION = 64,
}
#[derive(Debug, Copy, Clone)]
#[repr(u32)]
pub enum SDL_MessageBoxButtonFlags {
SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT = 1,
SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT = 2,
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct SDL_MessageBoxButtonData {
pub flags: u32,
pub buttonid: c_int,
pub text: *const c_char,
}
impl ::std::default::Default for SDL_MessageBoxButtonData {
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct SDL_MessageBoxColor {
pub r: u8,
pub g: u8,
pub b: u8,
}
#[derive(Debug, Copy, Clone)]
#[repr(u32)]
pub enum SDL_MessageBoxColorType {
SDL_MESSAGEBOX_COLOR_BACKGROUND = 0,
SDL_MESSAGEBOX_COLOR_TEXT = 1,
SDL_MESSAGEBOX_COLOR_BUTTON_BORDER = 2,
SDL_MESSAGEBOX_COLOR_BUTTON_BACKGROUND = 3,
SDL_MESSAGEBOX_COLOR_BUTTON_SELECTED = 4,
SDL_MESSAGEBOX_COLOR_MAX = 5,
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct SDL_MessageBoxColorScheme {
pub colors: [SDL_MessageBoxColor; 5usize],
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct SDL_MessageBoxData {
pub flags: u32,
pub window: *mut SDL_Window,
pub title: *const c_char,
pub message: *const c_char,
pub numbuttons: c_int,
pub buttons: *const SDL_MessageBoxButtonData,
pub color_scheme: *const SDL_MessageBoxColorScheme,
}
extern "C" {
pub fn SDL_ShowSimpleMessageBox(flags: uint32_t, title: *const c_char, message: *const c_char, window: *mut SDL_Window) -> c_int;
pub fn SDL_ShowMessageBox(messageboxdata: *const SDL_MessageBoxData,
buttonid: *mut c_int)
-> c_int;
pub fn SDL_ShowSimpleMessageBox(flags: u32,
title: *const c_char,
message: *const c_char,
window: *mut SDL_Window)
-> c_int;
}
+140 -4
View File
@@ -1,6 +1,6 @@
use std::ffi::{CString, NulError};
use std::ptr;
use libc::c_char;
use std::os::raw::{c_char,c_int};
use video::WindowRef;
use get_error;
@@ -9,18 +9,83 @@ use sys::messagebox as ll;
bitflags! {
pub flags MessageBoxFlag: u32 {
const MESSAGEBOX_ERROR = ::sys::messagebox::SDL_MESSAGEBOX_ERROR,
const MESSAGEBOX_WARNING = ::sys::messagebox::SDL_MESSAGEBOX_WARNING,
const MESSAGEBOX_INFORMATION = ::sys::messagebox::SDL_MESSAGEBOX_INFORMATION
const MESSAGEBOX_ERROR =
::sys::messagebox::SDL_MessageBoxFlags::SDL_MESSAGEBOX_ERROR as u32,
const MESSAGEBOX_WARNING =
::sys::messagebox::SDL_MessageBoxFlags::SDL_MESSAGEBOX_WARNING as u32,
const MESSAGEBOX_INFORMATION =
::sys::messagebox::SDL_MessageBoxFlags::SDL_MESSAGEBOX_INFORMATION as u32
}
}
bitflags! {
pub flags MessageBoxButtonFlag: u32 {
const MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT =
::sys::messagebox::SDL_MessageBoxButtonFlags::SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT as u32,
const MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT =
::sys::messagebox::SDL_MessageBoxButtonFlags::SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT as u32,
const MESSAGEBOX_BUTTON_NOTHING = 0
}
}
#[derive(Debug)]
pub struct MessageBoxColorScheme {
pub background:(u8,u8,u8),
pub text:(u8,u8,u8),
pub button_border:(u8,u8,u8),
pub button_background:(u8,u8,u8),
pub button_selected:(u8,u8,u8)
}
/// button_id is the integer that will be returned
/// by show_message_box. It is not sed by SDL2,
/// and should only be used to know which button has been triggered
#[derive(Debug)]
pub struct ButtonData<'a> {
pub flags:MessageBoxButtonFlag,
pub button_id:i32,
pub text:&'a str
}
#[derive(Debug)]
pub enum ClickedButton<'a> {
CloseButton,
CustomButton(&'a ButtonData<'a>)
}
impl From<MessageBoxColorScheme> for [ll::SDL_MessageBoxColor ; 5] {
fn from(scheme:MessageBoxColorScheme) -> [ll::SDL_MessageBoxColor ; 5] {
fn to_message_box_color(t:(u8,u8,u8)) -> ll::SDL_MessageBoxColor {
ll::SDL_MessageBoxColor {
r:t.0,
g:t.1,
b:t.2
}
};
[to_message_box_color(scheme.background),
to_message_box_color(scheme.text),
to_message_box_color(scheme.button_border),
to_message_box_color(scheme.button_background),
to_message_box_color(scheme.button_selected)]
}
}
#[derive(Debug)]
pub enum ShowMessageError {
InvalidTitle(NulError),
InvalidMessage(NulError),
/// Second argument of the tuple (i32) corresponds to the
/// first button_id having an error
InvalidButton(NulError,i32),
SdlError(String),
}
/// Show a simple message box, meant to be informative only.
///
/// There is no way to know if the user clicked "Ok" or closed the message box,
/// If you want to retrieve which button was clicked and customize a bit more
/// your message box, use `show_message_box` instead.
pub fn show_simple_message_box(flags: MessageBoxFlag, title: &str,
message: &str, window: Option<&WindowRef>)
-> Result<(), ShowMessageError> {
@@ -48,3 +113,74 @@ pub fn show_simple_message_box(flags: MessageBoxFlag, title: &str,
Err(SdlError(get_error()))
}
}
/// Show a customizable message box.
///
/// An array of buttons is required for it to work. The array can be empty,
/// but it will have no button beside the close button.
///
/// On success, it will return either the button clicked or the close button.
/// Note that the variant of the `ClickedButton` enum will also be returned if the message box
/// has been forcefully closed (Alt-F4, ...)
///
pub fn show_message_box<'a>(flags:MessageBoxFlag, buttons:&'a [ButtonData], title:&str,
message:&str, window:Option<&WindowRef>, scheme:Option<MessageBoxColorScheme>)
-> Result<ClickedButton<'a>,ShowMessageError> {
use self::ShowMessageError::*;
let mut button_id : c_int = 0;
let title = match CString::new(title) {
Ok(s) => s,
Err(err) => return Err(InvalidTitle(err)),
};
let message = match CString::new(message) {
Ok(s) => s,
Err(err) => return Err(InvalidMessage(err)),
};
let button_texts : Result<Vec<_>,(_,i32)> = buttons.iter().map(|b|{
CString::new(b.text).map_err(|e|(e,b.button_id))
}).collect(); // Create CString for every button; and catch any CString Error
let button_texts = match button_texts {
Ok(b) => b,
Err(e) => return Err(InvalidButton(e.0,e.1))
};
let raw_buttons : Vec<ll::SDL_MessageBoxButtonData> =
buttons.iter().zip(button_texts.iter()).map(|(b,b_text)|{
ll::SDL_MessageBoxButtonData {
flags:b.flags.bits(),
buttonid:b.button_id as c_int,
text:b_text.as_ptr()
}
}).collect();
let result = unsafe {
let msg_box_data = ll::SDL_MessageBoxData {
flags:flags.bits(),
window:window.map_or(ptr::null_mut(), |win| win.raw()),
title: title.as_ptr() as *const c_char,
message: message.as_ptr() as *const c_char,
numbuttons: raw_buttons.len() as c_int,
buttons: raw_buttons.as_ptr(),
color_scheme: if let Some(scheme) = scheme {
&ll::SDL_MessageBoxColorScheme {
colors:From::from(scheme)
} as *const _
} else {
ptr::null()
}
};
ll::SDL_ShowMessageBox(
&msg_box_data as *const _,
&mut button_id as &mut _
)
} == 0;
if result {
match button_id {
-1 => Ok(ClickedButton::CloseButton),
id => {
let button = buttons.iter().find(|b| b.button_id == id);
Ok(ClickedButton::CustomButton(button.unwrap()))
}
}
} else {
Err(SdlError(get_error()))
}
}