fltk/app/
widget.rs

1use crate::prelude::*;
2use crate::window::Window;
3use fltk_sys::fl;
4use std::{mem, os::raw, panic, ptr};
5
6/// Alias Widget ptr
7pub type WidgetPtr = *mut fltk_sys::widget::Fl_Widget;
8
9/// Get the grabbed window
10pub fn grab() -> Option<impl WindowExt> {
11    unsafe {
12        let ptr = fl::Fl_grab();
13        if ptr.is_null() {
14            None
15        } else {
16            Some(crate::window::Window::from_widget_ptr(ptr as *mut _))
17        }
18    }
19}
20
21/// Set the current grab
22pub fn set_grab<W: WindowExt>(win: Option<W>) {
23    unsafe {
24        win.map_or_else(
25            || fl::Fl_set_grab(ptr::null_mut()),
26            |w| fl::Fl_set_grab(w.as_widget_ptr() as *mut _),
27        );
28    }
29}
30
31/// Sets the callback of a widget
32pub fn set_callback<F, W>(widget: &mut W, cb: F)
33where
34    F: FnMut(&mut dyn WidgetExt),
35    W: WidgetExt,
36{
37    unsafe {
38        unsafe extern "C" fn shim(wid: *mut fltk_sys::widget::Fl_Widget, data: *mut raw::c_void) {
39            unsafe {
40                #[allow(clippy::type_complexity)]
41                let a: *mut Box<dyn FnMut(&mut dyn WidgetExt)> =
42                    data as *mut Box<dyn FnMut(&mut dyn WidgetExt)>;
43                let f: &mut (dyn FnMut(&mut dyn WidgetExt)) = &mut **a;
44                let mut wid = crate::widget::Widget::from_widget_ptr(wid);
45                let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| f(&mut wid)));
46            }
47        }
48        let mut _old_data = None;
49        if widget.is_derived() {
50            _old_data = widget.user_data();
51        }
52        #[allow(clippy::type_complexity)]
53        let a: *mut Box<dyn FnMut(&mut dyn WidgetExt)> = Box::into_raw(Box::new(Box::new(cb)));
54        let data: *mut raw::c_void = a as *mut raw::c_void;
55        let callback: fltk_sys::widget::Fl_Callback = Some(shim);
56        fltk_sys::widget::Fl_Widget_set_callback(widget.as_widget_ptr(), callback, data);
57    }
58}
59
60/**
61    Set a widget callback using a C style API
62    ```rust,no_run
63    use fltk::{prelude::*, *};
64    use std::os::raw::*;
65    // data can be anything, even a different widget
66    fn cb(w: app::WidgetPtr, data: *mut c_void) {
67        // To access the button
68        let mut btn = unsafe { button::Button::from_widget_ptr(w) }; // Gets a Widget
69        btn.set_label("Works!");
70        // To access the frame
71        let mut frm = unsafe { widget::Widget::from_widget_ptr(data as app::WidgetPtr) };
72        frm.set_label("Works!");
73    }
74    let mut but = button::Button::default();
75    let mut frame = frame::Frame::default();
76    unsafe {
77        // If no data needs to be passed, you can pass 0 as *mut _
78        app::set_raw_callback(&mut but, frame.as_widget_ptr() as *mut _, Some(cb));
79        // Using a closure also works
80        app::set_raw_callback(&mut but, frame.as_widget_ptr() as *mut _, Some(|_ , _| { println!("Also works!")}));
81    }
82    ```
83    # Safety
84    The function involves dereferencing externally provided raw pointers
85*/
86pub unsafe fn set_raw_callback<W>(
87    widget: &mut W,
88    data: *mut raw::c_void,
89    cb: Option<fn(WidgetPtr, *mut raw::c_void)>,
90) where
91    W: WidgetExt,
92{
93    unsafe {
94        let cb: Option<unsafe extern "C" fn(WidgetPtr, *mut raw::c_void)> = mem::transmute(cb);
95        fltk_sys::widget::Fl_Widget_set_callback(widget.as_widget_ptr(), cb, data);
96    }
97}
98
99/// Returns the first window of the application
100pub fn first_window() -> Option<impl WindowExt> {
101    unsafe {
102        let x = fl::Fl_first_window();
103        if x.is_null() {
104            None
105        } else {
106            let x = Window::from_widget_ptr(x as *mut fltk_sys::widget::Fl_Widget);
107            Some(x)
108        }
109    }
110}
111
112/// Returns the next window in order
113pub fn next_window<W: WindowExt>(w: &W) -> Option<impl WindowExt> {
114    unsafe {
115        let x = fl::Fl_next_window(w.as_widget_ptr() as *const raw::c_void);
116        if x.is_null() {
117            None
118        } else {
119            let x = Window::from_widget_ptr(x as *mut fltk_sys::widget::Fl_Widget);
120            Some(x)
121        }
122    }
123}
124
125/// Returns the last modal window of the application
126pub fn modal() -> Option<impl WindowExt> {
127    unsafe {
128        let x = fl::Fl_modal();
129        if x.is_null() {
130            None
131        } else {
132            let x = Window::from_widget_ptr(x as *mut fltk_sys::widget::Fl_Widget);
133            Some(x)
134        }
135    }
136}
137
138/// Deletes widgets and their children.
139pub fn delete_widget<Wid: WidgetBase>(wid: Wid) {
140    WidgetBase::delete(wid);
141}
142
143/// Sets the damage to true or false, eliciting a redraw by the application
144pub fn set_damage(flag: bool) {
145    let flag = if flag { 0x80 } else { 0 };
146    unsafe { fl::Fl_set_damage(flag) }
147}
148
149/// Returns whether any of the widgets were damaged
150pub fn damage() -> bool {
151    unsafe { fl::Fl_damage() != 0 }
152}
153
154/// Gets the widget which was pushed
155pub fn pushed() -> Option<impl WidgetExt> {
156    unsafe {
157        let ptr = fl::Fl_pushed();
158        if ptr.is_null() {
159            None
160        } else {
161            Some(crate::widget::Widget::from_widget_ptr(ptr as *mut _))
162        }
163    }
164}
165
166/// Gets the widget which has focus
167pub fn focus() -> Option<impl WidgetExt> {
168    unsafe {
169        let ptr = fl::Fl_focus();
170        if ptr.is_null() {
171            None
172        } else {
173            Some(crate::widget::Widget::from_widget_ptr(
174                ptr as *mut fltk_sys::widget::Fl_Widget,
175            ))
176        }
177    }
178}
179
180/// Sets the widget which has focus at the start of the application
181pub fn set_focus<W: WidgetExt>(wid: &W) {
182    unsafe { fl::Fl_set_focus(wid.as_widget_ptr() as *mut raw::c_void) }
183}
184
185/// Returns the apps windows.
186pub fn windows() -> Option<Vec<impl WindowExt>> {
187    let mut v: Vec<Window> = vec![];
188    if let Some(first) = first_window() {
189        let first: Window = unsafe { first.as_widget() };
190        v.push(first.clone());
191        let mut win = first;
192        while let Some(wind) = next_window(&win.clone()) {
193            let w = unsafe { wind.as_widget::<Window>() };
194            v.push(w.clone());
195            win = w;
196        }
197        Some(v)
198    } else {
199        None
200    }
201}