From ea960bd30ddd8b61ee2214748da75451b3916c39 Mon Sep 17 00:00:00 2001 From: 4bb4 <67376761+4bb4@users.noreply.github.com> Date: Sun, 11 Oct 2020 16:25:48 +0200 Subject: [PATCH] Linked context into things, adapted examples. --- implot-examples/examples/bar_plots.rs | 19 ++++++----- implot-examples/examples/line_plots.rs | 40 +++++++++++++---------- implot-examples/examples/scatter_plots.rs | 19 ++++++----- implot-examples/examples/text_plots.rs | 13 +++++--- src/context.rs | 13 +++++--- src/lib.rs | 33 +++++++++---------- src/plot.rs | 17 +++++----- 7 files changed, 85 insertions(+), 69 deletions(-) diff --git a/implot-examples/examples/bar_plots.rs b/implot-examples/examples/bar_plots.rs index 10c4147..df02f75 100644 --- a/implot-examples/examples/bar_plots.rs +++ b/implot-examples/examples/bar_plots.rs @@ -2,18 +2,18 @@ //! features of the libray, see the line_plots example. use imgui::{im_str, CollapsingHeader, Condition, Ui, Window}; -use implot::{Context, Plot, PlotBars}; +use implot::{Context, Plot, PlotBars, PlotUi}; mod support; -fn show_basic_vertical_plot(ui: &Ui) { +fn show_basic_vertical_plot(ui: &Ui, plot_ui: &PlotUi) { ui.text(im_str!("This header shows a simple vertical bar plot.")); let content_width = ui.window_content_region_width(); Plot::new("Vertical bar plot") // The size call could also be omitted, though the defaults don't consider window // width, which is why we're not doing so here. .size(content_width, 300.0) - .build(|| { + .build(plot_ui, || { // If this is called outside a plot build callback, the program will panic. let axis_positions = vec![0.2, 0.4, 0.6, 0.8]; let values = vec![0.1, 0.2, 0.3, 0.4]; @@ -23,14 +23,14 @@ fn show_basic_vertical_plot(ui: &Ui) { }); } -fn show_basic_horizontal_plot(ui: &Ui) { +fn show_basic_horizontal_plot(ui: &Ui, plot_ui: &PlotUi) { ui.text(im_str!("This header shows a simple horizontal bar plot.")); let content_width = ui.window_content_region_width(); Plot::new("Horizontal bar plot") // The size call could also be omitted, though the defaults don't consider window // width, which is why we're not doing so here. .size(content_width, 300.0) - .build(|| { + .build(plot_ui, || { // If this is called outside a plot build callback, the program will panic. let axis_positions = vec![0.2, 0.4, 0.6, 0.8]; let values = vec![0.1, 0.2, 0.3, 0.4]; @@ -44,8 +44,11 @@ fn show_basic_horizontal_plot(ui: &Ui) { fn main() { let system = support::init(file!()); let mut showing_demo = false; - let _plotcontext = Context::create(); // TODO(4bb4) use this as soon as things have been adapted + let plotcontext = Context::create(); system.main_loop(move |_, ui| { + // The context is moved into the closure after creation so plot_ui is valid. + let plot_ui = plotcontext.get_plot_ui(); + Window::new(im_str!("Bar plots example")) .size([430.0, 450.0], Condition::FirstUseEver) .build(ui, || { @@ -62,11 +65,11 @@ fn main() { // Show individual examples in collapsed headers if CollapsingHeader::new(im_str!("Basic vertical plot")).build(&ui) { - show_basic_vertical_plot(&ui); + show_basic_vertical_plot(&ui, &plot_ui); } if CollapsingHeader::new(im_str!("Basic horizontal plot")).build(&ui) { - show_basic_horizontal_plot(&ui); + show_basic_horizontal_plot(&ui, &plot_ui); } }); diff --git a/implot-examples/examples/line_plots.rs b/implot-examples/examples/line_plots.rs index b13a9f8..51d9b70 100644 --- a/implot-examples/examples/line_plots.rs +++ b/implot-examples/examples/line_plots.rs @@ -6,12 +6,12 @@ use implot::{ get_plot_limits, get_plot_mouse_position, get_plot_query, is_plot_hovered, is_plot_queried, push_style_color, push_style_var_f32, push_style_var_i32, set_colormap_from_preset, set_colormap_from_vec, AxisFlags, Colormap, Context, ImPlotLimits, ImPlotPoint, ImPlotRange, - ImVec4, Marker, Plot, PlotColorElement, PlotFlags, PlotLine, StyleVar, + ImVec4, Marker, Plot, PlotColorElement, PlotFlags, PlotLine, PlotUi, StyleVar, }; mod support; -fn show_basic_plot(ui: &Ui) { +fn show_basic_plot(ui: &Ui, plot_ui: &PlotUi) { ui.text(im_str!( "This header just plots a line with as little code as possible." )); @@ -20,7 +20,7 @@ fn show_basic_plot(ui: &Ui) { // The size call could also be omitted, though the defaults don't consider window // width, which is why we're not doing so here. .size(content_width, 300.0) - .build(|| { + .build(plot_ui, || { // If this is called outside a plot build callback, the program will panic. let x_positions = vec![0.1, 0.9]; let y_positions = vec![0.1, 0.9]; @@ -28,7 +28,7 @@ fn show_basic_plot(ui: &Ui) { }); } -fn show_configurable_plot(ui: &Ui) { +fn show_configurable_plot(ui: &Ui, plot_ui: &PlotUi) { ui.text(im_str!( "This header demos what we can configure about plots." )); @@ -87,12 +87,12 @@ fn show_configurable_plot(ui: &Ui) { .with_plot_flags(&plot_flags) .with_x_axis_flags(&x_axis_flags) .with_y_axis_flags(&y_axis_flags) - .build(|| { + .build(plot_ui, || { PlotLine::new("A line").plot(&vec![2.1, 2.9], &vec![1.1, 1.9]); }); } -fn show_query_features_plot(ui: &Ui) { +fn show_query_features_plot(ui: &Ui, plot_ui: &PlotUi) { ui.text(im_str!( "This header demos how to use the querying features." )); @@ -108,7 +108,8 @@ fn show_query_features_plot(ui: &Ui) { .size(content_width, 300.0) .x_limits(&ImPlotRange { Min: 0.0, Max: 5.0 }, Condition::FirstUseEver) .y_limits(&ImPlotRange { Min: 0.0, Max: 5.0 }, Condition::FirstUseEver) - .build(|| { + .with_plot_flags(&(PlotFlags::NONE | PlotFlags::QUERY)) + .build(plot_ui, || { if is_plot_hovered() { hover_pos = Some(get_plot_mouse_position()); } @@ -133,7 +134,7 @@ fn show_query_features_plot(ui: &Ui) { } } -fn show_style_plot(ui: &Ui) { +fn show_style_plot(ui: &Ui, plot_ui: &PlotUi) { ui.text(im_str!( "This header demos how to use the styling features." )); @@ -156,7 +157,7 @@ fn show_style_plot(ui: &Ui) { ) .with_plot_flags(&(PlotFlags::NONE)) .with_y_axis_flags(&(AxisFlags::NONE)) - .build(|| { + .build(plot_ui, || { // Markers can be selected as shown here. The markers are internally represented // as an u32, hence this calling style. let markerchoice = push_style_var_i32(&StyleVar::Marker, Marker::Cross as i32); @@ -178,7 +179,7 @@ fn show_style_plot(ui: &Ui) { style.pop(); } -fn show_colormaps_plot(ui: &Ui) { +fn show_colormaps_plot(ui: &Ui, plot_ui: &PlotUi) { ui.text(im_str!("This header demos how to select colormaps.")); let content_width = ui.window_content_region_width(); @@ -190,7 +191,7 @@ fn show_colormaps_plot(ui: &Ui) { Plot::new("Colormap demo plot") .size(content_width, 300.0) - .build(|| { + .build(plot_ui, || { (1..10) .map(|x| x as f64 * 0.1) .map(|x| PlotLine::new(&format!("{:3.3}", x)).plot(&vec![0.1, 0.9], &vec![x, x])) @@ -217,7 +218,7 @@ fn show_colormaps_plot(ui: &Ui) { Plot::new("Colormap demo plot #2") .size(content_width, 300.0) - .build(|| { + .build(plot_ui, || { (1..10) .map(|x| x as f64 * 0.1) .map(|x| PlotLine::new(&format!("{:3.3}", x)).plot(&vec![0.1, 0.9], &vec![x, x])) @@ -232,8 +233,11 @@ fn show_colormaps_plot(ui: &Ui) { fn main() { let system = support::init(file!()); let mut showing_demo = false; - let _plotcontext = Context::create(); // TODO(4bb4) use this as soon as things have been adapted + let plotcontext = Context::create(); system.main_loop(move |_, ui| { + // The context is moved into the closure after creation so plot_ui is valid. + let plot_ui = plotcontext.get_plot_ui(); + Window::new(im_str!("Line plots example")) .size([430.0, 450.0], Condition::FirstUseEver) .build(ui, || { @@ -250,19 +254,19 @@ fn main() { // Show individual examples in collapsed headers if CollapsingHeader::new(im_str!("Basic lineplot")).build(&ui) { - show_basic_plot(&ui); + show_basic_plot(&ui, &plot_ui); } if CollapsingHeader::new(im_str!("Configurable lineplot")).build(&ui) { - show_configurable_plot(&ui); + show_configurable_plot(&ui, &plot_ui); } if CollapsingHeader::new(im_str!("Querying a plot")).build(&ui) { - show_query_features_plot(&ui); + show_query_features_plot(&ui, &plot_ui); } if CollapsingHeader::new(im_str!("Styling a plot")).build(&ui) { - show_style_plot(&ui); + show_style_plot(&ui, &plot_ui); } if CollapsingHeader::new(im_str!("Colormap selection")).build(&ui) { - show_colormaps_plot(&ui); + show_colormaps_plot(&ui, &plot_ui); } }); diff --git a/implot-examples/examples/scatter_plots.rs b/implot-examples/examples/scatter_plots.rs index 0d7f2ec..ea32711 100644 --- a/implot-examples/examples/scatter_plots.rs +++ b/implot-examples/examples/scatter_plots.rs @@ -3,12 +3,12 @@ use imgui::{im_str, CollapsingHeader, Condition, Ui, Window}; use implot::{ - push_style_var_f32, push_style_var_i32, Context, Marker, Plot, PlotScatter, StyleVar, + push_style_var_f32, push_style_var_i32, Context, Marker, Plot, PlotScatter, PlotUi, StyleVar, }; mod support; -fn show_basic_plot(ui: &Ui) { +fn show_basic_plot(ui: &Ui, plot_ui: &PlotUi) { ui.text(im_str!( "This header just draws a scatter plot with as little code as possible." )); @@ -17,7 +17,7 @@ fn show_basic_plot(ui: &Ui) { // The size call could also be omitted, though the defaults don't consider window // width, which is why we're not doing so here. .size(content_width, 300.0) - .build(|| { + .build(plot_ui, || { // If this is called outside a plot build callback, the program will panic. let x_positions = vec![0.1, 0.2, 0.1, 0.5, 0.9]; let y_positions = vec![0.1, 0.1, 0.3, 0.3, 0.9]; @@ -25,7 +25,7 @@ fn show_basic_plot(ui: &Ui) { }); } -fn show_custom_markers_plot(ui: &Ui) { +fn show_custom_markers_plot(ui: &Ui, plot_ui: &PlotUi) { ui.text(im_str!( "This header shows how markers can be used in scatter plots." )); @@ -34,7 +34,7 @@ fn show_custom_markers_plot(ui: &Ui) { // The size call could also be omitted, though the defaults don't consider window // width, which is why we're not doing so here. .size(content_width, 300.0) - .build(|| { + .build(plot_ui, || { // Change to cross marker for one scatter plot call let x_positions = vec![0.1, 0.2, 0.1, 0.5, 0.9]; let y_positions = vec![0.1, 0.1, 0.3, 0.3, 0.9]; @@ -59,8 +59,11 @@ fn show_custom_markers_plot(ui: &Ui) { fn main() { let system = support::init(file!()); let mut showing_demo = false; - let _plotcontext = Context::create(); // TODO(4bb4) use this as soon as things have been adapted + let plotcontext = Context::create(); system.main_loop(move |_, ui| { + // The context is moved into the closure after creation so plot_ui is valid. + let plot_ui = plotcontext.get_plot_ui(); + Window::new(im_str!("Scatter plots example")) .size([430.0, 450.0], Condition::FirstUseEver) .build(ui, || { @@ -77,11 +80,11 @@ fn main() { // Show individual examples in collapsed headers if CollapsingHeader::new(im_str!("Basic scatter plot")).build(&ui) { - show_basic_plot(&ui); + show_basic_plot(&ui, &plot_ui); } if CollapsingHeader::new(im_str!("Custom markers")).build(&ui) { - show_custom_markers_plot(&ui); + show_custom_markers_plot(&ui, &plot_ui); } }); diff --git a/implot-examples/examples/text_plots.rs b/implot-examples/examples/text_plots.rs index 41e9a19..e82a848 100644 --- a/implot-examples/examples/text_plots.rs +++ b/implot-examples/examples/text_plots.rs @@ -2,11 +2,11 @@ //! features of the libray, see the line_plots example. use imgui::{im_str, CollapsingHeader, Condition, Ui, Window}; -use implot::{Context, Plot, PlotText}; +use implot::{Context, Plot, PlotText, PlotUi}; mod support; -fn show_basic_plot(ui: &Ui) { +fn show_basic_plot(ui: &Ui, plot_ui: &PlotUi) { ui.text(im_str!( "This header just plots some text with as little code as possible." )); @@ -15,7 +15,7 @@ fn show_basic_plot(ui: &Ui) { // The size call could also be omitted, though the defaults don't consider window // width, which is why we're not doing so here. .size(content_width, 300.0) - .build(|| { + .build(plot_ui, || { // The text passed to "new" is what gets displayed. let x_position: f64 = 0.5; let y_position: f64 = 0.2; @@ -33,8 +33,11 @@ fn show_basic_plot(ui: &Ui) { fn main() { let system = support::init(file!()); let mut showing_demo = false; - let _plotcontext = Context::create(); // TODO(4bb4) use this as soon as things have been adapted + let plotcontext = Context::create(); system.main_loop(move |_, ui| { + // The context is moved into the closure after creation so plot_ui is valid. + let plot_ui = plotcontext.get_plot_ui(); + Window::new(im_str!("Text plots example")) .size([430.0, 450.0], Condition::FirstUseEver) .build(ui, || { @@ -51,7 +54,7 @@ fn main() { // Show individual examples in collapsed headers if CollapsingHeader::new(im_str!("Basic text plot")).build(&ui) { - show_basic_plot(&ui); + show_basic_plot(&ui, &plot_ui); } }); diff --git a/src/context.rs b/src/context.rs index d841407..7bc1f17 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1,5 +1,3 @@ -use parking_lot::ReentrantMutex; - // TODO(4bb4) Do this properly. // I already added a simple Context struct that can be created once and used as long as it is not // dropped here for initial tests - this is of course neither threadsafe nor otherwise safe to use @@ -22,6 +20,9 @@ use parking_lot::ReentrantMutex; // I think I'll call this PlotUi to mimmick imgui-rs' Ui. // - Think about what this means in terms of the stacks and things like is_plot_hovered() - // they should also only work when there is a context available. +use parking_lot::ReentrantMutex; + +use crate::PlotUi; /// An implot context. /// @@ -32,8 +33,7 @@ pub struct Context { } lazy_static! { - // This mutex needs to be used to guard all public functions that can affect the underlying - // ImPlot active context + // This mutex is used to guard any accesses to the context static ref CTX_MUTEX: ReentrantMutex<()> = ReentrantMutex::new(()); } @@ -57,6 +57,11 @@ impl Context { } Self { raw: ctx } } + + /// Get a "plot ui" struct, this will be used to build actual plots. + pub fn get_plot_ui(&self) -> PlotUi { + PlotUi { context: self } + } } impl Drop for Context { diff --git a/src/lib.rs b/src/lib.rs index d0c8124..16e8a04 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,23 +12,25 @@ pub extern crate implot_sys as sys; #[macro_use] extern crate lazy_static; -pub use sys::imgui::Condition; -// TODO(4bb4) facade-wrap these -pub use sys::{ImPlotLimits, ImPlotPoint, ImPlotRange, ImVec2, ImVec4}; +// TODO(4bb4) facade-wrap these? +pub use sys::{imgui::Condition, ImPlotLimits, ImPlotPoint, ImPlotRange, ImVec2, ImVec4}; -// Plot struct and associated enums -pub mod context; -pub mod plot; -pub mod plot_elements; +pub use self::context::*; +pub use self::plot::*; +pub use self::plot_elements::*; -pub use context::Context; -pub use plot::{AxisFlags, Plot, PlotFlags}; -pub use plot_elements::{PlotBars, PlotLine, PlotScatter, PlotText}; +mod context; +mod plot; +mod plot_elements; -// --- Enum definitions -------------------------------------------------------------------------- -// Things that are to be combined like flags are done using bitflags, and things that are meant -// as enumerations in the traditional sense are plain enums. +/// A temporary reference for building plots. This does not really do anything on its own at +/// this point, but it is used to enforce that a context is created and active for other features, +/// such as creating plots. +pub struct PlotUi<'ui> { + context: &'ui Context, +} +// --- Markers, color maps, style variables---------------------------------------------------- /// Markers, documentation copied from implot.h for convenience. #[repr(i32)] #[derive(Copy, Clone, Debug)] @@ -190,11 +192,6 @@ pub enum StyleVar { PlotMinSize = sys::ImPlotStyleVar__ImPlotStyleVar_PlotMinSize, } -// --- Context ----------------------------------------------------------------------------------- - -// --- Main plot structure ----------------------------------------------------------------------- - -// --- Color maps ----------------------------------------------------------------------------- /// Switch to one of the built-in preset colormaps. If samples is greater than 1, the map will be /// linearly resampled. pub fn set_colormap_from_preset(preset: Colormap, samples: u32) { diff --git a/src/plot.rs b/src/plot.rs index 6b7da06..a5c5477 100644 --- a/src/plot.rs +++ b/src/plot.rs @@ -8,6 +8,8 @@ pub use sys::imgui::Condition; use sys::imgui::{im_str, ImString}; pub use sys::{ImPlotLimits, ImPlotPoint, ImPlotRange, ImVec2, ImVec4}; +use crate::{Context, PlotUi}; + const DEFAULT_PLOT_SIZE_X: f32 = 400.0; const DEFAULT_PLOT_SIZE_Y: f32 = 400.0; @@ -375,7 +377,7 @@ impl Plot { /// /// For a convenient implementation of all this, use [`build()`](struct.Plot.html#method.build) /// instead. - pub fn begin(&self) -> Option { + pub fn begin(&self, plot_ui: &PlotUi) -> Option { self.maybe_set_axis_limits(); self.maybe_set_tick_labels(); @@ -398,8 +400,8 @@ impl Plot { if should_render { Some(PlotToken { + context: plot_ui.context, plot_title: self.title.clone(), - has_ended: false, }) } else { // In contrast with imgui windows, end() does not have to be @@ -412,8 +414,8 @@ impl Plot { /// /// Note: the closure is not called if ImPlot::BeginPlot() returned /// false - TODO(4bb4) figure out if this is if things are not rendered - pub fn build(self, f: F) { - if let Some(token) = self.begin() { + pub fn build(self, plot_ui: &PlotUi, f: F) { + if let Some(token) = self.begin(plot_ui) { f(); token.end() } @@ -422,23 +424,22 @@ impl Plot { /// Tracks a plot that must be ended by calling `.end()` pub struct PlotToken { + context: *const Context, /// For better error messages plot_title: String, - /// Whether end() has been called on this already or not - has_ended: bool, } impl PlotToken { /// End a previously begin()'ed plot. pub fn end(mut self) { - self.has_ended = true; + self.context = std::ptr::null(); unsafe { sys::ImPlot_EndPlot() }; } } impl Drop for PlotToken { fn drop(&mut self) { - if !self.has_ended && !std::thread::panicking() { + if !self.context.is_null() && !std::thread::panicking() { panic!( "Warning: A PlotToken for plot \"{}\" was not called end() on", self.plot_title