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