boing 0.7.0

A safe wrapper over libui-ng-sys
Documentation
// SPDX-License-Identifier: MPL-2.0

//! A set of mutually-exclusive selectable items.

use std::cell::Cell;

use crate::prelude::*;

impl Ui {
    /// Creates a new set of [`RadioButtons`].
    pub fn create_radio_buttons<'ui>(&'ui self) -> Result<&'ui mut RadioButtons, crate::Error> {
        unsafe { call_libui_new_fn!(ui: self, fn: uiNewRadioButtons() -> RadioButtons) }
    }
}

/// A set of mutually-exclusive selectable items.
#[subcontrol(handle = "uiRadioButtons")]
pub struct RadioButtons {
    child_count: Cell<u16>,
}

impl<'ui> RadioButtons<'ui> {
    /// Appends a new item with the given text, returning its index.
    ///
    /// The new item is appended to the bottom of the button set.
    pub fn push_item(&self, text: impl Into<Vec<u8>>) -> Result<NonNegativeInt, crate::Error> {
        let index = self.child_count.get();
        let text = self.ui.make_cstring(text)?;
        unsafe { uiRadioButtonsAppend(self.as_ptr(), text.as_ptr()) };
        self.child_count.set(index + 1);

        Ok(NonNegativeInt::from(index))
    }

    /// The index of the currently-selected item.
    ///
    /// If no item is selected, this returns `None`.
    pub fn selected_item(&self) -> Option<NonNegativeInt> {
        match unsafe { uiRadioButtonsSelected(self.as_ptr()) } {
            -1 => None,
            it => Some(unsafe { NonNegativeInt::from_libui(it) }),
        }
    }

    /// Selects the item with the given index.
    ///
    /// This overrides any selections made by the user.
    ///
    /// # Panics
    ///
    /// Panics if `index` is out of bounds.
    pub fn select_item(&self, index: impl Into<NonNegativeInt>) {
        let index = index.into();
        assert!(index.as_u32() < self.child_count.get().into(), "item index is out of bounds");

        unsafe { uiRadioButtonsSetSelected(self.as_ptr(), index.to_libui()) };
    }

    /// De-selects the currently-selected item.
    ///
    /// This overrides any selections made by the user. If no item is selected, this does nothing.
    #[inline]
    pub fn deselect_item(&self) {
        unsafe { uiRadioButtonsSetSelected(self.as_ptr(), -1) };
    }

    /// Sets a callback for when an item is selected.
    ///
    /// This callback is unset by default. This is not activated when
    /// [`select_item`](Self::select_item) is called.
    #[bind_callback(fn = "uiRadioButtonsOnSelected")]
    pub fn on_item_selected(&self, f: fn()) {
        f();
    }
}