1use crate::{api::AddonApi, imgui};
2use std::{
3 fmt, mem, ptr,
4 sync::{Mutex, OnceLock},
5};
6
7#[cfg(feature = "panic")]
8use crate::panic::init_panic_hook;
9
10#[cfg(feature = "log")]
11use crate::logger::NexusLogger;
12
13static ADDON_API: OnceLock<&'static AddonApi> = OnceLock::new();
14
15static IMGUI_CTX: OnceLock<ContextWrapper> = OnceLock::new();
16
17thread_local! { static IMGUI_UI: imgui::Ui<'static> = imgui::Ui::from_ctx(&IMGUI_CTX.get().expect("imgui context not initialized").0); }
18
19pub unsafe fn init(
27 api: *const AddonApi,
28 addon_name: &'static str,
29 _log_filter: Option<&'static str>,
30) {
31 let api = unsafe { api.as_ref() }.expect("no addon api supplied");
32 ADDON_API
33 .set(api)
34 .expect("addon api initialized multiple times");
35
36 #[cfg(feature = "panic")]
38 init_panic_hook(addon_name);
39
40 #[cfg(feature = "log")]
42 NexusLogger::set_logger(addon_name, _log_filter);
43
44 unsafe {
46 imgui::sys::igSetCurrentContext(api.imgui_context);
47 imgui::sys::igSetAllocatorFunctions(api.imgui_malloc, api.imgui_free, ptr::null_mut());
48 }
49 IMGUI_CTX
50 .set(imgui::Context::current().into())
51 .expect("imgui context initialized multiple times");
52}
53
54static UNLOAD_ACTIONS: Mutex<Vec<Box<dyn FnOnce() + Send>>> = Mutex::new(Vec::new());
56
57#[inline]
59pub fn on_unload(action: impl FnOnce() + Send + 'static) {
60 UNLOAD_ACTIONS.lock().unwrap().push(Box::new(action));
61}
62
63pub unsafe fn deinit() {
70 let mut guard = UNLOAD_ACTIONS.lock().unwrap();
72 let vec: Vec<_> = mem::take(&mut guard);
73 for action in vec {
74 action();
75 }
76}
77
78#[inline]
82pub fn addon_api() -> &'static AddonApi {
83 ADDON_API.get().expect("addon api not initialized")
84}
85
86#[inline]
91pub unsafe fn with_ui<R>(body: impl FnOnce(&imgui::Ui<'static>) -> R) -> R {
92 IMGUI_UI.with(body)
93}
94
95#[repr(transparent)]
97struct ContextWrapper(pub imgui::Context);
98
99impl From<imgui::Context> for ContextWrapper {
100 #[inline]
101 fn from(ctx: imgui::Context) -> Self {
102 Self(ctx)
103 }
104}
105
106impl fmt::Debug for ContextWrapper {
107 #[inline]
108 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
109 self.0.fmt(f)
110 }
111}
112
113unsafe impl Send for ContextWrapper {}
114
115unsafe impl Sync for ContextWrapper {}