Skip to main content

dear_imgui_rs/stacks/
id.rs

1use crate::{Ui, sys};
2
3/// # ID stack
4impl Ui {
5    /// Pushes an identifier to the ID stack.
6    ///
7    /// Returns an `IdStackToken` that can be popped by calling `.end()`
8    /// or by dropping manually.
9    ///
10    /// # Examples
11    /// Dear ImGui uses labels to uniquely identify widgets. For a good explanation, see this part of the [Dear ImGui FAQ][faq]
12    ///
13    /// [faq]: https://github.com/ocornut/imgui/blob/v1.84.2/docs/FAQ.md#q-why-is-my-widget-not-reacting-when-i-click-on-it
14    ///
15    /// In `dear-imgui-rs` the same applies, we can manually specify labels with the `##` syntax:
16    ///
17    /// ```no_run
18    /// # let mut imgui = dear_imgui_rs::Context::create();
19    /// # let ui = imgui.frame();
20    ///
21    /// ui.button("Click##button1");
22    /// ui.button("Click##button2");
23    /// ```
24    ///
25    /// But sometimes we want to create widgets in a loop, or we want to avoid
26    /// having to manually give each widget a unique label. In these cases, we can
27    /// push an ID to the ID stack:
28    ///
29    /// ```no_run
30    /// # let mut imgui = dear_imgui_rs::Context::create();
31    /// # let ui = imgui.frame();
32    ///
33    /// for i in 0..10 {
34    ///     let _id = ui.push_id(i);
35    ///     ui.button("Click");
36    /// }
37    /// ```
38    #[doc(alias = "PushID")]
39    pub fn push_id<'a, T: Into<Id<'a>>>(&self, id: T) -> IdStackToken<'_> {
40        let id = id.into();
41        self.run_with_bound_context(|| unsafe {
42            match id {
43                Id::Int(i) => sys::igPushID_Int(i),
44                Id::Str(s) => sys::igPushID_Str(self.scratch_txt(s)),
45                Id::Ptr(p) => sys::igPushID_Ptr(p),
46            }
47        });
48        IdStackToken::new(self)
49    }
50}
51
52create_token!(
53    /// Tracks an ID pushed to the ID stack that can be popped by calling `.pop()`
54    /// or by dropping. See [`crate::Ui::push_id`] for more details.
55    #[doc(alias = "PopID")]
56    pub struct IdStackToken<'ui>;
57
58    pop crate::scope::NativeScopePop::PopId;
59
60    /// Pops a change from the ID stack
61    drop { unsafe { sys::igPopID() } }
62);
63
64impl IdStackToken<'_> {
65    /// Pops a change from the ID stack.
66    ///
67    /// # Panics
68    ///
69    /// Panics under the same conditions as [`Self::end`].
70    pub fn pop(self) {
71        self.end()
72    }
73}
74
75// ============================================================================
76// Focus scope stack
77// ============================================================================
78
79create_token!(
80    /// Tracks a pushed focus scope, popped on drop.
81    pub struct FocusScopeToken<'ui>;
82
83    pop crate::scope::NativeScopePop::PopFocusScope;
84
85    /// Pops a focus scope.
86    #[doc(alias = "PopFocusScope")]
87    drop { unsafe { sys::igPopFocusScope() } }
88);
89
90impl Ui {
91    /// Push a focus scope (affects e.g. navigation focus allocation).
92    ///
93    /// Returns a `FocusScopeToken` which will pop the focus scope when dropped.
94    #[doc(alias = "PushFocusScope")]
95    pub fn push_focus_scope(&self, id: crate::Id) -> FocusScopeToken<'_> {
96        self.run_with_bound_context(|| unsafe { sys::igPushFocusScope(id.raw()) });
97        FocusScopeToken::new(self)
98    }
99}
100
101/// Represents an identifier that can be pushed to the ID stack
102#[derive(Copy, Clone, Debug)]
103pub enum Id<'a> {
104    /// Integer identifier
105    Int(i32),
106    /// String identifier
107    Str(&'a str),
108    /// Pointer identifier
109    Ptr(*const std::ffi::c_void),
110}
111
112impl From<i32> for Id<'_> {
113    fn from(i: i32) -> Self {
114        Id::Int(i)
115    }
116}
117
118impl From<usize> for Id<'_> {
119    fn from(i: usize) -> Self {
120        Id::Int(i as i32)
121    }
122}
123
124impl<'a> From<&'a str> for Id<'a> {
125    fn from(s: &'a str) -> Self {
126        Id::Str(s)
127    }
128}
129
130impl<'a> From<&'a String> for Id<'a> {
131    fn from(s: &'a String) -> Self {
132        Id::Str(s.as_str())
133    }
134}
135
136impl<T> From<*const T> for Id<'_> {
137    fn from(p: *const T) -> Self {
138        Id::Ptr(p as *const std::ffi::c_void)
139    }
140}
141
142impl<T> From<*mut T> for Id<'_> {
143    fn from(p: *mut T) -> Self {
144        Id::Ptr(p as *const std::ffi::c_void)
145    }
146}