dear_implot/context/
core.rs1use super::ui::PlotUi;
2use crate::sys;
3use dear_imgui_rs::{Context as ImGuiContext, ContextBinding, ContextBindingError, Ui};
4
5pub struct PlotContext {
10 raw: *mut sys::ImPlotContext,
11 imgui_binding: ContextBinding,
12 owns_context: bool,
13}
14
15#[derive(Clone)]
16pub(crate) struct PlotContextBinding {
17 plot_ctx_raw: *mut sys::ImPlotContext,
18 imgui_binding: ContextBinding,
19}
20
21#[must_use = "dropping the guard restores the previous ImPlot context"]
22struct PlotContextGuard {
23 prev_plot_ctx_raw: *mut sys::ImPlotContext,
24 restore_plot: bool,
25}
26
27impl PlotContextBinding {
28 pub(crate) fn with_bound_context<R>(&self, caller: &str, f: impl FnOnce() -> R) -> R {
29 self.try_with_bound_context(f)
30 .unwrap_or_else(|error| panic!("{caller}: {error}"))
31 }
32
33 pub(crate) fn try_with_bound_context<R>(
34 &self,
35 f: impl FnOnce() -> R,
36 ) -> Result<R, ContextBindingError> {
37 self.imgui_binding.try_with_bound_context(|| {
38 let _guard = PlotContextGuard::bind(self.plot_ctx_raw);
39 f()
40 })
41 }
42}
43
44impl PlotContextGuard {
45 fn bind(plot_ctx_raw: *mut sys::ImPlotContext) -> Self {
46 assert!(
47 !plot_ctx_raw.is_null(),
48 "dear-implot requires an active ImPlot context"
49 );
50 let prev_plot_ctx_raw = unsafe { sys::ImPlot_GetCurrentContext() };
51 let restore_plot = prev_plot_ctx_raw != plot_ctx_raw;
52 unsafe {
53 sys::ImPlot_SetCurrentContext(plot_ctx_raw);
54 }
55 Self {
56 prev_plot_ctx_raw,
57 restore_plot,
58 }
59 }
60}
61
62impl Drop for PlotContextGuard {
63 fn drop(&mut self) {
64 if self.restore_plot {
65 unsafe {
66 sys::ImPlot_SetCurrentContext(self.prev_plot_ctx_raw);
67 }
68 }
69 }
70}
71
72impl PlotContext {
73 pub fn try_create(imgui_ctx: &ImGuiContext) -> dear_imgui_rs::ImGuiResult<Self> {
78 let imgui_binding = imgui_ctx.binding();
79 let raw = imgui_binding.with_bound_context(|| unsafe {
80 let prev_plot = sys::ImPlot_GetCurrentContext();
81 let raw = sys::ImPlot_CreateContext();
82 if sys::ImPlot_GetCurrentContext() != prev_plot {
83 sys::ImPlot_SetCurrentContext(prev_plot);
84 }
85 raw
86 });
87 if raw.is_null() {
88 return Err(dear_imgui_rs::ImGuiError::context_creation(
89 "ImPlot_CreateContext returned null",
90 ));
91 }
92
93 Ok(Self {
94 raw,
95 imgui_binding,
96 owns_context: true,
97 })
98 }
99
100 pub fn create(imgui_ctx: &ImGuiContext) -> Self {
102 Self::try_create(imgui_ctx).expect("Failed to create ImPlot context")
103 }
104
105 pub(crate) fn binding(&self) -> PlotContextBinding {
106 PlotContextBinding {
107 plot_ctx_raw: self.raw,
108 imgui_binding: self.imgui_binding.clone(),
109 }
110 }
111
112 pub fn get_plot_ui<'ui>(&'ui self, ui: &'ui Ui) -> PlotUi<'ui> {
117 assert_eq!(
118 ui.context_id(),
119 self.imgui_binding.id(),
120 "dear-implot: PlotContext::get_plot_ui() requires a Ui from the owning ImGui context"
121 );
122 PlotUi { context: self, ui }
123 }
124
125 pub unsafe fn raw(&self) -> *mut sys::ImPlotContext {
132 self.raw
133 }
134}
135
136impl Drop for PlotContext {
137 fn drop(&mut self) {
138 if !self.owns_context || self.raw.is_null() {
139 return;
140 }
141
142 let _ = self.imgui_binding.try_with_bound_context(|| unsafe {
143 let prev_plot = sys::ImPlot_GetCurrentContext();
144 let restore_plot = if prev_plot == self.raw {
145 std::ptr::null_mut()
146 } else {
147 prev_plot
148 };
149 sys::ImPlot_DestroyContext(self.raw);
150 sys::ImPlot_SetCurrentContext(restore_plot);
151 });
152 }
153}
154
155