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}