Skip to main content

dear_imgui_rs/stacks/
item.rs

1use bitflags::bitflags;
2
3use crate::{Ui, sys};
4
5bitflags! {
6    /// Flags that can be applied to subsequently submitted items.
7    #[repr(transparent)]
8    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
9    pub struct ItemFlags: i32 {
10        /// No item flags.
11        const NONE = sys::ImGuiItemFlags_None as i32;
12        /// Disable keyboard tabbing while retaining directional navigation.
13        const NO_TAB_STOP = sys::ImGuiItemFlags_NoTabStop as i32;
14        /// Disable keyboard and gamepad navigation.
15        const NO_NAV = sys::ImGuiItemFlags_NoNav as i32;
16        /// Prevent the item from receiving default navigation focus.
17        const NO_NAV_DEFAULT_FOCUS = sys::ImGuiItemFlags_NoNavDefaultFocus as i32;
18        /// Enable repeat behavior for button-like items.
19        const BUTTON_REPEAT = sys::ImGuiItemFlags_ButtonRepeat as i32;
20        /// Automatically close a parent popup after activating a menu item or selectable.
21        const AUTO_CLOSE_POPUPS = sys::ImGuiItemFlags_AutoClosePopups as i32;
22        /// Allow duplicate item IDs without a debug conflict warning.
23        const ALLOW_DUPLICATE_ID = sys::ImGuiItemFlags_AllowDuplicateId as i32;
24        /// Apply `InputText` keyboard edits to the backing value while typing.
25        const LIVE_EDIT_ON_INPUT_TEXT = sys::ImGuiItemFlags_LiveEditOnInputText as i32;
26        /// Apply scalar keyboard edits to the backing value while typing.
27        const LIVE_EDIT_ON_INPUT_SCALAR = sys::ImGuiItemFlags_LiveEditOnInputScalar as i32;
28        /// Apply text and scalar keyboard edits to backing values while typing.
29        const LIVE_EDIT_ON_INPUT = sys::ImGuiItemFlags_LiveEditOnInput as i32;
30    }
31}
32
33bitflags! {
34    /// Flags recorded for the last submitted item.
35    ///
36    /// This includes the public flags accepted by [`Ui::push_item_flag`] plus
37    /// read-only state such as [`Self::DISABLED`]. Unknown internal bits are
38    /// retained when returned by [`Ui::item_flags`].
39    #[repr(transparent)]
40    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
41    pub struct ItemStateFlags: i32 {
42        /// No item flags.
43        const NONE = sys::ImGuiItemFlags_None as i32;
44        /// Keyboard tabbing was disabled while retaining directional navigation.
45        const NO_TAB_STOP = sys::ImGuiItemFlags_NoTabStop as i32;
46        /// Keyboard and gamepad navigation was disabled.
47        const NO_NAV = sys::ImGuiItemFlags_NoNav as i32;
48        /// The item could not receive default navigation focus.
49        const NO_NAV_DEFAULT_FOCUS = sys::ImGuiItemFlags_NoNavDefaultFocus as i32;
50        /// Repeat behavior was enabled for the item.
51        const BUTTON_REPEAT = sys::ImGuiItemFlags_ButtonRepeat as i32;
52        /// The item could automatically close its parent popup.
53        const AUTO_CLOSE_POPUPS = sys::ImGuiItemFlags_AutoClosePopups as i32;
54        /// Duplicate IDs were allowed for the item.
55        const ALLOW_DUPLICATE_ID = sys::ImGuiItemFlags_AllowDuplicateId as i32;
56        /// `InputText` keyboard edits were applied while typing.
57        const LIVE_EDIT_ON_INPUT_TEXT = sys::ImGuiItemFlags_LiveEditOnInputText as i32;
58        /// Scalar keyboard edits were applied while typing.
59        const LIVE_EDIT_ON_INPUT_SCALAR = sys::ImGuiItemFlags_LiveEditOnInputScalar as i32;
60        /// Text and scalar keyboard edits were applied while typing.
61        const LIVE_EDIT_ON_INPUT = sys::ImGuiItemFlags_LiveEditOnInput as i32;
62        /// The last item was disabled.
63        const DISABLED = sys::ImGuiItemFlags_Disabled as i32;
64    }
65}
66
67impl Default for ItemFlags {
68    fn default() -> Self {
69        Self::NONE
70    }
71}
72
73impl Default for ItemStateFlags {
74    fn default() -> Self {
75        Self::NONE
76    }
77}
78
79impl From<ItemFlags> for ItemStateFlags {
80    fn from(flags: ItemFlags) -> Self {
81        Self::from_bits_retain(flags.bits())
82    }
83}
84
85create_token!(
86    /// Tracks item flags pushed with [`Ui::push_item_flag`].
87    pub struct ItemFlagStackToken<'ui>;
88
89    /// Pops item flags pushed with [`Ui::push_item_flag`].
90    #[doc(alias = "PopItemFlag")]
91    drop { unsafe { sys::igPopItemFlag() } }
92);
93
94impl ItemFlagStackToken<'_> {
95    /// Pops the item flag scope.
96    pub fn pop(self) {
97        self.end()
98    }
99}
100
101impl Ui {
102    /// Returns the flags recorded for the last submitted item.
103    ///
104    /// Unknown bits introduced by newer Dear ImGui versions are retained.
105    #[doc(alias = "GetItemFlags")]
106    pub fn item_flags(&self) -> ItemStateFlags {
107        self.run_with_bound_context(|| unsafe {
108            ItemStateFlags::from_bits_retain(sys::igGetItemFlags())
109        })
110    }
111
112    /// Enables or disables flags for subsequently submitted items.
113    ///
114    /// The returned token restores the previous item flags when dropped.
115    #[doc(alias = "PushItemFlag")]
116    pub fn push_item_flag(&self, flags: ItemFlags, enabled: bool) -> ItemFlagStackToken<'_> {
117        self.run_with_bound_context(|| unsafe { sys::igPushItemFlag(flags.bits(), enabled) });
118        ItemFlagStackToken::new(self)
119    }
120
121    /// Runs `f` with the requested item flags enabled or disabled.
122    ///
123    /// The previous flags are restored even if `f` panics.
124    #[doc(alias = "PushItemFlag", alias = "PopItemFlag")]
125    pub fn with_item_flag<R>(&self, flags: ItemFlags, enabled: bool, f: impl FnOnce() -> R) -> R {
126        let _flags = self.push_item_flag(flags, enabled);
127        f()
128    }
129}
130
131#[cfg(test)]
132mod tests {
133    use super::*;
134
135    fn setup_context() -> crate::Context {
136        let mut ctx = crate::Context::create();
137        ctx.io_mut().set_display_size([128.0, 128.0]);
138        ctx.io_mut().set_delta_time(1.0 / 60.0);
139        let _ = ctx.font_atlas().build();
140        ctx
141    }
142
143    #[test]
144    fn item_flag_scope_is_typed_and_restores_previous_flags() {
145        let mut ctx = setup_context();
146        let ui = ctx.frame();
147
148        ui.window("item_flags").build(|| {
149            ui.with_item_flag(
150                ItemFlags::NO_NAV
151                    | ItemFlags::ALLOW_DUPLICATE_ID
152                    | ItemFlags::LIVE_EDIT_ON_INPUT_SCALAR,
153                true,
154                || {
155                    ui.button("scoped");
156                    let flags = ui.item_flags();
157                    assert!(flags.contains(ItemStateFlags::NO_NAV));
158                    assert!(flags.contains(ItemStateFlags::ALLOW_DUPLICATE_ID));
159                    assert!(flags.contains(ItemStateFlags::LIVE_EDIT_ON_INPUT_SCALAR));
160                },
161            );
162
163            ui.button("restored");
164            let flags = ui.item_flags();
165            assert!(!flags.contains(ItemStateFlags::NO_NAV));
166            assert!(!flags.contains(ItemStateFlags::ALLOW_DUPLICATE_ID));
167            assert!(!flags.contains(ItemStateFlags::LIVE_EDIT_ON_INPUT_SCALAR));
168        });
169    }
170
171    #[test]
172    fn item_flag_scope_can_clear_defaults_and_reports_disabled_items() {
173        let mut ctx = setup_context();
174        let ui = ctx.frame();
175
176        ui.window("item_flag_values").build(|| {
177            ui.button("default");
178            assert!(ui.item_flags().contains(ItemStateFlags::AUTO_CLOSE_POPUPS));
179
180            {
181                let _flags = ui.push_item_flag(ItemFlags::AUTO_CLOSE_POPUPS, false);
182                ui.button("without_auto_close");
183                assert!(!ui.item_flags().contains(ItemStateFlags::AUTO_CLOSE_POPUPS));
184            }
185
186            ui.button("restored_default");
187            assert!(ui.item_flags().contains(ItemStateFlags::AUTO_CLOSE_POPUPS));
188
189            {
190                let _disabled = ui.begin_disabled();
191                ui.button("disabled");
192                assert!(ui.item_flags().contains(ItemStateFlags::DISABLED));
193            }
194        });
195    }
196}