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 = 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 imgui::sys::igSetCurrentContext(api.imgui_context);
46 imgui::sys::igSetAllocatorFunctions(api.imgui_malloc, api.imgui_free, ptr::null_mut());
47 IMGUI_CTX
48 .set(imgui::Context::current().into())
49 .expect("imgui context initialized multiple times");
50}
51
52static UNLOAD_ACTIONS: Mutex<Vec<Box<dyn FnOnce() + Send>>> = Mutex::new(Vec::new());
54
55#[inline]
57pub fn on_unload(action: impl FnOnce() + Send + 'static) {
58 UNLOAD_ACTIONS.lock().unwrap().push(Box::new(action));
59}
60
61pub unsafe fn deinit() {
68 let mut guard = UNLOAD_ACTIONS.lock().unwrap();
70 let vec: Vec<_> = mem::take(&mut guard);
71 for action in vec {
72 action();
73 }
74}
75
76#[inline]
80pub fn addon_api() -> &'static AddonApi {
81 ADDON_API.get().expect("addon api not initialized")
82}
83
84#[inline]
89pub unsafe fn with_ui<R>(body: impl FnOnce(&imgui::Ui<'static>) -> R) -> R {
90 IMGUI_UI.with(body)
91}
92
93#[repr(transparent)]
95struct ContextWrapper(pub imgui::Context);
96
97impl From<imgui::Context> for ContextWrapper {
98 #[inline]
99 fn from(ctx: imgui::Context) -> Self {
100 Self(ctx)
101 }
102}
103
104impl fmt::Debug for ContextWrapper {
105 #[inline]
106 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
107 self.0.fmt(f)
108 }
109}
110
111unsafe impl Send for ContextWrapper {}
112
113unsafe impl Sync for ContextWrapper {}