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    pub struct IdStackToken<'ui>;
56
57    /// Pops a change from the ID stack
58    drop { unsafe { sys::igPopID() } }
59);
60
61impl IdStackToken<'_> {
62    /// Pops a change from the ID stack.
63    pub fn pop(self) {
64        self.end()
65    }
66}
67
68// ============================================================================
69// Focus scope stack
70// ============================================================================
71
72create_token!(
73    /// Tracks a pushed focus scope, popped on drop.
74    pub struct FocusScopeToken<'ui>;
75
76    /// Pops a focus scope.
77    #[doc(alias = "PopFocusScope")]
78    drop { unsafe { sys::igPopFocusScope() } }
79);
80
81impl Ui {
82    /// Push a focus scope (affects e.g. navigation focus allocation).
83    ///
84    /// Returns a `FocusScopeToken` which will pop the focus scope when dropped.
85    #[doc(alias = "PushFocusScope")]
86    pub fn push_focus_scope(&self, id: crate::Id) -> FocusScopeToken<'_> {
87        self.run_with_bound_context(|| unsafe { sys::igPushFocusScope(id.raw()) });
88        FocusScopeToken::new(self)
89    }
90}
91
92/// Represents an identifier that can be pushed to the ID stack
93#[derive(Copy, Clone, Debug)]
94pub enum Id<'a> {
95    /// Integer identifier
96    Int(i32),
97    /// String identifier
98    Str(&'a str),
99    /// Pointer identifier
100    Ptr(*const std::ffi::c_void),
101}
102
103impl From<i32> for Id<'_> {
104    fn from(i: i32) -> Self {
105        Id::Int(i)
106    }
107}
108
109impl From<usize> for Id<'_> {
110    fn from(i: usize) -> Self {
111        Id::Int(i as i32)
112    }
113}
114
115impl<'a> From<&'a str> for Id<'a> {
116    fn from(s: &'a str) -> Self {
117        Id::Str(s)
118    }
119}
120
121impl<'a> From<&'a String> for Id<'a> {
122    fn from(s: &'a String) -> Self {
123        Id::Str(s.as_str())
124    }
125}
126
127impl<T> From<*const T> for Id<'_> {
128    fn from(p: *const T) -> Self {
129        Id::Ptr(p as *const std::ffi::c_void)
130    }
131}
132
133impl<T> From<*mut T> for Id<'_> {
134    fn from(p: *mut T) -> Self {
135        Id::Ptr(p as *const std::ffi::c_void)
136    }
137}