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}