Skip to main content

dear_imgui_rs/widget/
misc.rs

1//! Miscellaneous widgets
2//!
3//! Small convenience widgets that don’t fit elsewhere (e.g. bullets, help
4//! markers). See functions on `Ui` for details.
5//!
6#![allow(
7    clippy::cast_possible_truncation,
8    clippy::cast_sign_loss,
9    clippy::as_conversions
10)]
11use crate::Ui;
12use crate::sys;
13
14bitflags::bitflags! {
15    /// Flags for invisible buttons
16    #[repr(transparent)]
17    #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
18    pub struct ButtonFlags: i32 {
19        /// No flags
20        const NONE = 0;
21        /// Allow interaction overlap with following items.
22        const ALLOW_OVERLAP = sys::ImGuiButtonFlags_AllowOverlap as i32;
23        /// React on left mouse button
24        const MOUSE_BUTTON_LEFT = sys::ImGuiButtonFlags_MouseButtonLeft as i32;
25        /// React on right mouse button
26        const MOUSE_BUTTON_RIGHT = sys::ImGuiButtonFlags_MouseButtonRight as i32;
27        /// React on middle mouse button
28        const MOUSE_BUTTON_MIDDLE = sys::ImGuiButtonFlags_MouseButtonMiddle as i32;
29    }
30}
31
32/// Direction for arrow buttons (alias for Direction)
33pub use crate::Direction as ArrowDirection;
34
35impl Ui {
36    /// Creates a bullet point
37    #[doc(alias = "Bullet")]
38    pub fn bullet(&self) {
39        unsafe {
40            sys::igBullet();
41        }
42    }
43
44    /// Creates a bullet point with text
45    #[doc(alias = "BulletText")]
46    pub fn bullet_text(&self, text: impl AsRef<str>) {
47        let text_ptr = self.scratch_txt(text);
48        unsafe {
49            // Always treat the value as unformatted user text.
50            const FMT: &[u8; 3] = b"%s\0";
51            sys::igBulletText(FMT.as_ptr() as *const std::os::raw::c_char, text_ptr);
52        }
53    }
54}
55
56impl Ui {
57    /// Creates a small button
58    #[doc(alias = "SmallButton")]
59    pub fn small_button(&self, label: impl AsRef<str>) -> bool {
60        let label_ptr = self.scratch_txt(label);
61        unsafe { sys::igSmallButton(label_ptr) }
62    }
63
64    /// Creates an invisible button
65    #[doc(alias = "InvisibleButton")]
66    pub fn invisible_button(&self, str_id: impl AsRef<str>, size: impl Into<[f32; 2]>) -> bool {
67        self.invisible_button_flags(str_id, size, crate::widget::ButtonFlags::NONE)
68    }
69
70    /// Creates an invisible button with flags
71    #[doc(alias = "InvisibleButton")]
72    pub fn invisible_button_flags(
73        &self,
74        str_id: impl AsRef<str>,
75        size: impl Into<[f32; 2]>,
76        flags: crate::widget::ButtonFlags,
77    ) -> bool {
78        let id_ptr = self.scratch_txt(str_id);
79        let size_vec: sys::ImVec2 = size.into().into();
80        unsafe { sys::igInvisibleButton(id_ptr, size_vec, flags.bits()) }
81    }
82
83    /// Creates an arrow button
84    #[doc(alias = "ArrowButton")]
85    pub fn arrow_button(&self, str_id: impl AsRef<str>, dir: crate::Direction) -> bool {
86        let id_ptr = self.scratch_txt(str_id);
87        unsafe { sys::igArrowButton(id_ptr, dir as i32) }
88    }
89}
90
91// ============================================================================
92// Disabled scope (RAII)
93// ============================================================================
94
95/// Tracks a disabled scope begun with [`Ui::begin_disabled`] and ended on drop.
96#[must_use]
97pub struct DisabledToken<'ui> {
98    _ui: &'ui Ui,
99}
100
101impl<'ui> DisabledToken<'ui> {
102    fn new(ui: &'ui Ui) -> Self {
103        DisabledToken { _ui: ui }
104    }
105
106    /// Ends the disabled scope explicitly.
107    pub fn end(self) {
108        // Drop will call EndDisabled
109    }
110}
111
112impl<'ui> Drop for DisabledToken<'ui> {
113    fn drop(&mut self) {
114        unsafe { sys::igEndDisabled() }
115    }
116}
117
118impl Ui {
119    /// Begin a disabled scope for subsequent items.
120    ///
121    /// All following widgets will be disabled (grayed out and non-interactive)
122    /// until the returned token is dropped.
123    #[doc(alias = "BeginDisabled")]
124    pub fn begin_disabled(&self) -> DisabledToken<'_> {
125        unsafe { sys::igBeginDisabled(true) }
126        DisabledToken::new(self)
127    }
128
129    /// Begin a conditionally disabled scope for subsequent items.
130    ///
131    /// If `disabled` is false, this still needs to be paired with the returned
132    /// token being dropped to correctly balance the internal stack.
133    #[doc(alias = "BeginDisabled")]
134    pub fn begin_disabled_with_cond(&self, disabled: bool) -> DisabledToken<'_> {
135        unsafe { sys::igBeginDisabled(disabled) }
136        DisabledToken::new(self)
137    }
138}
139
140// ============================================================================
141// Button repeat (convenience over item flag)
142// ============================================================================
143
144impl Ui {
145    /// Enable/disable repeating behavior for subsequent buttons.
146    ///
147    /// Internally uses `PushItemFlag(ImGuiItemFlags_ButtonRepeat, repeat)`.
148    #[doc(alias = "PushButtonRepeat")]
149    pub fn push_button_repeat(&self, repeat: bool) {
150        unsafe { sys::igPushItemFlag(sys::ImGuiItemFlags_ButtonRepeat as i32, repeat) }
151    }
152
153    /// Pop the button repeat item flag.
154    #[doc(alias = "PopButtonRepeat")]
155    pub fn pop_button_repeat(&self) {
156        unsafe { sys::igPopItemFlag() }
157    }
158}
159
160// ============================================================================
161// Item key ownership
162// ============================================================================
163
164impl Ui {
165    /// Set the key owner for the last item, without flags.
166    #[doc(alias = "SetItemKeyOwner")]
167    pub fn set_item_key_owner(&self, key: crate::input::Key) {
168        let k: sys::ImGuiKey = key as sys::ImGuiKey;
169        unsafe { sys::igSetItemKeyOwner_Nil(k) }
170    }
171
172    /// Set the key owner for the last item with input flags.
173    #[doc(alias = "SetItemKeyOwner")]
174    pub fn set_item_key_owner_with_flags(
175        &self,
176        key: crate::input::Key,
177        flags: crate::input::ItemKeyOwnerFlags,
178    ) {
179        let k: sys::ImGuiKey = key as sys::ImGuiKey;
180        unsafe { sys::igSetItemKeyOwner_InputFlags(k, flags.raw()) }
181    }
182}