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
23impl PlotContextBinding {
24 pub(crate) fn bind(self, caller: &str) {
25 assert!(
26 !self.imgui_ctx_raw.is_null(),
27 "{caller} requires an active ImGui context"
28 );
29 assert!(
30 !self.plot_ctx_raw.is_null(),
31 "{caller} requires an active ImPlot context"
32 );
33 assert_eq!(
34 unsafe { imgui_sys::igGetCurrentContext() },
35 self.imgui_ctx_raw,
36 "{caller} must be used with the currently-active ImGui context"
37 );
38 unsafe {
39 sys::ImPlot_SetImGuiContext(self.imgui_ctx_raw);
40 sys::ImPlot_SetCurrentContext(self.plot_ctx_raw);
41 }
42 }
43}
44
45impl PlotContext {
46 pub fn try_create(imgui_ctx: &ImGuiContext) -> dear_imgui_rs::ImGuiResult<Self> {
51 let imgui_ctx_raw = imgui_ctx.as_raw();
52 let imgui_alive = Some(imgui_ctx.alive_token());
53 assert_eq!(
54 unsafe { imgui_sys::igGetCurrentContext() },
55 imgui_ctx_raw,
56 "dear-implot: PlotContext must be created with the currently-active ImGui context"
57 );
58
59 unsafe { sys::ImPlot_SetImGuiContext(imgui_ctx_raw) };
63
64 let raw = unsafe { sys::ImPlot_CreateContext() };
65 if raw.is_null() {
66 return Err(dear_imgui_rs::ImGuiError::context_creation(
67 "ImPlot_CreateContext returned null",
68 ));
69 }
70
71 unsafe { sys::ImPlot_SetCurrentContext(raw) };
73
74 Ok(Self {
75 raw,
76 imgui_ctx_raw,
77 imgui_alive,
78 owns_context: true,
79 })
80 }
81
82 pub fn create(imgui_ctx: &ImGuiContext) -> Self {
84 Self::try_create(imgui_ctx).expect("Failed to create ImPlot context")
85 }
86
87 pub unsafe fn current() -> Option<Self> {
97 let raw = unsafe { sys::ImPlot_GetCurrentContext() };
98 if raw.is_null() {
99 None
100 } else {
101 Some(Self {
102 raw,
103 imgui_ctx_raw: unsafe { imgui_sys::igGetCurrentContext() },
104 imgui_alive: None,
105 owns_context: false,
106 })
107 }
108 }
109
110 pub fn set_as_current(&self) {
112 self.assert_imgui_alive();
113 self.binding().bind("dear-implot: PlotContext");
114 }
115
116 pub(crate) fn assert_imgui_alive(&self) {
117 if let Some(alive) = &self.imgui_alive {
118 assert!(
119 alive.is_alive(),
120 "dear-implot: ImGui context has been dropped"
121 );
122 }
123 }
124
125 pub(crate) fn binding(&self) -> PlotContextBinding {
126 PlotContextBinding {
127 plot_ctx_raw: self.raw,
128 imgui_ctx_raw: self.imgui_ctx_raw,
129 }
130 }
131
132 pub(crate) fn imgui_alive_token(&self) -> Option<dear_imgui_rs::ContextAliveToken> {
133 self.imgui_alive.clone()
134 }
135
136 pub fn get_plot_ui<'ui>(&'ui self, ui: &'ui Ui) -> PlotUi<'ui> {
141 self.set_as_current();
142 PlotUi { context: self, ui }
143 }
144
145 pub unsafe fn raw(&self) -> *mut sys::ImPlotContext {
152 self.raw
153 }
154}
155
156impl Drop for PlotContext {
157 fn drop(&mut self) {
158 if !self.owns_context || self.raw.is_null() {
159 return;
160 }
161
162 if let Some(alive) = &self.imgui_alive {
163 if !alive.is_alive() {
164 return;
167 }
168 }
169
170 unsafe {
171 let prev_imgui = imgui_sys::igGetCurrentContext();
172 imgui_sys::igSetCurrentContext(self.imgui_ctx_raw);
173 sys::ImPlot_SetImGuiContext(self.imgui_ctx_raw);
174
175 if sys::ImPlot_GetCurrentContext() == self.raw {
176 sys::ImPlot_SetCurrentContext(std::ptr::null_mut());
177 }
178 sys::ImPlot_DestroyContext(self.raw);
179
180 imgui_sys::igSetCurrentContext(prev_imgui);
181 }
182 }
183}
184
185