gtk4/
spin_button.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{boxed::Box as Box_, mem::transmute};
4
5use glib::{
6    signal::{connect_raw, SignalHandlerId},
7    translate::*,
8};
9use libc::{c_double, c_int};
10
11use crate::{ffi, prelude::*, SpinButton};
12
13impl SpinButton {
14    /// Emitted to convert the users input into a double value.
15    ///
16    /// The signal handler is expected to use [`EditableExt::text()`][crate::prelude::EditableExt::text()]
17    /// to retrieve the text of the spinbutton and set @new_value to the
18    /// new value.
19    ///
20    /// The default conversion uses g_strtod().
21    ///
22    /// # Returns
23    ///
24    /// [`true`] for a successful conversion, [`false`] if the input
25    ///   was not handled, and `GTK_INPUT_ERROR` if the conversion failed.
26    ///
27    /// ## `new_value`
28    /// return location for the new value
29    pub fn connect_input<F>(&self, f: F) -> SignalHandlerId
30    where
31        F: Fn(&Self) -> Option<Result<f64, ()>> + 'static,
32    {
33        unsafe {
34            let f: Box_<F> = Box_::new(f);
35            connect_raw(
36                self.as_ptr() as *mut _,
37                b"input\0".as_ptr() as *mut _,
38                Some(transmute::<usize, unsafe extern "C" fn()>(
39                    input_trampoline::<F> as usize,
40                )),
41                Box_::into_raw(f),
42            )
43        }
44    }
45}
46
47unsafe extern "C" fn input_trampoline<F: Fn(&SpinButton) -> Option<Result<f64, ()>> + 'static>(
48    this: *mut ffi::GtkSpinButton,
49    new_value: *mut c_double,
50    f: &F,
51) -> c_int {
52    match f(SpinButton::from_glib_borrow(this).unsafe_cast_ref()) {
53        Some(Ok(v)) => {
54            *new_value = v;
55            glib::ffi::GTRUE
56        }
57        Some(Err(_)) => ffi::GTK_INPUT_ERROR,
58        None => glib::ffi::GFALSE,
59    }
60}