1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
//! Module for handling the ImPlot context. This is modeled quite directly after how
//! this is dealt with in imgui-rs, because it follows the same concepts and doing this
//! also helps readability if one is already familiar with the imgui code.

use parking_lot::ReentrantMutex;

use crate::sys;
use crate::PlotUi;
/// An implot context.
///
/// A context is required to do most of the things this library provides. While this was created
/// implicitly in earlier versions of the library, it is now created explicitly. These contexts
/// cannot currently be disabled through the high level API. This could be implemented though,
/// if you need multiple contexts that you can switch around between, file an issue.
#[rustversion::attr(since(1.48), doc(alias = "ImPlotContext"))]
pub struct Context {
    raw: *mut sys::ImPlotContext,
}

// This mutex is used to guard any accesses to the context
static CTX_MUTEX: ReentrantMutex<()> = parking_lot::const_reentrant_mutex(());

/// Check if there is no current context defined by calling into the C++ API
fn no_current_context() -> bool {
    let ctx = unsafe { sys::ImPlot_GetCurrentContext() };
    ctx.is_null()
}

impl Context {
    /// Create a context. This will also activate the context in ImPlot, and hence creating
    /// a second context when one already exists is an error and will panic.
    pub fn create() -> Self {
        let _guard = CTX_MUTEX.lock();
        assert!(
            no_current_context(),
            "A new active context cannot be created, because another one already exists"
        );

        let ctx = unsafe { sys::ImPlot_CreateContext() };
        unsafe {
            sys::ImPlot_SetCurrentContext(ctx);
        }
        Self { raw: ctx }
    }

    /// Get a "plot ui" struct, this will be used to build actual plots and is quite
    /// analogous to imgui-rs' "Ui" struct.
    pub fn get_plot_ui(&self) -> PlotUi {
        PlotUi { context: self }
    }

    /// Use light colors for the implot style.
    ///
    /// This will eventually be exposed more thoroughly in the form of ImPlotStyle,
    /// but for now this allows one to at least easily set the color preset.
    pub fn use_light_colors(&self) {
        unsafe {
            let style = sys::ImPlot_GetStyle();
            assert_ne!(style, std::ptr::null_mut());
            sys::ImPlot_StyleColorsLight(style);
        }
    }

    /// Use dark colors for the implot style.
    ///
    /// This will eventually be exposed more thoroughly in the form of ImPlotStyle,
    /// but for now this allows one to at least easily set the color preset.
    pub fn use_dark_colors(&self) {
        unsafe {
            let style = sys::ImPlot_GetStyle();
            assert_ne!(style, std::ptr::null_mut());
            sys::ImPlot_StyleColorsDark(style);
        }
    }

    /// Use classic colors for the implot style.
    ///
    /// This will eventually be exposed more thoroughly in the form of ImPlotStyle,
    /// but for now this allows one to at least easily set the color preset.
    pub fn use_classic_colors(&self) {
        unsafe {
            let style = sys::ImPlot_GetStyle();
            assert_ne!(style, std::ptr::null_mut());
            sys::ImPlot_StyleColorsClassic(style);
        }
    }
}

impl Drop for Context {
    fn drop(&mut self) {
        let _guard = CTX_MUTEX.lock();
        unsafe {
            sys::ImPlot_DestroyContext(self.raw);
        }
    }
}