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}