use crate::prelude::*;
use crate::window::Window;
use fltk_sys::fl;
use std::{mem, os::raw, panic, ptr};
pub type WidgetPtr = *mut fltk_sys::widget::Fl_Widget;
pub fn grab() -> Option<impl WindowExt> {
unsafe {
let ptr = fl::Fl_grab();
if ptr.is_null() {
None
} else {
Some(crate::window::Window::from_widget_ptr(ptr as *mut _))
}
}
}
pub fn set_grab<W: WindowExt>(win: Option<W>) {
unsafe {
win.map_or_else(
|| fl::Fl_set_grab(ptr::null_mut()),
|w| fl::Fl_set_grab(w.as_widget_ptr() as *mut _),
)
}
}
#[deprecated = "use app::set_grab(None) instead"]
pub fn release() {
unsafe { fl::Fl_release() }
}
pub fn set_callback<F, W>(widget: &mut W, cb: F)
where
F: FnMut(&mut dyn WidgetExt),
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(&mut dyn WidgetExt)> =
data as *mut Box<dyn FnMut(&mut dyn WidgetExt)>;
let f: &mut (dyn FnMut(&mut dyn WidgetExt)) = &mut **a;
let mut wid = crate::widget::Widget::from_widget_ptr(wid);
let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| f(&mut wid)));
}
let mut _old_data = None;
if widget.is_derived() {
_old_data = widget.user_data();
}
let a: *mut Box<dyn FnMut(&mut dyn WidgetExt)> = Box::into_raw(Box::new(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_set_callback(widget.as_widget_ptr(), callback, data);
}
}
#[allow(clippy::missing_safety_doc)]
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_set_callback(widget.as_widget_ptr(), cb, data);
}
pub fn first_window() -> Option<impl WindowExt> {
unsafe {
let x = fl::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<impl WindowExt> {
unsafe {
let x = fl::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 modal() -> Option<impl WindowExt> {
unsafe {
let x = fl::Fl_modal();
if x.is_null() {
None
} else {
let x = Window::from_widget_ptr(x as *mut fltk_sys::widget::Fl_Widget);
Some(x)
}
}
}
pub fn delete_widget<Wid: WidgetBase>(wid: Wid) {
assert!(!wid.was_deleted());
WidgetBase::delete(wid)
}
pub fn set_damage(flag: bool) {
unsafe { fl::Fl_set_damage(flag as i32) }
}
pub fn damage() -> bool {
unsafe { fl::Fl_damage() != 0 }
}
pub fn pushed() -> Option<impl WidgetExt> {
unsafe {
let ptr = fl::Fl_pushed();
if ptr.is_null() {
None
} else {
Some(crate::widget::Widget::from_widget_ptr(ptr as *mut _))
}
}
}
pub fn focus() -> Option<impl WidgetExt> {
unsafe {
let ptr = fl::Fl_focus();
if ptr.is_null() {
None
} else {
Some(crate::widget::Widget::from_widget_ptr(
ptr as *mut fltk_sys::widget::Fl_Widget,
))
}
}
}
pub fn set_focus<W: WidgetExt>(wid: &W) {
unsafe { fl::Fl_set_focus(wid.as_widget_ptr() as *mut raw::c_void) }
}
pub fn windows() -> Option<Vec<impl WindowExt>> {
let mut v: Vec<Window> = vec![];
if let Some(first) = first_window() {
let first: Window = unsafe { first.into_widget() };
v.push(first.clone());
let mut win = first;
while let Some(wind) = next_window(&win) {
let w = unsafe { wind.into_widget::<Window>() };
v.push(w.clone());
win = w;
}
Some(v)
} else {
None
}
}