Skip to main content

dear_imgui_rs/
state_storage.rs

1//! State storage utilities
2//!
3//! Dear ImGui provides a per-window key/value storage (`ImGuiStorage`) that is
4//! used by many widgets and can also be used by custom widgets to persist state.
5//!
6use crate::{Id, Ui, sys};
7use std::marker::PhantomData;
8use std::ptr::NonNull;
9
10/// A non-owning reference to an `ImGuiStorage` belonging to the current context.
11#[derive(Copy, Clone, Debug)]
12pub struct StateStorage<'ui> {
13    raw: NonNull<sys::ImGuiStorage>,
14    _phantom: PhantomData<&'ui mut sys::ImGuiStorage>,
15}
16
17impl<'ui> StateStorage<'ui> {
18    /// # Safety
19    /// `raw` must be a valid, non-null pointer to an `ImGuiStorage`.
20    pub unsafe fn from_raw(raw: *mut sys::ImGuiStorage) -> Self {
21        let raw = NonNull::new(raw).expect("StateStorage::from_raw() requires non-null pointer");
22        Self {
23            raw,
24            _phantom: PhantomData,
25        }
26    }
27
28    /// Returns the raw `ImGuiStorage*`.
29    pub fn as_raw(self) -> *mut sys::ImGuiStorage {
30        self.raw.as_ptr()
31    }
32
33    /// Clears all storage entries.
34    pub fn clear(&mut self) {
35        unsafe { sys::ImGuiStorage_Clear(self.raw.as_ptr()) }
36    }
37
38    pub fn get_int(&self, key: Id, default: i32) -> i32 {
39        unsafe { sys::ImGuiStorage_GetInt(self.raw.as_ptr(), key.raw(), default) }
40    }
41
42    pub fn set_int(&mut self, key: Id, value: i32) {
43        unsafe { sys::ImGuiStorage_SetInt(self.raw.as_ptr(), key.raw(), value) }
44    }
45
46    pub fn get_bool(&self, key: Id, default: bool) -> bool {
47        unsafe { sys::ImGuiStorage_GetBool(self.raw.as_ptr(), key.raw(), default) }
48    }
49
50    pub fn set_bool(&mut self, key: Id, value: bool) {
51        unsafe { sys::ImGuiStorage_SetBool(self.raw.as_ptr(), key.raw(), value) }
52    }
53
54    pub fn get_float(&self, key: Id, default: f32) -> f32 {
55        unsafe { sys::ImGuiStorage_GetFloat(self.raw.as_ptr(), key.raw(), default) }
56    }
57
58    pub fn set_float(&mut self, key: Id, value: f32) {
59        unsafe { sys::ImGuiStorage_SetFloat(self.raw.as_ptr(), key.raw(), value) }
60    }
61}
62
63/// Owns an `ImGuiStorage` and clears it on drop.
64///
65/// This is useful when you want to keep widget state outside of the current
66/// window storage (e.g. sharing state across windows or providing custom storage
67/// for a widget subtree via `Ui::push_state_storage`).
68#[derive(Debug, Default)]
69pub struct OwnedStateStorage {
70    raw: sys::ImGuiStorage,
71}
72
73impl OwnedStateStorage {
74    pub fn new() -> Self {
75        Self::default()
76    }
77
78    pub fn as_mut(&mut self) -> &mut sys::ImGuiStorage {
79        &mut self.raw
80    }
81
82    pub fn as_ref(&self) -> &sys::ImGuiStorage {
83        &self.raw
84    }
85
86    pub fn as_raw_mut(&mut self) -> *mut sys::ImGuiStorage {
87        &mut self.raw as *mut sys::ImGuiStorage
88    }
89
90    pub fn as_raw(&self) -> *const sys::ImGuiStorage {
91        &self.raw as *const sys::ImGuiStorage
92    }
93}
94
95impl Drop for OwnedStateStorage {
96    fn drop(&mut self) {
97        unsafe { sys::ImGuiStorage_Clear(self.as_raw_mut()) }
98    }
99}
100
101/// RAII token that restores the previous state storage on drop.
102#[must_use]
103pub struct StateStorageToken<'ui, 'storage> {
104    ui: &'ui Ui,
105    prev: *mut sys::ImGuiStorage,
106    _marker: PhantomData<&'storage mut sys::ImGuiStorage>,
107}
108
109impl Drop for StateStorageToken<'_, '_> {
110    fn drop(&mut self) {
111        self.ui
112            .run_with_bound_context(|| unsafe { sys::igSetStateStorage(self.prev) });
113    }
114}
115
116impl crate::ui::Ui {
117    /// Returns the current window's state storage.
118    #[doc(alias = "GetStateStorage")]
119    pub fn state_storage(&self) -> StateStorage<'_> {
120        self.run_with_bound_context(|| unsafe { StateStorage::from_raw(sys::igGetStateStorage()) })
121    }
122
123    /// Overrides the current state storage until the returned token is dropped.
124    #[doc(alias = "SetStateStorage")]
125    pub fn push_state_storage<'storage>(
126        &self,
127        storage: &'storage mut sys::ImGuiStorage,
128    ) -> StateStorageToken<'_, 'storage> {
129        self.run_with_bound_context(|| unsafe {
130            let prev = sys::igGetStateStorage();
131            sys::igSetStateStorage(storage as *mut sys::ImGuiStorage);
132            StateStorageToken {
133                ui: self,
134                prev,
135                _marker: PhantomData,
136            }
137        })
138    }
139
140    /// Set the storage ID for the next item.
141    #[doc(alias = "SetNextItemStorageID")]
142    pub fn set_next_item_storage_id(&self, storage_id: Id) {
143        self.run_with_bound_context(|| unsafe { sys::igSetNextItemStorageID(storage_id.raw()) });
144    }
145}