pub use crate::enums::*;
use crate::prelude::*;
use crate::window::*;
use fltk_sys::fl::*;
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
use std::{
ffi::{CStr, CString},
mem,
os::raw,
};
pub type WidgetPtr = *mut fltk_sys::widget::Fl_Widget;
pub(crate) static mut FONTS: Vec<String> = Vec::new();
static mut LOADED_FONT: Option<&str> = None;
pub fn run() -> Result<(), FltkError> {
unsafe {
match Fl_run() {
0 => Ok(()),
_ => Err(FltkError::Internal(FltkErrorKind::FailedToRun)),
}
}
}
pub fn lock() -> Result<(), FltkError> {
unsafe {
match Fl_lock() {
0 => Ok(()),
_ => Err(FltkError::Internal(FltkErrorKind::FailedToLock)),
}
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum Scheme {
Base,
Plastic,
Gtk,
Gleam,
}
pub fn set_scheme(scheme: Scheme) {
let name_str = match scheme {
Scheme::Base => "base",
Scheme::Gtk => "gtk+",
Scheme::Gleam => "gleam",
Scheme::Plastic => "plastic",
};
let name_str = CString::new(name_str).unwrap();
unsafe { Fl_set_scheme(name_str.as_ptr()) }
}
pub fn scheme() -> Scheme {
unsafe {
use Scheme::*;
match Fl_scheme() {
0 => Base,
1 => Gtk,
2 => Gleam,
3 => Plastic,
_ => unreachable!(),
}
}
}
pub type AppScheme = Scheme;
#[allow(dead_code)]
pub fn unlock() {
unsafe {
Fl_unlock();
}
}
pub fn awake(cb: Box<dyn FnMut()>) {
unsafe {
unsafe extern "C" fn shim(data: *mut raw::c_void) {
let a: *mut Box<dyn FnMut()> = data as *mut Box<dyn FnMut()>;
let f: &mut (dyn FnMut()) = &mut **a;
let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| f()));
}
let a: *mut Box<dyn FnMut()> = Box::into_raw(Box::new(cb));
let data: *mut raw::c_void = a as *mut raw::c_void;
let callback: Fl_Awake_Handler = Some(shim);
Fl_awake(callback, data);
}
}
#[derive(Debug, Copy, Clone)]
pub struct App {}
impl App {
pub fn default() -> App {
register_images();
init_all();
unsafe {
FONTS = vec![
"Helvetica".to_owned(),
"HelveticaBold".to_owned(),
"HelveticaItalic".to_owned(),
"HelveticaBoldItalic".to_owned(),
"Courier".to_owned(),
"CourierBold".to_owned(),
"CourierItalic".to_owned(),
"CourierBoldItalic".to_owned(),
"Times".to_owned(),
"TimesBold".to_owned(),
"TimesItalic".to_owned(),
"TimesBoldItalic".to_owned(),
"Symbol".to_owned(),
"Screen".to_owned(),
"ScreenBold".to_owned(),
"Zapfdingbats".to_owned(),
];
}
App {}
}
pub fn set_scheme(&mut self, scheme: Scheme) {
set_scheme(scheme);
}
pub fn with_scheme(self, scheme: Scheme) -> App {
set_scheme(scheme);
self
}
pub fn scheme(&self) -> Scheme {
scheme()
}
pub fn run(&self) -> Result<(), FltkError> {
lock()?;
run()
}
pub fn wait(&self) -> Result<bool, FltkError> {
lock()?;
Ok(wait())
}
pub fn load_system_fonts(self) -> Self {
unsafe {
FONTS = get_font_names();
}
self
}
pub fn load_font(&self, path: &std::path::Path) -> Result<String, FltkError> {
if !path.exists() {
return Err::<String, FltkError>(FltkError::Internal(FltkErrorKind::ResourceNotFound));
}
if let Some(p) = path.to_str() {
let name = load_font(p)?;
Ok(name)
} else {
Err(FltkError::Internal(FltkErrorKind::ResourceNotFound))
}
}
pub fn set_visual(&self, mode: Mode) -> Result<(), FltkError> {
set_visual(mode)
}
pub fn awake(&self, cb: Box<dyn FnMut()>) {
unsafe {
unsafe extern "C" fn shim(data: *mut raw::c_void) {
let a: *mut Box<dyn FnMut()> = data as *mut Box<dyn FnMut()>;
let f: &mut (dyn FnMut()) = &mut **a;
let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| f()));
}
let a: *mut Box<dyn FnMut()> = Box::into_raw(Box::new(cb));
let data: *mut raw::c_void = a as *mut raw::c_void;
let callback: Fl_Awake_Handler = Some(shim);
Fl_awake(callback, data);
}
}
pub fn windows(&self) -> Option<Vec<Window>> {
let mut v: Vec<Window> = vec![];
let first = first_window();
first.as_ref()?;
let first = first?;
v.push(first.clone());
let mut win = first;
while let Some(wind) = next_window(&win) {
v.push(wind.clone());
win = wind;
}
Some(v)
}
pub fn redraw(&self) {
redraw()
}
pub fn set_damage(&self, flag: bool) {
set_damage(flag)
}
pub fn damage(&self) -> bool {
damage()
}
pub fn quit(&self) {
quit()
}
}
pub fn event() -> Event {
unsafe {
let x = Fl_event();
let x: Event = mem::transmute(x);
x
}
}
pub fn event_key() -> Key {
unsafe {
let x = Fl_event_key();
mem::transmute(x)
}
}
pub fn event_text() -> String {
unsafe {
let text = Fl_event_text();
if text.is_null() {
String::from("")
} else {
CStr::from_ptr(text as *mut raw::c_char)
.to_string_lossy()
.to_string()
}
}
}
pub fn event_button() -> i32 {
unsafe { Fl_event_button() }
}
pub fn event_clicks() -> bool {
unsafe {
match Fl_event_clicks() {
0 => false,
_ => true,
}
}
}
pub fn event_x() -> i32 {
unsafe {
Fl_event_x()
}
}
pub fn event_y() -> i32 {
unsafe {
Fl_event_y()
}
}
pub fn event_x_root() -> i32 {
unsafe {
Fl_event_x_root()
}
}
pub fn event_y_root() -> i32 {
unsafe {
Fl_event_y_root()
}
}
pub fn event_dx() -> i32 {
unsafe {
Fl_event_dx()
}
}
pub fn event_dy() -> i32 {
unsafe {
Fl_event_dy()
}
}
pub fn get_mouse() -> (i32, i32) {
unsafe {
let mut x: i32 = 0;
let mut y: i32 = 0;
Fl_get_mouse(&mut x, &mut y);
(x, y)
}
}
pub fn event_coords() -> (i32, i32) {
unsafe { (Fl_event_x(), Fl_event_y()) }
}
pub fn event_is_click() -> bool {
unsafe {
match Fl_event_is_click() {
0 => false,
_ => true,
}
}
}
pub fn event_length() -> u32 {
unsafe { Fl_event_length() as u32 }
}
pub fn event_state() -> Shortcut {
unsafe { mem::transmute(Fl_event_state()) }
}
pub fn screen_size() -> (f64, f64) {
unsafe { ((Fl_screen_w() as f64 / 0.96), (Fl_screen_h() as f64 / 0.96)) }
}
pub fn paste<T>(widget: &T)
where
T: WidgetExt + InputExt,
{
assert!(!widget.was_deleted());
unsafe {
Fl_paste(widget.as_widget_ptr() as *mut fltk_sys::fl::Fl_Widget, 1);
}
}
pub fn set_callback<W>(widget: &mut W, cb: Box<dyn FnMut()>)
where
W: WidgetExt,
{
assert!(!widget.was_deleted());
unsafe {
unsafe extern "C" fn shim(_wid: *mut fltk_sys::widget::Fl_Widget, data: *mut raw::c_void) {
let a: *mut Box<dyn FnMut()> = data as *mut Box<dyn FnMut()>;
let f: &mut (dyn FnMut()) = &mut **a;
let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| f()));
}
widget.unset_callback();
let a: *mut Box<dyn FnMut()> = Box::into_raw(Box::new(cb));
let data: *mut raw::c_void = a as *mut raw::c_void;
let callback: fltk_sys::widget::Fl_Callback = Some(shim);
fltk_sys::widget::Fl_Widget_callback_with_captures(widget.as_widget_ptr(), callback, data);
}
}
pub unsafe fn set_raw_callback<W>(widget: &mut W, data: *mut raw::c_void, cb: Option<fn(WidgetPtr, *mut raw::c_void)>)
where
W: WidgetExt,
{
assert!(!widget.was_deleted());
let cb: Option<unsafe extern "C" fn(WidgetPtr, *mut raw::c_void)> = mem::transmute(cb);
fltk_sys::widget::Fl_Widget_callback_with_captures(widget.as_widget_ptr(), cb, data);
}
pub fn set_fonts(name: &str) -> u8 {
let name = CString::new(name).unwrap();
unsafe { Fl_set_fonts(name.as_ptr() as *mut raw::c_char) as u8 }
}
pub fn font_name(idx: usize) -> Option<String> {
unsafe {
Some(FONTS[idx].clone())
}
}
pub fn get_font_names() -> Vec<String> {
let mut vec: Vec<String> = vec![];
let cnt = set_fonts("*") as usize;
for i in 0..cnt {
let temp = unsafe {
CStr::from_ptr(Fl_get_font(i as i32))
.to_string_lossy().to_string()
};
vec.push(temp);
}
vec
}
pub fn font_index(name: &str) -> Option<usize> {
unsafe {
FONTS.iter().position(|i| i == name)
}
}
pub fn font_count() -> usize {
unsafe {
FONTS.len()
}
}
pub fn fonts() -> Vec<String> {
unsafe { FONTS.clone() }
}
pub fn add_handler(cb: fn(Event) -> bool) {
unsafe {
let callback: Option<unsafe extern "C" fn(ev: raw::c_int) -> raw::c_int> =
Some(mem::transmute(move |ev| {
let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| cb(ev) as i32));
}));
Fl_add_handler(callback);
}
}
pub fn wait() -> bool {
unsafe {
match Fl_wait() {
0 => false,
_ => true,
}
}
}
pub fn wait_for(dur: f64) -> Result<(), FltkError> {
unsafe {
if Fl_wait_for(dur) >= 0.0 {
Ok(())
} else {
Err(FltkError::Unknown(String::from("An unknown error occured!")))
}
}
}
fn awake_msg<T>(msg: T) {
unsafe { Fl_awake_msg(Box::into_raw(Box::from(msg)) as *mut raw::c_void) }
}
fn thread_msg<T>() -> Option<T> {
unsafe {
let msg = Fl_thread_msg();
if msg.is_null() {
None
} else {
let msg = Box::from_raw(msg as *const _ as *mut T);
Some(*msg)
}
}
}
#[repr(C)]
struct Message<T: Copy + Send + Sync> {
hash: u64,
sz: usize,
msg: T,
}
#[derive(Debug, Clone, Copy)]
pub struct Sender<T: Copy + Send + Sync> {
data: std::marker::PhantomData<T>,
hash: u64,
sz: usize,
}
impl<T: Copy + Send + Sync> Sender<T> {
pub fn send(&self, val: T) {
let msg = Message {
hash: self.hash,
sz: self.sz,
msg: val,
};
awake_msg(msg)
}
}
#[derive(Debug, Clone, Copy)]
pub struct Receiver<T: Copy + Send + Sync> {
data: std::marker::PhantomData<T>,
hash: u64,
sz: usize,
}
impl<T: Copy + Send + Sync> Receiver<T> {
pub fn recv(&self) -> Option<T> {
let data: Option<Message<T>> = thread_msg();
if let Some(data) = data {
if data.sz == self.sz && data.hash == self.hash {
Some(data.msg)
} else {
None
}
} else {
None
}
}
}
pub fn channel<T: Copy + Send + Sync>() -> (Sender<T>, Receiver<T>) {
let msg_sz = std::mem::size_of::<T>();
let type_name = std::any::type_name::<T>();
let mut hasher = DefaultHasher::new();
type_name.hash(&mut hasher);
let type_hash = hasher.finish();
let s = Sender {
data: std::marker::PhantomData,
hash: type_hash,
sz: msg_sz,
};
let r = Receiver {
data: std::marker::PhantomData,
hash: type_hash,
sz: msg_sz,
};
(s, r)
}
pub fn first_window() -> Option<Window> {
unsafe {
let x = Fl_first_window();
if x.is_null() {
None
} else {
let x = Window::from_widget_ptr(x as *mut fltk_sys::widget::Fl_Widget);
Some(x)
}
}
}
pub fn next_window<W: WindowExt>(w: &W) -> Option<Window> {
unsafe {
let x = Fl_next_window(w.as_widget_ptr() as *const raw::c_void);
if x.is_null() {
None
} else {
let x = Window::from_widget_ptr(x as *mut fltk_sys::widget::Fl_Widget);
Some(x)
}
}
}
pub fn quit() {
unsafe {
if let Some(loaded_font) = LOADED_FONT {
unload_font(loaded_font).unwrap_or(());
}
}
let mut v: Vec<Window> = vec![];
let first = first_window();
if first.is_none() {
return;
}
let first = first.unwrap();
v.push(first.clone());
let mut win = first;
while let Some(wind) = next_window(&win) {
v.push(wind.clone());
win = wind;
}
for mut i in v {
if i.shown() {
i.hide();
}
}
}
pub fn add_timeout(tm: f64, cb: Box<dyn FnMut()>) {
unsafe {
unsafe extern "C" fn shim(data: *mut raw::c_void) {
let a: *mut Box<dyn FnMut()> = data as *mut Box<dyn FnMut()>;
let f: &mut (dyn FnMut()) = &mut **a;
let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| f()));
}
let a: *mut Box<dyn FnMut()> = Box::into_raw(Box::new(cb));
let data: *mut raw::c_void = a as *mut raw::c_void;
let callback: Option<unsafe extern "C" fn(arg1: *mut raw::c_void)> = Some(shim);
fltk_sys::fl::Fl_add_timeout(tm, callback, data);
}
}
pub fn repeat_timeout(tm: f64, cb: Box<dyn FnMut()>) {
unsafe {
unsafe extern "C" fn shim(data: *mut raw::c_void) {
let a: *mut Box<dyn FnMut()> = data as *mut Box<dyn FnMut()>;
let f: &mut (dyn FnMut()) = &mut **a;
let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| f()));
}
let a: *mut Box<dyn FnMut()> = Box::into_raw(Box::new(cb));
let data: *mut raw::c_void = a as *mut raw::c_void;
let callback: Option<unsafe extern "C" fn(arg1: *mut raw::c_void)> = Some(shim);
fltk_sys::fl::Fl_repeat_timeout(tm, callback, data);
}
}
pub fn remove_timeout(cb: Box<dyn FnMut()>) {
unsafe {
unsafe extern "C" fn shim(data: *mut raw::c_void) {
let a: *mut Box<dyn FnMut()> = data as *mut Box<dyn FnMut()>;
let f: &mut (dyn FnMut()) = &mut **a;
let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| f()));
}
let a: *mut Box<dyn FnMut()> = Box::into_raw(Box::new(cb));
let data: *mut raw::c_void = a as *mut raw::c_void;
let callback: Option<unsafe extern "C" fn(arg1: *mut raw::c_void)> = Some(shim);
fltk_sys::fl::Fl_remove_timeout(callback, data);
}
}
pub fn should_program_quit() -> bool {
unsafe {
match Fl_should_program_quit() {
0 => false,
_ => true,
}
}
}
pub fn program_should_quit(flag: bool) {
unsafe { Fl_program_should_quit(flag as i32) }
}
pub fn event_inside_widget<Wid: WidgetExt>(wid: &Wid) -> bool {
assert!(!wid.was_deleted());
let x = wid.x();
let y = wid.y();
let w = wid.width();
let h = wid.height();
unsafe {
match Fl_event_inside(x, y, w, h) {
0 => false,
_ => true,
}
}
}
pub fn event_inside(x: i32, y: i32, w: i32, h: i32) -> bool {
unsafe {
match Fl_event_inside(x, y, w, h) {
0 => false,
_ => true,
}
}
}
pub fn belowmouse<Wid: WidgetExt>() -> Option<impl WidgetExt> {
unsafe {
let x = Fl_belowmouse() as *mut fltk_sys::fl::Fl_Widget;
if x.is_null() {
None
} else {
Some(crate::widget::Widget::from_widget_ptr(
x as *mut fltk_sys::widget::Fl_Widget,
))
}
}
}
pub fn delete_widget<Wid: WidgetExt>(wid: &mut Wid) {
assert!(!wid.was_deleted());
unsafe {
Fl_delete_widget(wid.as_widget_ptr() as *mut fltk_sys::fl::Fl_Widget);
wid.cleanup();
}
}
pub unsafe fn unsafe_delete_widget<Wid: WidgetExt>(wid: &mut Wid) {
assert!(!wid.was_deleted());
let _u = wid.user_data();
Fl_delete_widget(wid.as_widget_ptr() as *mut fltk_sys::fl::Fl_Widget);
wid.cleanup();
}
pub fn register_images() {
unsafe { fltk_sys::image::Fl_register_images() }
}
pub fn init_all() {
unsafe { fltk_sys::fl::Fl_init_all() }
}
pub fn redraw() {
unsafe { Fl_redraw() }
}
pub fn is_event_shift() -> bool {
unsafe { Fl_event_shift() != 0 }
}
pub fn is_event_ctrl() -> bool {
unsafe { Fl_event_ctrl() != 0 }
}
pub fn is_event_command() -> bool {
unsafe { Fl_event_command() != 0 }
}
pub fn is_event_alt() -> bool {
unsafe { Fl_event_alt() != 0 }
}
pub fn set_damage(flag: bool) {
unsafe { Fl_set_damage(flag as i32) }
}
pub fn damage() -> bool {
unsafe { Fl_damage() != 0 }
}
pub fn set_visual(mode: Mode) -> Result<(), FltkError> {
unsafe {
match Fl_visual(mode as i32) {
0 => Err(FltkError::Internal(FltkErrorKind::FailedOperation)),
_ => Ok(()),
}
}
}
pub fn own_colormap() {
unsafe { Fl_own_colormap() }
}
pub fn pushed() -> Option<crate::widget::Widget> {
unsafe {
let ptr = Fl_pushed();
if ptr.is_null() {
None
} else {
Some(crate::widget::Widget::from_raw(
ptr as *mut fltk_sys::widget::Fl_Widget,
))
}
}
}
pub fn focus() -> Option<crate::widget::Widget> {
unsafe {
let ptr = Fl_focus();
if ptr.is_null() {
None
} else {
Some(crate::widget::Widget::from_raw(
ptr as *mut fltk_sys::widget::Fl_Widget,
))
}
}
}
pub fn set_focus<W: WidgetExt>(wid: &W) {
unsafe { Fl_set_focus(wid.as_widget_ptr() as *mut raw::c_void) }
}
pub fn delay(millis: u128) {
let now = std::time::Instant::now();
loop {
let after = std::time::Instant::now();
if after.duration_since(now).as_millis() > millis {
break;
}
}
}
pub fn version() -> f64 {
unsafe { Fl_version() }
}
pub fn api_version() -> i32 {
unsafe { Fl_api_version() }
}
pub fn abi_version() -> i32 {
unsafe { Fl_abi_version() }
}
pub fn crate_version() -> &'static str {
env!("CARGO_PKG_VERSION")
}
pub type GraphicsContext = *mut raw::c_void;
pub fn graphics_context() -> GraphicsContext {
unsafe {
let ctx = fltk_sys::window::Fl_gc();
assert!(!ctx.is_null());
ctx
}
}
pub type Display = *mut raw::c_void;
pub fn display() -> Display {
unsafe {
let disp = fltk_sys::window::Fl_display();
assert!(!disp.is_null());
disp
}
}
pub fn dnd() {
unsafe {
Fl_dnd();
}
}
fn load_font(path: &str) -> Result<String, FltkError> {
unsafe {
let path = CString::new(path)?;
if let Some(load_font) = LOADED_FONT {
unload_font(load_font)?;
}
let ptr = Fl_load_font(path.as_ptr());
if ptr.is_null() {
Err::<String, FltkError>(FltkError::Internal(FltkErrorKind::FailedOperation))
} else {
let name = CString::from_raw(ptr as *mut _).to_string_lossy().to_string();
if FONTS.len() < 17 {
FONTS.push(name.clone());
} else {
FONTS[16] = name.clone();
}
Ok(name)
}
}
}
fn unload_font(path: &str) -> Result<(), FltkError> {
unsafe {
let check = std::path::Path::new(path);
if !check.exists() {
return Err::<(), FltkError>(FltkError::Internal(FltkErrorKind::ResourceNotFound));
}
let path = CString::new(path)?;
Fl_unload_font(path.as_ptr());
Ok(())
}
}