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