Skip to main content

dear_imgui_rs/ui/
core.rs

1use super::*;
2
3impl Ui {
4    pub(crate) fn assert_finite_f32(caller: &str, name: &str, value: f32) {
5        assert!(value.is_finite(), "{caller} {name} must be finite");
6    }
7
8    pub(super) fn assert_finite_vec2(caller: &str, name: &str, value: [f32; 2]) {
9        assert!(
10            value[0].is_finite() && value[1].is_finite(),
11            "{caller} {name} must contain finite values"
12        );
13    }
14
15    /// Creates a new Ui instance
16    ///
17    /// This should only be called by Context::create()
18    pub(crate) fn new(
19        ctx: *mut sys::ImGuiContext,
20        ctx_binding: crate::ContextBinding,
21        texture_registry: crate::context::SharedTextureRegistry,
22    ) -> Self {
23        Ui {
24            ctx,
25            ctx_binding,
26            texture_registry,
27            native_scopes: std::cell::RefCell::new(crate::scope::NativeScopeTracker::default()),
28            buffer: UnsafeCell::new(UiBuffer::new(1024)),
29        }
30    }
31
32    pub(crate) fn context_raw(&self) -> *mut sys::ImGuiContext {
33        self.ctx
34    }
35
36    /// Returns a persistent capability for the Context that owns this `Ui`.
37    pub fn binding(&self) -> crate::ContextBinding {
38        self.ctx_binding.clone()
39    }
40
41    /// Returns the process-unique identity of the Context that owns this `Ui`.
42    pub fn context_id(&self) -> crate::ContextId {
43        self.ctx_binding.id()
44    }
45
46    pub(crate) fn run_with_bound_context<R>(&self, f: impl FnOnce() -> R) -> R {
47        self.assert_native_scopes_usable();
48        self.ctx_binding.with_bound_context(f)
49    }
50
51    pub(crate) fn resolve_texture_ref(
52        &self,
53        texture: crate::texture::TextureRef<'_>,
54    ) -> Result<sys::ImTextureRef, crate::texture::ManagedTextureError> {
55        match texture.source() {
56            crate::texture::TextureSource::Legacy(id) => Ok(sys::ImTextureRef {
57                _TexData: std::ptr::null_mut(),
58                _TexID: sys::ImTextureID::from(id),
59            }),
60            crate::texture::TextureSource::Managed(id) => {
61                self.texture_registry.borrow().resolve(id)
62            }
63            crate::texture::TextureSource::FontAtlas { atlas, texture } => {
64                let io = unsafe { sys::igGetIO_ContextPtr(self.ctx) };
65                if io.is_null() || !std::ptr::eq(unsafe { (*io).Fonts }, atlas) {
66                    return Err(crate::texture::ManagedTextureError::ForeignFontAtlas);
67                }
68                Ok(texture)
69            }
70        }
71    }
72
73    /// Resolve a logical texture for an adjacent extension FFI call.
74    ///
75    /// # Safety
76    ///
77    /// A returned managed pointer is valid only for an immediate native call while this `Ui` and
78    /// its frame remain borrowed. It must not be stored, sent, or used after the call returns.
79    #[doc(hidden)]
80    pub unsafe fn resolve_texture_ref_raw(
81        &self,
82        texture: crate::texture::TextureRef<'_>,
83    ) -> Result<sys::ImTextureRef, crate::texture::ManagedTextureError> {
84        self.run_with_bound_context(|| self.resolve_texture_ref(texture))
85    }
86
87    /// Runs a closure while this `Ui`'s owning ImGui context is current.
88    ///
89    /// The previously current context is restored before this method returns,
90    /// including when the closure panics. This is primarily intended for
91    /// extension crates that need to call raw Dear ImGui-adjacent FFI while
92    /// still honoring the `Ui` that created the safe wrapper.
93    pub fn with_bound_context<R>(&self, f: impl FnOnce() -> R) -> R {
94        self.run_with_bound_context(f)
95    }
96
97    /// Returns an immutable reference to the inputs/outputs object
98    #[doc(alias = "GetIO")]
99    pub fn io(&self) -> &crate::io::Io {
100        self.run_with_bound_context(|| unsafe {
101            let io = sys::igGetIO_Nil();
102            if io.is_null() {
103                panic!("Ui::io() requires an active ImGui context");
104            }
105            &*(io as *const crate::io::Io)
106        })
107    }
108
109    /// Internal method to push a single text to our scratch buffer.
110    pub(crate) fn scratch_txt(&self, txt: impl AsRef<str>) -> *const std::os::raw::c_char {
111        unsafe {
112            let handle = &mut *self.buffer.get();
113            handle.scratch_txt(txt)
114        }
115    }
116
117    /// Stages an explicit text range with a readable NUL sentinel at its end.
118    pub(crate) fn scratch_txt_range(
119        &self,
120        txt: impl AsRef<str>,
121    ) -> std::ops::Range<*const std::os::raw::c_char> {
122        unsafe {
123            let handle = &mut *self.buffer.get();
124            handle.scratch_txt_range(txt)
125        }
126    }
127
128    /// Helper method for two strings
129    pub(crate) fn scratch_txt_two(
130        &self,
131        txt_0: impl AsRef<str>,
132        txt_1: impl AsRef<str>,
133    ) -> (*const std::os::raw::c_char, *const std::os::raw::c_char) {
134        unsafe {
135            let handle = &mut *self.buffer.get();
136            handle.scratch_txt_two(txt_0, txt_1)
137        }
138    }
139
140    /// Helper method with one optional value
141    pub(crate) fn scratch_txt_with_opt(
142        &self,
143        txt_0: impl AsRef<str>,
144        txt_1: Option<impl AsRef<str>>,
145    ) -> (*const std::os::raw::c_char, *const std::os::raw::c_char) {
146        unsafe {
147            let handle = &mut *self.buffer.get();
148            handle.scratch_txt_with_opt(txt_0, txt_1)
149        }
150    }
151
152    /// Get access to the scratch buffer for complex string operations
153    pub(crate) fn scratch_buffer(&self) -> &UnsafeCell<UiBuffer> {
154        &self.buffer
155    }
156
157    /// Returns an ID from a string label in the current ID scope.
158    ///
159    /// This mirrors `ImGui::GetID(label)`. Useful for building stable IDs
160    /// for widgets or dockspaces inside the current window/scope.
161    #[doc(alias = "GetID")]
162    pub fn get_id(&self, label: &str) -> Id {
163        let label = self.scratch_txt_range(label);
164        self.run_with_bound_context(|| unsafe {
165            Id::from(sys::igGetID_StrStr(label.start, label.end))
166        })
167    }
168}