use error::UIError;
use ffi_tools;
use libc::{c_int, c_void};
use ui_sys;
use std::ffi::CStr;
use std::marker::PhantomData;
use std::mem;
use std::rc::Rc;
use std::thread::sleep;
use std::time::Duration;
use controls::Window;
struct UIToken {
_pd: PhantomData<*mut ()>,
}
impl Drop for UIToken {
fn drop(&mut self) {
assert!(
ffi_tools::is_initialized(),
"Attempted to uninit libUI in UIToken destructor when libUI was not initialized!"
);
unsafe {
Window::destroy_all_windows();
ui_sys::uiUninit();
ffi_tools::unset_initialized();
}
}
}
#[derive(Clone)]
pub struct UI {
token: Rc<UIToken>,
}
impl UI {
pub fn init() -> Result<UI, UIError> {
if ffi_tools::is_initialized() {
return Err(UIError::MultipleInitError {});
};
unsafe {
let mut init_options = ui_sys::uiInitOptions {
Size: mem::size_of::<ui_sys::uiInitOptions>(),
};
let err = ui_sys::uiInit(&mut init_options);
if err.is_null() {
ffi_tools::set_initialized();
Ok(UI {
token: Rc::new(UIToken { _pd: PhantomData }),
})
} else {
let error_string = CStr::from_ptr(err).to_string_lossy().into_owned();
ui_sys::uiFreeInitError(err);
Err(UIError::FailedInitError {
error: error_string,
})
}
}
}
pub fn main(&self) {
self.event_loop().run(self);
}
pub fn event_loop(&self) -> EventLoop {
unsafe { ui_sys::uiMainSteps() };
return EventLoop {
_pd: PhantomData,
callback: None,
};
}
pub fn quit(&self) {
unsafe { ui_sys::uiQuit() }
}
pub fn queue_main<F: FnMut()>(&self, callback: F) {
unsafe {
let mut data: Box<Box<FnMut()>> = Box::new(Box::new(callback));
ui_sys::uiQueueMain(
ffi_tools::void_void_callback,
&mut *data as *mut Box<FnMut()> as *mut c_void,
);
mem::forget(data);
}
}
pub fn on_should_quit<F: FnMut()>(&self, callback: F) {
unsafe {
let mut data: Box<Box<FnMut()>> = Box::new(Box::new(callback));
ui_sys::uiOnShouldQuit(
ffi_tools::void_void_callback,
&mut *data as *mut Box<FnMut()> as *mut c_void,
);
mem::forget(data);
}
}
}
pub struct EventLoop {
_pd: PhantomData<*mut ()>,
callback: Option<Box<FnMut()>>,
}
impl EventLoop {
pub fn on_tick<F: FnMut() + 'static>(&mut self, _ctx: &UI, callback: F) {
self.callback = Some(Box::new(callback));
}
pub fn next_tick(&mut self, _ctx: &UI) -> bool {
let result = unsafe { ui_sys::uiMainStep(false as c_int) == 1 };
if let Some(ref mut c) = self.callback {
c();
}
result
}
pub fn next_event_tick(&mut self, _ctx: &UI) -> bool {
let result = unsafe { ui_sys::uiMainStep(true as c_int) == 1 };
if let Some(ref mut c) = self.callback {
c();
}
result
}
pub fn run(&mut self, ctx: &UI) {
loop {
if !self.next_event_tick(ctx) {
break;
}
}
}
pub fn run_delay(&mut self, ctx: &UI, delay_ms: u32) {
loop {
if !self.next_tick(ctx) {
break;
}
}
sleep(Duration::new(0, delay_ms * 1000000))
}
}