dear_implot/context/
core.rs1use super::ui::PlotUi;
2use crate::sys;
3use dear_imgui_rs::{Context as ImGuiContext, Ui};
4use dear_imgui_sys as imgui_sys;
5
6pub struct PlotContext {
11 raw: *mut sys::ImPlotContext,
12 imgui_ctx_raw: *mut imgui_sys::ImGuiContext,
13 imgui_alive: Option<dear_imgui_rs::ContextAliveToken>,
14 owns_context: bool,
15}
16
17#[derive(Clone, Copy)]
18pub(crate) struct PlotContextBinding {
19 plot_ctx_raw: *mut sys::ImPlotContext,
20 imgui_ctx_raw: *mut imgui_sys::ImGuiContext,
21}
22
23#[must_use = "dropping the guard restores the previous Dear ImGui/ImPlot contexts"]
24pub(crate) struct PlotContextBindingGuard {
25 prev_imgui_ctx_raw: *mut imgui_sys::ImGuiContext,
26 prev_plot_ctx_raw: *mut sys::ImPlotContext,
27 restore_imgui: bool,
28 restore_plot: bool,
29}
30
31impl PlotContextBinding {
32 pub(crate) fn bind(&self, caller: &str) -> PlotContextBindingGuard {
33 assert!(
34 !self.imgui_ctx_raw.is_null(),
35 "{caller} requires an active ImGui context"
36 );
37 assert!(
38 !self.plot_ctx_raw.is_null(),
39 "{caller} requires an active ImPlot context"
40 );
41 let prev_imgui_ctx_raw = unsafe { imgui_sys::igGetCurrentContext() };
42 let prev_plot_ctx_raw = unsafe { sys::ImPlot_GetCurrentContext() };
43 let restore_imgui = prev_imgui_ctx_raw != self.imgui_ctx_raw;
44 let restore_plot = prev_plot_ctx_raw != self.plot_ctx_raw;
45 unsafe {
46 if restore_imgui {
47 imgui_sys::igSetCurrentContext(self.imgui_ctx_raw);
48 }
49 sys::ImPlot_SetImGuiContext(self.imgui_ctx_raw);
50 sys::ImPlot_SetCurrentContext(self.plot_ctx_raw);
51 }
52 PlotContextBindingGuard {
53 prev_imgui_ctx_raw,
54 prev_plot_ctx_raw,
55 restore_imgui,
56 restore_plot,
57 }
58 }
59}
60
61impl Drop for PlotContextBindingGuard {
62 fn drop(&mut self) {
63 unsafe {
64 if self.restore_plot {
65 sys::ImPlot_SetCurrentContext(self.prev_plot_ctx_raw);
66 }
67 if self.restore_imgui {
68 sys::ImPlot_SetImGuiContext(self.prev_imgui_ctx_raw);
69 imgui_sys::igSetCurrentContext(self.prev_imgui_ctx_raw);
70 }
71 }
72 }
73}
74
75impl PlotContext {
76 pub fn try_create(imgui_ctx: &ImGuiContext) -> dear_imgui_rs::ImGuiResult<Self> {
81 let imgui_ctx_raw = imgui_ctx.as_raw();
82 let imgui_alive = Some(imgui_ctx.alive_token());
83 let prev_imgui = unsafe { imgui_sys::igGetCurrentContext() };
84 let prev_plot = unsafe { sys::ImPlot_GetCurrentContext() };
85
86 unsafe {
90 if prev_imgui != imgui_ctx_raw {
91 imgui_sys::igSetCurrentContext(imgui_ctx_raw);
92 }
93 sys::ImPlot_SetImGuiContext(imgui_ctx_raw);
94 }
95
96 let raw = unsafe { sys::ImPlot_CreateContext() };
97 unsafe {
98 if sys::ImPlot_GetCurrentContext() != prev_plot {
99 sys::ImPlot_SetCurrentContext(prev_plot);
100 }
101 if prev_imgui != imgui_ctx_raw {
102 imgui_sys::igSetCurrentContext(prev_imgui);
103 }
104 }
105 if raw.is_null() {
106 return Err(dear_imgui_rs::ImGuiError::context_creation(
107 "ImPlot_CreateContext returned null",
108 ));
109 }
110
111 Ok(Self {
112 raw,
113 imgui_ctx_raw,
114 imgui_alive,
115 owns_context: true,
116 })
117 }
118
119 pub fn create(imgui_ctx: &ImGuiContext) -> Self {
121 Self::try_create(imgui_ctx).expect("Failed to create ImPlot context")
122 }
123
124 pub(crate) fn assert_imgui_alive(&self) {
125 if let Some(alive) = &self.imgui_alive {
126 assert!(
127 alive.is_alive(),
128 "dear-implot: ImGui context has been dropped"
129 );
130 }
131 }
132
133 pub(crate) fn binding(&self) -> PlotContextBinding {
134 PlotContextBinding {
135 plot_ctx_raw: self.raw,
136 imgui_ctx_raw: self.imgui_ctx_raw,
137 }
138 }
139
140 pub(crate) fn imgui_alive_token(&self) -> Option<dear_imgui_rs::ContextAliveToken> {
141 self.imgui_alive.clone()
142 }
143
144 pub fn get_plot_ui<'ui>(&'ui self, ui: &'ui Ui) -> PlotUi<'ui> {
149 let ui_ctx_raw = ui.with_bound_context(|| unsafe { imgui_sys::igGetCurrentContext() });
150 assert_eq!(
151 ui_ctx_raw, self.imgui_ctx_raw,
152 "dear-implot: PlotContext::get_plot_ui() requires a Ui from the owning ImGui context"
153 );
154 PlotUi { context: self, ui }
155 }
156
157 pub unsafe fn raw(&self) -> *mut sys::ImPlotContext {
164 self.raw
165 }
166}
167
168impl Drop for PlotContext {
169 fn drop(&mut self) {
170 if !self.owns_context || self.raw.is_null() {
171 return;
172 }
173
174 if let Some(alive) = &self.imgui_alive {
175 if !alive.is_alive() {
176 return;
179 }
180 }
181
182 unsafe {
183 let prev_imgui = imgui_sys::igGetCurrentContext();
184 let prev_plot = sys::ImPlot_GetCurrentContext();
185 let restore_plot = if prev_plot == self.raw {
186 std::ptr::null_mut()
187 } else {
188 prev_plot
189 };
190 imgui_sys::igSetCurrentContext(self.imgui_ctx_raw);
191 sys::ImPlot_SetImGuiContext(self.imgui_ctx_raw);
192 sys::ImPlot_DestroyContext(self.raw);
193 sys::ImPlot_SetCurrentContext(restore_plot);
194 imgui_sys::igSetCurrentContext(prev_imgui);
195 }
196 }
197}
198
199