Skip to main content

dear_imgui_rs/widget/
button.rs

1//! Buttons
2//!
3//! Push-button widgets with optional sizing and configuration helpers.
4//!
5use crate::Ui;
6use crate::sys;
7use std::borrow::Cow;
8
9fn assert_finite_vec2(caller: &str, name: &str, value: [f32; 2]) {
10    assert!(
11        value[0].is_finite() && value[1].is_finite(),
12        "{caller} {name} must contain finite values"
13    );
14}
15
16impl Ui {
17    /// Creates a button with the given label
18    #[doc(alias = "Button")]
19    pub fn button(&self, label: impl AsRef<str>) -> bool {
20        self.button_config(label.as_ref()).build()
21    }
22
23    /// Creates a button with the given label and size
24    #[doc(alias = "Button")]
25    pub fn button_with_size(&self, label: impl AsRef<str>, size: impl Into<[f32; 2]>) -> bool {
26        self.button_config(label.as_ref()).size(size).build()
27    }
28
29    /// Creates a button builder
30    pub fn button_config<'ui>(&'ui self, label: impl Into<Cow<'ui, str>>) -> Button<'ui> {
31        Button::new(self, label)
32    }
33}
34
35impl Ui {
36    /// Creates a checkbox
37    #[doc(alias = "Checkbox")]
38    pub fn checkbox(&self, label: impl AsRef<str>, value: &mut bool) -> bool {
39        let label_ptr = self.scratch_txt(label);
40        unsafe { sys::igCheckbox(label_ptr, value) }
41    }
42
43    /// Creates a radio button
44    #[doc(alias = "RadioButton")]
45    pub fn radio_button(&self, label: impl AsRef<str>, active: bool) -> bool {
46        let label_ptr = self.scratch_txt(label);
47        unsafe { sys::igRadioButton_Bool(label_ptr, active) }
48    }
49
50    /// Creates a radio button with integer value
51    #[doc(alias = "RadioButton")]
52    pub fn radio_button_int(&self, label: impl AsRef<str>, v: &mut i32, v_button: i32) -> bool {
53        let label_ptr = self.scratch_txt(label);
54        unsafe { sys::igRadioButton_IntPtr(label_ptr, v, v_button) }
55    }
56
57    /// Creates a radio button suitable for choosing an arbitrary value.
58    ///
59    /// Returns true if this radio button was clicked.
60    #[doc(alias = "RadioButtonBool")]
61    pub fn radio_button_bool(&self, label: impl AsRef<str>, active: bool) -> bool {
62        let label_ptr = self.scratch_txt(label);
63        unsafe { sys::igRadioButton_Bool(label_ptr, active) }
64    }
65
66    /// Renders a checkbox suitable for toggling bit flags using a mask.
67    ///
68    /// Returns true if this checkbox was clicked.
69    ///
70    /// This matches the semantics of Dear ImGui's `CheckboxFlags()` helpers:
71    /// the checkbox is checked when `(*flags & mask) == mask`, and clicking it
72    /// toggles the bits in `mask`.
73    #[doc(alias = "CheckboxFlags")]
74    pub fn checkbox_flags<T>(&self, label: impl AsRef<str>, flags: &mut T, mask: T) -> bool
75    where
76        T: Copy
77            + PartialEq
78            + std::ops::BitOrAssign
79            + std::ops::BitAndAssign
80            + std::ops::BitAnd<Output = T>
81            + std::ops::Not<Output = T>,
82    {
83        let mut value = *flags & mask == mask;
84        let pressed = self.checkbox(label, &mut value);
85        if pressed {
86            if value {
87                *flags |= mask;
88            } else {
89                *flags &= !mask;
90            }
91        }
92        pressed
93    }
94}
95
96/// Builder for button widget
97pub struct Button<'ui> {
98    ui: &'ui Ui,
99    label: Cow<'ui, str>,
100    size: Option<[f32; 2]>,
101}
102
103impl<'ui> Button<'ui> {
104    /// Creates a new button builder
105    pub fn new(ui: &'ui Ui, label: impl Into<Cow<'ui, str>>) -> Self {
106        Self {
107            ui,
108            label: label.into(),
109            size: None,
110        }
111    }
112
113    /// Sets the size of the button
114    pub fn size(mut self, size: impl Into<[f32; 2]>) -> Self {
115        self.size = Some(size.into());
116        self
117    }
118
119    /// Builds the button
120    pub fn build(self) -> bool {
121        let label_ptr = self.ui.scratch_txt(self.label.as_ref());
122        let size = self.size.unwrap_or([0.0, 0.0]);
123        assert_finite_vec2("Button::build()", "size", size);
124        let size_vec: sys::ImVec2 = size.into();
125        unsafe { sys::igButton(label_ptr, size_vec) }
126    }
127}