pub use crate::enums::*;
use crate::prelude::*;
use fltk_sys::fl::*;
use std::{
ffi::{CStr, CString},
mem,
os::raw,
};
fn run() -> Result<(), FltkError> {
unsafe {
match Fl_run() {
0 => Ok(()),
_ => return Err(FltkError::Internal(FltkErrorKind::FailedToRun)),
}
}
}
pub fn lock() -> Result<(), FltkError> {
unsafe {
match Fl_lock() {
0 => Ok(()),
_ => return Err(FltkError::Internal(FltkErrorKind::FailedToLock)),
}
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum AppScheme {
Base,
Plastic,
Gtk,
Gleam,
}
fn set_scheme(scheme: AppScheme) {
let name_str = match scheme {
AppScheme::Base => "base",
AppScheme::Gtk => "gtk+",
AppScheme::Gleam => "gleam",
AppScheme::Plastic => "plastic",
};
let name_str = CString::new(name_str).unwrap();
unsafe { Fl_set_scheme(name_str.into_raw() as *const raw::c_char) }
}
#[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()> = mem::transmute(data);
let f: &mut (dyn FnMut()) = &mut **a;
f();
}
let a: *mut Box<dyn FnMut()> = Box::into_raw(Box::new(cb));
let data: *mut raw::c_void = mem::transmute(a);
let callback: Fl_Awake_Handler = Some(shim);
Fl_awake(callback, data);
}
}
#[derive(Debug, Copy, Clone)]
pub struct App {}
impl App {
pub fn default() -> App {
App {}
}
pub fn set_scheme(self, scheme: AppScheme) -> App {
set_scheme(scheme);
self
}
pub fn run(&self) -> Result<(), FltkError> {
lock()?;
return run();
}
pub fn wait(&self) -> bool {
let ret = lock();
if ret.is_err() {
return false;
}
wait()
}
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()> = mem::transmute(data);
let f: &mut (dyn FnMut()) = &mut **a;
f();
}
let a: *mut Box<dyn FnMut()> = Box::into_raw(Box::new(cb));
let data: *mut raw::c_void = mem::transmute(a);
let callback: Fl_Awake_Handler = Some(shim);
Fl_awake(callback, data);
}
}
}
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 {
CString::from_raw(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_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).into(),
(Fl_screen_h() as f64 / 0.96).into(),
)
}
}
pub fn paste<T>(widget: &T)
where
T: WidgetExt + InputExt,
{
unsafe {
Fl_paste(widget.as_widget_ptr() as *mut raw::c_void, 1);
}
}
pub fn set_callback<W>(widget: &mut W, cb: Box<dyn FnMut()>)
where
W: WidgetExt,
{
debug_assert!(
widget.top_window().unwrap().takes_events() && widget.takes_events(),
"Handling events requires that the window and widget be active!"
);
unsafe {
unsafe extern "C" fn shim(_wid: *mut fltk_sys::widget::Fl_Widget, data: *mut raw::c_void) {
let a: *mut Box<dyn FnMut()> = mem::transmute(data);
let f: &mut (dyn FnMut()) = &mut **a;
f();
}
let a: *mut Box<dyn FnMut()> = Box::into_raw(Box::new(cb));
let data: *mut raw::c_void = mem::transmute(a);
let callback: fltk_sys::widget::Fl_Callback = Some(shim);
fltk_sys::widget::Fl_Widget_callback_with_captures(widget.as_widget_ptr(), callback, data);
}
}
fn set_fonts(name: &str) -> u8 {
let name = CString::new(name).unwrap();
unsafe { Fl_set_fonts(name.into_raw() as *mut raw::c_char) as u8 }
}
pub fn get_font_count() -> u8 {
set_fonts("*")
}
pub fn get_font_name(idx: u8) -> Option<String> {
unsafe {
let font = Fl_get_font(idx as i32);
if font.is_null() {
None
} else {
Some(
CStr::from_ptr(font as *mut raw::c_char)
.to_string_lossy()
.to_string(),
)
}
}
}
pub fn get_font_names() -> Vec<String> {
let mut vec: Vec<String> = vec![];
let cnt = get_font_count();
for i in 0..cnt {
vec.push(get_font_name(i).unwrap());
}
vec
}
pub fn get_font_index(name: &str) -> Option<u8> {
let cnt = set_fonts("*");
let mut ret: Option<u8> = None;
for i in 0..cnt {
if name == get_font_name(i).unwrap() {
ret = Some(i);
break;
}
}
ret
}
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| {
cb(ev) as i32;
}));
Fl_add_handler(callback);
}
}
fn wait() -> bool {
unsafe {
match Fl_wait() {
0 => false,
_ => true,
}
}
}
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: *const T = msg as *const T;
Some(std::ptr::read(msg))
}
}
}
#[repr(C)]
struct Message<T: Copy> {
id: usize,
msg: T,
}
#[derive(Debug, Clone, Copy)]
pub struct Sender<T: Copy> {
data: std::marker::PhantomData<T>,
id: usize,
}
impl<T: Copy> Sender<T> {
pub fn send(&self, val: T) {
let msg = Message { id: self.id, msg: val };
awake_msg(msg)
}
}
#[derive(Debug, Clone, Copy)]
pub struct Receiver<T: Copy> {
data: std::marker::PhantomData<T>,
id: usize,
}
impl<T: Copy> Receiver<T> {
pub fn recv(&self) -> Option<T> {
let data: Option<Message<T>> = thread_msg();
if data.is_some() {
let data = data.unwrap();
if data.id == self.id {
Some(data.msg)
} else {
None
}
} else {
None
}
}
}
pub fn channel<T: Copy>() -> (Sender<T>, Receiver<T>) {
let mut s = Sender {
data: std::marker::PhantomData,
id: 0,
};
let mut r = Receiver {
data: std::marker::PhantomData,
id: 0,
};
let sz = std::mem::size_of::<T>();
s.id = sz;
r.id = sz;
(s, r)
}