From 4401d696b104bb0d1390813dd995a1626955d6a4 Mon Sep 17 00:00:00 2001 From: 4bb4 <67376761+4bb4@users.noreply.github.com> Date: Sun, 3 Oct 2021 12:26:08 +0200 Subject: [PATCH] Removed im_str and ImString usage --- .../examples-shared/src/bar_plots.rs | 14 +-- .../examples-shared/src/heatmaps.rs | 8 +- implot-examples/examples-shared/src/lib.rs | 32 +++-- .../examples-shared/src/line_plots.rs | 118 ++++++++---------- .../examples-shared/src/scatter_plots.rs | 18 ++- .../examples-shared/src/stairs_plots.rs | 10 +- .../examples-shared/src/stem_plots.rs | 8 +- .../examples-shared/src/text_plots.rs | 10 +- implot-examples/implot-glium-demo/src/main.rs | 17 ++- implot-examples/implot-wgpu-demo/src/main.rs | 17 ++- src/plot.rs | 88 +++++++++---- src/plot_elements.rs | 100 ++++++++++----- 12 files changed, 248 insertions(+), 192 deletions(-) diff --git a/implot-examples/examples-shared/src/bar_plots.rs b/implot-examples/examples-shared/src/bar_plots.rs index 6aab4c4..52ae000 100644 --- a/implot-examples/examples-shared/src/bar_plots.rs +++ b/implot-examples/examples-shared/src/bar_plots.rs @@ -1,11 +1,11 @@ //! This example demonstrates how bar plots are to be used. For more general //! features of the libray, see the line_plots example. -use imgui::{im_str, CollapsingHeader, Ui}; +use imgui::{CollapsingHeader, Ui}; use implot::{Plot, PlotBars, PlotUi}; pub fn show_basic_vertical_plot(ui: &Ui, plot_ui: &PlotUi) { - ui.text(im_str!("This header shows a simple vertical bar plot.")); + ui.text("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 @@ -22,7 +22,7 @@ pub fn show_basic_vertical_plot(ui: &Ui, plot_ui: &PlotUi) { } pub fn show_basic_horizontal_plot(ui: &Ui, plot_ui: &PlotUi) { - ui.text(im_str!("This header shows a simple horizontal bar plot.")); + ui.text("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 @@ -40,10 +40,10 @@ pub fn show_basic_horizontal_plot(ui: &Ui, plot_ui: &PlotUi) { } pub fn show_demo_headers(ui: &Ui, plot_ui: &PlotUi) { - if CollapsingHeader::new(im_str!("Bar plots: Basic vertical")).build(&ui) { - show_basic_vertical_plot(&ui, &plot_ui); + if CollapsingHeader::new("Bar plots: Basic vertical").build(ui) { + show_basic_vertical_plot(ui, plot_ui); } - if CollapsingHeader::new(im_str!("Bar plots: Basic horizontal")).build(&ui) { - show_basic_horizontal_plot(&ui, &plot_ui); + if CollapsingHeader::new("Bar plots: Basic horizontal").build(ui) { + show_basic_horizontal_plot(ui, plot_ui); } } diff --git a/implot-examples/examples-shared/src/heatmaps.rs b/implot-examples/examples-shared/src/heatmaps.rs index 665f0d8..5d528cc 100644 --- a/implot-examples/examples-shared/src/heatmaps.rs +++ b/implot-examples/examples-shared/src/heatmaps.rs @@ -1,11 +1,11 @@ //! This example demonstrates how heatmaps are to be used. For more general //! features of the libray, see the line_plots example. -use imgui::{im_str, CollapsingHeader, Ui}; +use imgui::{CollapsingHeader, Ui}; use implot::{ImPlotPoint, Plot, PlotHeatmap, PlotUi}; pub fn show_basic_heatmap(ui: &Ui, plot_ui: &PlotUi) { - ui.text(im_str!("This header shows a simple heatmap")); + ui.text("This header shows a simple heatmap"); let content_width = ui.window_content_region_width(); Plot::new("Heatmap plot") // The size call could also be omitted, though the defaults don't consider window @@ -25,7 +25,7 @@ pub fn show_basic_heatmap(ui: &Ui, plot_ui: &PlotUi) { } pub fn show_demo_headers(ui: &Ui, plot_ui: &PlotUi) { - if CollapsingHeader::new(im_str!("Heatmap: Basic")).build(&ui) { - show_basic_heatmap(&ui, &plot_ui); + if CollapsingHeader::new("Heatmap: Basic").build(ui) { + show_basic_heatmap(ui, plot_ui); } } diff --git a/implot-examples/examples-shared/src/lib.rs b/implot-examples/examples-shared/src/lib.rs index 9d61368..c0b6a5b 100644 --- a/implot-examples/examples-shared/src/lib.rs +++ b/implot-examples/examples-shared/src/lib.rs @@ -6,7 +6,7 @@ pub mod stairs_plots; mod stem_plots; pub mod text_plots; -use imgui::{im_str, Condition, Ui, Window}; +use imgui::{Condition, Ui, Window}; use implot::PlotUi; /// State of the demo code @@ -28,45 +28,51 @@ impl DemoState { // Most of the demos are currently still stateless, so the code here mostly just calls into // the modules. The line plots demo is stateful though. Things will be refactored soon to // make all the individual demos stateful to unify things more. - Window::new(im_str!("implot-rs demo")) + Window::new("implot-rs demo") .size([430.0, 450.0], Condition::FirstUseEver) .build(ui, || { - ui.text(im_str!("Hello from implot-rs!")); - ui.text_wrapped(im_str!( + ui.text("Hello from implot-rs!"); + ui.text_wrapped( "The headers here demo the plotting features of the library.\ Have a look at the example source code to see how they are implemented.\n\ Check out the demo from ImPlot itself first for instructions on how to\ - interact with ImPlot plots." - )); + interact with ImPlot plots.", + ); ui.separator(); - ui.text(im_str!("Bar plots:")); + ui.text("Bar plots:"); bar_plots::show_demo_headers(ui, plot_ui); ui.separator(); - ui.text(im_str!("Line plots:")); + ui.text("Line plots:"); // The line plots demo is stateful self.line_plots.show_demo_headers(ui, plot_ui); ui.separator(); - ui.text(im_str!("Scatter plots:")); + ui.text("Scatter plots:"); scatter_plots::show_demo_headers(ui, plot_ui); ui.separator(); - ui.text(im_str!("Text plots:")); + ui.text("Text plots:"); text_plots::show_demo_headers(ui, plot_ui); ui.separator(); - ui.text(im_str!("Stairs plots:")); + ui.text("Stairs plots:"); stairs_plots::show_demo_headers(ui, plot_ui); ui.separator(); - ui.text(im_str!("Heatmaps:")); + ui.text("Heatmaps:"); heatmaps::show_demo_headers(ui, plot_ui); ui.separator(); - ui.text(im_str!("Stem plots:")); + ui.text("Stem plots:"); stem_plots::show_demo_headers(ui, plot_ui); }); } } + +impl Default for DemoState { + fn default() -> Self { + Self::new() + } +} diff --git a/implot-examples/examples-shared/src/line_plots.rs b/implot-examples/examples-shared/src/line_plots.rs index 978c2c3..7acd76b 100644 --- a/implot-examples/examples-shared/src/line_plots.rs +++ b/implot-examples/examples-shared/src/line_plots.rs @@ -1,7 +1,7 @@ //! This example demonstrates how line plots are to be used, along with some querying features //! that will be applicable to all kinds of plots. -use imgui::{im_str, CollapsingHeader, Condition, Ui}; +use imgui::{CollapsingHeader, Condition, Ui}; use implot::{ get_plot_limits, get_plot_mouse_position, get_plot_query, is_legend_entry_hovered, is_plot_hovered, is_plot_queried, pixels_to_plot_vec2, plot_to_pixels_vec2, push_style_color, @@ -27,9 +27,7 @@ impl LinePlotDemoState { } pub 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." - )); + ui.text("This header just plots a line with as little code as possible."); let content_width = ui.window_content_region_width(); Plot::new("Simple line plot") // The size call could also be omitted, though the defaults don't consider window @@ -44,9 +42,7 @@ impl LinePlotDemoState { } pub fn show_two_yaxis_plot(ui: &Ui, plot_ui: &PlotUi) { - ui.text(im_str!( - "This header shows how to create a plot with multiple Y axes." - )); + ui.text("This header shows how to create a plot with multiple Y axes."); let content_width = ui.window_content_region_width(); Plot::new("Multiple Y axis plots") // The size call could also be omitted, though the defaults don't consider window @@ -79,7 +75,7 @@ impl LinePlotDemoState { } pub fn show_axis_equal_plot(ui: &Ui, plot_ui: &PlotUi) { - ui.text(im_str!("This plot has axis equal set (1:1 aspect ratio).")); + ui.text("This plot has axis equal set (1:1 aspect ratio)."); let content_width = ui.window_content_region_width(); Plot::new("Axis equal line plot") // The size call could also be omitted, though the defaults don't consider window @@ -95,9 +91,7 @@ impl LinePlotDemoState { } pub fn show_configurable_plot(ui: &Ui, plot_ui: &PlotUi) { - ui.text(im_str!( - "This header demos what we can configure about plots." - )); + ui.text("This header demos what we can configure about plots."); // Settings for the plot // - X and Y size in pixels @@ -127,8 +121,8 @@ impl LinePlotDemoState { // Axis labels Plot::new("Configured line plot") .size([x_size, y_size]) - .x_label(&x_label) - .y_label(&y_label) + .x_label(x_label) + .y_label(y_label) .x_limits( ImPlotRange { Min: x_min, @@ -156,14 +150,12 @@ impl LinePlotDemoState { .with_y_axis_flags(YAxisChoice::First, &y_axis_flags) .with_legend_location(&PlotLocation::West, &PlotOrientation::Horizontal, true) .build(plot_ui, || { - PlotLine::new("A line 2").plot(&vec![2.4, 2.9], &vec![1.1, 1.9]); + PlotLine::new("A line 2").plot(&[2.4, 2.9], &[1.1, 1.9]); }); } pub fn show_query_features_plot(ui: &Ui, plot_ui: &PlotUi) { - ui.text(im_str!( - "This header demos how to use the querying features." - )); + ui.text("This header demos how to use the querying features."); let content_width = ui.window_content_region_width(); // Create some containers for exfiltrating data from the closure below @@ -202,8 +194,8 @@ impl LinePlotDemoState { )); // Plot a line so we have a legend entry - PlotLine::new("Legend1").plot(&vec![2.0, 2.0], &vec![2.0, 1.0]); - PlotLine::new("Legend2").plot(&vec![0.0, 0.0], &vec![1.0, 1.0]); + PlotLine::new("Legend1").plot(&[2.0, 2.0], &[2.0, 1.0]); + PlotLine::new("Legend2").plot(&[0.0, 0.0], &[1.0, 1.0]); legend1_hovered = is_legend_entry_hovered("Legend1"); legend2_hovered = is_legend_entry_hovered("Legend2"); @@ -217,43 +209,39 @@ impl LinePlotDemoState { // things like is_plot_hovered or get_plot_mouse_position() outside // of an actual Plot is not allowed. if let Some(pos) = hover_pos_plot { - ui.text(im_str!("hovered at {}, {}", pos.x, pos.y)); + ui.text(format!("hovered at {}, {}", pos.x, pos.y)); } if let Some(pixel_position) = hover_pos_pixels { // Try out converting plot mouse position to pixel position - ui.text(im_str!( + ui.text(format!( "pixel pos from plot: {}, {}", - pixel_position.x, - pixel_position.y + pixel_position.x, pixel_position.y )); - ui.text(im_str!( + ui.text(format!( "pixel pos from imgui: {}, {}", ui.io().mouse_pos[0], ui.io().mouse_pos[1] )); } if let Some(limits) = plot_limits { - ui.text(im_str!("Plot limits are {:#?}", limits)); + ui.text(format!("Plot limits are {:#?}", limits)); } if let Some(query) = query_limits { - ui.text(im_str!("Query limits are {:#?}", query)); + ui.text(format!("Query limits are {:#?}", query)); } - ui.text(im_str!( + ui.text(format!( "Legend hovering - 1: {}, 2: {}", - legend1_hovered, - legend2_hovered + legend1_hovered, legend2_hovered )); // Try out converting pixel position to plot position if let Some(pos) = hover_pos_from_pixels { - ui.text(im_str!("plot pos from imgui: {}, {}", pos.x, pos.y,)); + ui.text(format!("plot pos from imgui: {}, {}", pos.x, pos.y,)); } } pub fn show_style_plot(ui: &Ui, plot_ui: &PlotUi) { - ui.text(im_str!( - "This header demos how to use the styling features." - )); + ui.text("This header demos how to use the styling features."); let content_width = ui.window_content_region_width(); // The style stack works the same as for other imgui things - we can push @@ -278,14 +266,14 @@ impl LinePlotDemoState { // 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); - PlotLine::new("Left eye").plot(&vec![2.0, 2.0], &vec![2.0, 1.0]); + PlotLine::new("Left eye").plot(&[2.0, 2.0], &[2.0, 1.0]); // Calling pop() on the return value of the push above will undo the marker choice. markerchoice.pop(); // Line weights can be set the same way, along with some other things - see // the docs of StyleVar for more info. let lineweight = push_style_var_f32(&StyleVar::LineWeight, 5.0); - PlotLine::new("Right eye").plot(&vec![4.0, 4.0], &vec![2.0, 1.0]); + PlotLine::new("Right eye").plot(&[4.0, 4.0], &[2.0, 1.0]); lineweight.pop(); let x_values = vec![1.0, 2.0, 4.0, 5.0]; @@ -297,7 +285,7 @@ impl LinePlotDemoState { } pub fn show_colormaps_plot(ui: &Ui, plot_ui: &PlotUi) { - ui.text(im_str!("This header demos how to select colormaps.")); + ui.text("This header demos how to select colormaps."); let content_width = ui.window_content_region_width(); // Select a colormap from the presets. The presets are listed in the Colormap enum @@ -311,9 +299,7 @@ impl LinePlotDemoState { .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]) - }) + .map(|x| PlotLine::new(&format!("{:3.3}", x)).plot(&[0.1, 0.9], &[x, x])) .count(); }); @@ -340,9 +326,7 @@ impl LinePlotDemoState { .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]) - }) + .map(|x| PlotLine::new(&format!("{:3.3}", x)).plot(&[0.1, 0.9], &[x, x])) .count(); }); @@ -352,9 +336,7 @@ impl LinePlotDemoState { } pub fn show_conversions_plot(ui: &Ui, plot_ui: &PlotUi) { - ui.text(im_str!( - "This header demonstrates (in code) how to convert various ranges into ImRange" - )); + ui.text("This header demonstrates (in code) how to convert various ranges into ImRange"); let content_width = ui.window_content_region_width(); Plot::new("Simple line plot, conversion 1") .size([content_width, 300.0]) @@ -369,9 +351,7 @@ impl LinePlotDemoState { } pub fn show_linked_x_axis_plots(&mut self, ui: &Ui, plot_ui: &PlotUi) { - ui.text(im_str!( - "These plots have their X axes linked, but not the Y axes" - )); + ui.text("These plots have their X axes linked, but not the Y axes"); let content_width = ui.window_content_region_width(); Plot::new("Linked plot 1") .size([content_width, 300.0]) @@ -392,32 +372,38 @@ impl LinePlotDemoState { } pub fn show_demo_headers(&mut self, ui: &Ui, plot_ui: &PlotUi) { - if CollapsingHeader::new(im_str!("Line plot: Basic")).build(&ui) { - Self::show_basic_plot(&ui, &plot_ui); + if CollapsingHeader::new("Line plot: Basic").build(ui) { + Self::show_basic_plot(ui, plot_ui); } - if CollapsingHeader::new(im_str!("Line plot: Configured")).build(&ui) { - Self::show_configurable_plot(&ui, &plot_ui); + if CollapsingHeader::new("Line plot: Configured").build(ui) { + Self::show_configurable_plot(ui, plot_ui); } - if CollapsingHeader::new(im_str!("Line Plot: Plot queries")).build(&ui) { - Self::show_query_features_plot(&ui, &plot_ui); + if CollapsingHeader::new("Line Plot: Plot queries").build(ui) { + Self::show_query_features_plot(ui, plot_ui); } - if CollapsingHeader::new(im_str!("Line plot: Plot styling")).build(&ui) { - Self::show_style_plot(&ui, &plot_ui); + if CollapsingHeader::new("Line plot: Plot styling").build(ui) { + Self::show_style_plot(ui, plot_ui); } - if CollapsingHeader::new(im_str!("Line plot: Colormaps")).build(&ui) { - Self::show_colormaps_plot(&ui, &plot_ui); + if CollapsingHeader::new("Line plot: Colormaps").build(ui) { + Self::show_colormaps_plot(ui, plot_ui); } - if CollapsingHeader::new(im_str!("Line plot: Multiple Y Axes")).build(&ui) { - Self::show_two_yaxis_plot(&ui, &plot_ui); + if CollapsingHeader::new("Line plot: Multiple Y Axes").build(ui) { + Self::show_two_yaxis_plot(ui, plot_ui); } - if CollapsingHeader::new(im_str!("Line plot: \"Axis equal\"")).build(&ui) { - Self::show_axis_equal_plot(&ui, &plot_ui); + if CollapsingHeader::new("Line plot: \"Axis equal\"").build(ui) { + Self::show_axis_equal_plot(ui, plot_ui); } - if CollapsingHeader::new(im_str!("Line plot: Range conversions")).build(&ui) { - Self::show_conversions_plot(&ui, &plot_ui); + if CollapsingHeader::new("Line plot: Range conversions").build(ui) { + Self::show_conversions_plot(ui, plot_ui); } - if CollapsingHeader::new(im_str!("Line plot: Linked plots")).build(&ui) { - self.show_linked_x_axis_plots(&ui, &plot_ui); + if CollapsingHeader::new("Line plot: Linked plots").build(ui) { + self.show_linked_x_axis_plots(ui, plot_ui); } } } + +impl Default for LinePlotDemoState { + fn default() -> Self { + Self::new() + } +} diff --git a/implot-examples/examples-shared/src/scatter_plots.rs b/implot-examples/examples-shared/src/scatter_plots.rs index 43257f5..a05fa81 100644 --- a/implot-examples/examples-shared/src/scatter_plots.rs +++ b/implot-examples/examples-shared/src/scatter_plots.rs @@ -1,13 +1,11 @@ //! This example demonstrates how scatter plots are to be used. For more general //! features of the libray, see the line_plots example. -use imgui::{im_str, CollapsingHeader, Ui}; +use imgui::{CollapsingHeader, Ui}; use implot::{push_style_var_f32, push_style_var_i32, Marker, Plot, PlotScatter, PlotUi, StyleVar}; pub 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." - )); + ui.text("This header just draws a scatter plot with as little code as possible."); let content_width = ui.window_content_region_width(); Plot::new("Simple scatter plot") // The size call could also be omitted, though the defaults don't consider window @@ -22,9 +20,7 @@ pub fn show_basic_plot(ui: &Ui, plot_ui: &PlotUi) { } pub 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." - )); + ui.text("This header shows how markers can be used in scatter plots."); let content_width = ui.window_content_region_width(); Plot::new("Multi-marker scatter plot") // The size call could also be omitted, though the defaults don't consider window @@ -53,11 +49,11 @@ pub fn show_custom_markers_plot(ui: &Ui, plot_ui: &PlotUi) { } pub fn show_demo_headers(ui: &Ui, plot_ui: &PlotUi) { - if CollapsingHeader::new(im_str!("Basic scatter plot")).build(&ui) { - show_basic_plot(&ui, &plot_ui); + if CollapsingHeader::new("Basic scatter plot").build(ui) { + show_basic_plot(ui, plot_ui); } - if CollapsingHeader::new(im_str!("Custom markers")).build(&ui) { - show_custom_markers_plot(&ui, &plot_ui); + if CollapsingHeader::new("Custom markers").build(ui) { + show_custom_markers_plot(ui, plot_ui); } } diff --git a/implot-examples/examples-shared/src/stairs_plots.rs b/implot-examples/examples-shared/src/stairs_plots.rs index 0fc39d6..e8b400c 100644 --- a/implot-examples/examples-shared/src/stairs_plots.rs +++ b/implot-examples/examples-shared/src/stairs_plots.rs @@ -1,13 +1,11 @@ //! This example demonstrates how stairs plots are to be used. They are almost the same as line //! plots, so head over to the line plots example for more info. //! -use imgui::{im_str, CollapsingHeader, Ui}; +use imgui::{CollapsingHeader, Ui}; use implot::{Plot, PlotStairs, PlotUi}; pub fn show_basic_plot(ui: &Ui, plot_ui: &PlotUi) { - ui.text_wrapped(im_str!( - "This header just plots a stairs-style line with as little code as possible." - )); + ui.text_wrapped("This header just plots a stairs-style line with as little code as possible."); let content_width = ui.window_content_region_width(); Plot::new("Simple stairs plot") // The size call could also be omitted, though the defaults don't consider window @@ -22,7 +20,7 @@ pub fn show_basic_plot(ui: &Ui, plot_ui: &PlotUi) { } pub fn show_demo_headers(ui: &Ui, plot_ui: &PlotUi) { - if CollapsingHeader::new(im_str!("Stairs plot: Basic")).build(&ui) { - show_basic_plot(&ui, &plot_ui); + if CollapsingHeader::new("Stairs plot: Basic").build(ui) { + show_basic_plot(ui, plot_ui); } } diff --git a/implot-examples/examples-shared/src/stem_plots.rs b/implot-examples/examples-shared/src/stem_plots.rs index 23d9f97..c0472c1 100644 --- a/implot-examples/examples-shared/src/stem_plots.rs +++ b/implot-examples/examples-shared/src/stem_plots.rs @@ -1,11 +1,11 @@ //! This example demonstrates how stem plots are to be used. For more general //! features of the libray, see the line_plots example. -use imgui::{im_str, CollapsingHeader, Ui}; +use imgui::{CollapsingHeader, Ui}; use implot::{Plot, PlotStems, PlotUi}; pub fn show_basic_plot(ui: &Ui, plot_ui: &PlotUi) { - ui.text(im_str!("This header shows a simple stem plot.")); + ui.text("This header shows a simple stem plot."); let content_width = ui.window_content_region_width(); Plot::new("Stem plot") // The size call could also be omitted, though the defaults don't consider window @@ -22,7 +22,7 @@ pub fn show_basic_plot(ui: &Ui, plot_ui: &PlotUi) { } pub fn show_demo_headers(ui: &Ui, plot_ui: &PlotUi) { - if CollapsingHeader::new(im_str!("Stem plots")).build(&ui) { - show_basic_plot(&ui, &plot_ui); + if CollapsingHeader::new("Stem plots").build(ui) { + show_basic_plot(ui, plot_ui); } } diff --git a/implot-examples/examples-shared/src/text_plots.rs b/implot-examples/examples-shared/src/text_plots.rs index cc3e0d9..819a738 100644 --- a/implot-examples/examples-shared/src/text_plots.rs +++ b/implot-examples/examples-shared/src/text_plots.rs @@ -1,13 +1,11 @@ //! This example demonstrates how the text plotting features are to be used. For more general //! features of the libray, see the line_plots example. -use imgui::{im_str, CollapsingHeader, Ui}; +use imgui::{CollapsingHeader, Ui}; use implot::{Plot, PlotText, PlotUi}; pub 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." - )); + ui.text("This header just plots some text with as little code as possible."); let content_width = ui.window_content_region_width(); Plot::new("Simple text plot") // The size call could also be omitted, though the defaults don't consider window @@ -29,7 +27,7 @@ pub fn show_basic_plot(ui: &Ui, plot_ui: &PlotUi) { } pub fn show_demo_headers(ui: &Ui, plot_ui: &PlotUi) { - if CollapsingHeader::new(im_str!("Text plot: Basic")).build(&ui) { - show_basic_plot(&ui, &plot_ui); + if CollapsingHeader::new("Text plot: Basic").build(ui) { + show_basic_plot(ui, plot_ui); } } diff --git a/implot-examples/implot-glium-demo/src/main.rs b/implot-examples/implot-glium-demo/src/main.rs index 954624f..990fa9a 100644 --- a/implot-examples/implot-glium-demo/src/main.rs +++ b/implot-examples/implot-glium-demo/src/main.rs @@ -1,4 +1,4 @@ -use imgui::{im_str, Condition, Window}; +use imgui::{Condition, Window}; use implot::Context; // The actual backend-specific code is in this. @@ -22,23 +22,20 @@ fn main() { demo_state.show_demos(ui, &plot_ui); } - Window::new(im_str!("Welcome to the ImPlot-rs demo!")) + Window::new("Welcome to the ImPlot-rs demo!") .size([430.0, 450.0], Condition::FirstUseEver) .build(ui, || { - ui.checkbox(im_str!("Show C++ ImPlot demo window"), &mut showing_demo); - ui.checkbox( - im_str!("Show Rust ImPlot demo windows"), - &mut showing_rust_demo, - ); + ui.checkbox("Show C++ ImPlot demo window", &mut showing_demo); + ui.checkbox("Show Rust ImPlot demo windows", &mut showing_rust_demo); // TODO(4bb4) ... move windows by default so this is less confusing - ui.text_wrapped(im_str!( + ui.text_wrapped( "Note that the windows are stacked, so move this one out of the way to see\ the ones beneath it. If you see something in the C++ demo window, but not\ in the Rust ImPlot demo window, that means the bindings are likely not \ implemented yet. Feel free to open an issue if you are missing something \ in particular. - " - )); + ", + ); }); }); } diff --git a/implot-examples/implot-wgpu-demo/src/main.rs b/implot-examples/implot-wgpu-demo/src/main.rs index 954624f..990fa9a 100644 --- a/implot-examples/implot-wgpu-demo/src/main.rs +++ b/implot-examples/implot-wgpu-demo/src/main.rs @@ -1,4 +1,4 @@ -use imgui::{im_str, Condition, Window}; +use imgui::{Condition, Window}; use implot::Context; // The actual backend-specific code is in this. @@ -22,23 +22,20 @@ fn main() { demo_state.show_demos(ui, &plot_ui); } - Window::new(im_str!("Welcome to the ImPlot-rs demo!")) + Window::new("Welcome to the ImPlot-rs demo!") .size([430.0, 450.0], Condition::FirstUseEver) .build(ui, || { - ui.checkbox(im_str!("Show C++ ImPlot demo window"), &mut showing_demo); - ui.checkbox( - im_str!("Show Rust ImPlot demo windows"), - &mut showing_rust_demo, - ); + ui.checkbox("Show C++ ImPlot demo window", &mut showing_demo); + ui.checkbox("Show Rust ImPlot demo windows", &mut showing_rust_demo); // TODO(4bb4) ... move windows by default so this is less confusing - ui.text_wrapped(im_str!( + ui.text_wrapped( "Note that the windows are stacked, so move this one out of the way to see\ the ones beneath it. If you see something in the C++ demo window, but not\ in the Rust ImPlot demo window, that means the bindings are likely not \ implemented yet. Feel free to open an issue if you are missing something \ in particular. - " - )); + ", + ); }); }); } diff --git a/src/plot.rs b/src/plot.rs index c63aacf..ce48447 100644 --- a/src/plot.rs +++ b/src/plot.rs @@ -5,10 +5,10 @@ use crate::{Context, PlotLocation, PlotOrientation, PlotUi, YAxisChoice, NUMBER_OF_Y_AXES}; use bitflags::bitflags; pub use imgui::Condition; -use imgui::{im_str, ImString}; use implot_sys as sys; -use std::{cell::RefCell, rc::Rc}; +use std::ffi::CString; use std::os::raw::c_char; +use std::{cell::RefCell, rc::Rc}; pub use sys::{ImPlotLimits, ImPlotPoint, ImPlotRange, ImVec2, ImVec4}; const DEFAULT_PLOT_SIZE_X: f32 = 400.0; @@ -105,17 +105,17 @@ enum AxisLimitSpecification { /// (If you are coming from the C++ implementation or the C bindings: build() calls both /// begin() and end() internally) pub struct Plot { - /// Title of the plot, shown on top. Stored as ImString because that's what we'll use - /// afterwards, and this ensures the ImString itself will stay alive long enough for the plot. - title: ImString, + /// Title of the plot, shown on top. Stored as CString because that's what we'll use + /// afterwards, and this ensures the CString itself will stay alive long enough for the plot. + title: CString, /// Size of the plot in [x, y] direction, in the same units imgui uses. size: [f32; 2], - /// Label of the x axis, shown on the bottom. Stored as ImString because that's what we'll use - /// afterwards, and this ensures the ImString itself will stay alive long enough for the plot. - x_label: ImString, - /// Label of the y axis, shown on the left. Stored as ImString because that's what we'll use - /// afterwards, and this ensures the ImString itself will stay alive long enough for the plot. - y_label: ImString, + /// Label of the x axis, shown on the bottom. Stored as CString because that's what we'll use + /// afterwards, and this ensures the CString itself will stay alive long enough for the plot. + x_label: CString, + /// Label of the y axis, shown on the left. Stored as CString because that's what we'll use + /// afterwards, and this ensures the CString itself will stay alive long enough for the plot. + y_label: CString, /// X axis limits, if present x_limits: Option, /// Y axis limits, if present @@ -125,10 +125,10 @@ pub struct Plot { /// Labels for custom X axis ticks, if any. I'd prefer to store these together /// with the positions in one vector of an algebraic data type, but this would mean extra /// copies when it comes time to draw the plot because the C++ library expects separate lists. - /// The data is stored as ImStrings because those are null-terminated, and since we have to + /// The data is stored as CStrings because those are null-terminated, and since we have to /// convert to null-terminated data anyway, we may as well do that directly instead of cloning /// Strings and converting them afterwards. - x_tick_labels: Option>, + x_tick_labels: Option>, /// Whether to also show the default X ticks when showing custom ticks or not show_x_default_ticks: bool, /// Positions for custom Y axis ticks, if any @@ -136,10 +136,10 @@ pub struct Plot { /// Labels for custom Y axis ticks, if any. I'd prefer to store these together /// with the positions in one vector of an algebraic data type, but this would mean extra /// copies when it comes time to draw the plot because the C++ library expects separate lists. - /// The data is stored as ImStrings because those are null-terminated, and since we have to + /// The data is stored as CStrings because those are null-terminated, and since we have to /// convert to null-terminated data anyway, we may as well do that directly instead of cloning /// Strings and converting them afterwards. - y_tick_labels: [Option>; NUMBER_OF_Y_AXES], + y_tick_labels: [Option>; NUMBER_OF_Y_AXES], /// Whether to also show the default Y ticks when showing custom ticks or not show_y_default_ticks: [bool; NUMBER_OF_Y_AXES], /// Configuration for the legend, if specified. The tuple contains location, orientation @@ -158,18 +158,23 @@ pub struct Plot { impl Plot { /// Create a new plot with some defaults set. Does not draw anything yet. - /// Note that this uses antialiasing by default, unlike the C++ API. If you are seeing artifacts or weird rendering, try disabling it. + /// Note that this uses antialiasing by default, unlike the C++ API. If you are seeing + /// artifacts or weird rendering, try disabling it. + /// + /// # Panics + /// Will panic if the title string contains internal null bytes. pub fn new(title: &str) -> Self { // Needed for initialization, see https://github.com/rust-lang/rust/issues/49147 const POS_NONE: Option> = None; - const TICK_NONE: Option> = None; + const TICK_NONE: Option> = None; // TODO(4bb4) question these defaults, maybe remove some of them Self { - title: im_str!("{}", title), + title: CString::new(title) + .unwrap_or_else(|_| panic!("String contains internal null bytes: {}", title)), size: [DEFAULT_PLOT_SIZE_X, DEFAULT_PLOT_SIZE_Y], - x_label: im_str!("").into(), - y_label: im_str!("").into(), + x_label: CString::new("").unwrap(), + y_label: CString::new("").unwrap(), x_limits: None, y_limits: Default::default(), x_tick_positions: None, @@ -194,16 +199,24 @@ impl Plot { } /// Set the x label of the plot + /// + /// # Panics + /// Will panic if the label string contains internal null bytes. #[inline] pub fn x_label(mut self, label: &str) -> Self { - self.x_label = im_str!("{}", label); + self.x_label = CString::new(label) + .unwrap_or_else(|_| panic!("String contains internal null bytes: {}", label)); self } /// Set the y label of the plot + /// + /// # Panics + /// Will panic if the label string contains internal null bytes. #[inline] pub fn y_label(mut self, label: &str) -> Self { - self.y_label = im_str!("{}", label); + self.y_label = CString::new(label) + .unwrap_or_else(|_| panic!("String contains internal null bytes: {}", label)); self } @@ -338,6 +351,9 @@ impl Plot { /// Set X ticks with labels for the plot. The vector contains one position and label /// each in the form of a tuple `(label_position, label_string)`. The `show_default` /// setting determines whether the default ticks are also shown. + /// + /// # Panics + /// Will panic if any of the tick label strings contain internal null bytes. #[inline] pub fn x_ticks_with_labels( mut self, @@ -345,7 +361,15 @@ impl Plot { show_default: bool, ) -> Self { self.x_tick_positions = Some(tick_labels.iter().map(|x| x.0).collect()); - self.x_tick_labels = Some(tick_labels.iter().map(|x| im_str!("{}", x.1)).collect()); + self.x_tick_labels = Some( + tick_labels + .iter() + .map(|x| { + CString::new(x.1.as_str()) + .unwrap_or_else(|_| panic!("String contains internal null bytes: {}", x.1)) + }) + .collect(), + ); self.show_x_default_ticks = show_default; self } @@ -353,6 +377,9 @@ impl Plot { /// Set Y ticks with labels for the plot. The vector contains one position and label /// each in the form of a tuple `(label_position, label_string)`. The `show_default` /// setting determines whether the default ticks are also shown. + /// + /// # Panics + /// Will panic if any of the tick label strings contain internal null bytes. #[inline] pub fn y_ticks_with_labels( mut self, @@ -362,8 +389,15 @@ impl Plot { ) -> Self { let axis_index = y_axis_choice as usize; self.y_tick_positions[axis_index] = Some(tick_labels.iter().map(|x| x.0).collect()); - self.y_tick_labels[axis_index] = - Some(tick_labels.iter().map(|x| im_str!("{}", x.1)).collect()); + self.y_tick_labels[axis_index] = Some( + tick_labels + .iter() + .map(|x| { + CString::new(x.1.as_str()) + .unwrap_or_else(|_| panic!("String contains internal null bytes: {}", x.1)) + }) + .collect(), + ); self.show_y_default_ticks[axis_index] = show_default; self } @@ -618,7 +652,7 @@ impl Plot { pub struct PlotToken { context: *const Context, /// For better error messages - plot_title: ImString, + plot_title: CString, } impl PlotToken { @@ -634,7 +668,7 @@ impl Drop for PlotToken { fn drop(&mut self) { if !self.context.is_null() && !std::thread::panicking() { panic!( - "Warning: A PlotToken for plot \"{}\" was not called end() on", + "Warning: A PlotToken for plot \"{:?}\" was not called end() on", self.plot_title ); } diff --git a/src/plot_elements.rs b/src/plot_elements.rs index 5fedc8f..913d876 100644 --- a/src/plot_elements.rs +++ b/src/plot_elements.rs @@ -4,7 +4,7 @@ //! as lines, bars, scatter plots and text in a plot. For the module to create plots themselves, //! see `plot`. use crate::sys; -use imgui::{im_str, ImString}; +use std::ffi::CString; use std::os::raw::c_char; pub use crate::sys::ImPlotPoint; @@ -13,14 +13,18 @@ pub use crate::sys::ImPlotPoint; /// Struct to provide functionality for plotting a line in a plot. pub struct PlotLine { /// Label to show in the legend for this line - label: String, + label: CString, } impl PlotLine { /// Create a new line to be plotted. Does not draw anything yet. + /// + /// # Panics + /// Will panic if the label string contains internal null bytes. pub fn new(label: &str) -> Self { Self { - label: label.to_owned(), + label: CString::new(label) + .unwrap_or_else(|_| panic!("Label string has internal null bytes: {}", label)), } } @@ -32,7 +36,7 @@ impl PlotLine { } unsafe { sys::ImPlot_PlotLinedoublePtrdoublePtr( - im_str!("{}", self.label).as_ptr() as *const c_char, + self.label.as_ptr() as *const c_char, x.as_ptr(), y.as_ptr(), x.len().min(y.len()) as i32, // "as" casts saturate as of Rust 1.45. This is safe here. @@ -46,14 +50,18 @@ impl PlotLine { /// Struct to provide functionality for plotting a line in a plot with stairs style. pub struct PlotStairs { /// Label to show in the legend for this line - label: String, + label: CString, } impl PlotStairs { /// Create a new line to be plotted. Does not draw anything yet. + /// + /// # Panics + /// Will panic if the label string contains internal null bytes. pub fn new(label: &str) -> Self { Self { - label: label.to_owned(), + label: CString::new(label) + .unwrap_or_else(|_| panic!("Label string has internal null bytes: {}", label)), } } @@ -66,7 +74,7 @@ impl PlotStairs { } unsafe { sys::ImPlot_PlotStairsdoublePtrdoublePtr( - im_str!("{}", self.label).as_ptr() as *const c_char, + self.label.as_ptr() as *const c_char, x.as_ptr(), y.as_ptr(), x.len().min(y.len()) as i32, // "as" casts saturate as of Rust 1.45. This is safe here. @@ -80,14 +88,18 @@ impl PlotStairs { /// Struct to provide functionality for creating a scatter plot pub struct PlotScatter { /// Label to show in the legend for this scatter plot - label: String, + /// + /// # Panics + /// Will panic if the label string contains internal null bytes. + label: CString, } impl PlotScatter { /// Create a new scatter plot to be shown. Does not draw anything yet. pub fn new(label: &str) -> Self { Self { - label: label.to_owned(), + label: CString::new(label) + .unwrap_or_else(|_| panic!("Label string has internal null bytes: {}", label)), } } @@ -100,7 +112,7 @@ impl PlotScatter { } unsafe { sys::ImPlot_PlotScatterdoublePtrdoublePtr( - im_str!("{}", self.label).as_ptr() as *const c_char, + self.label.as_ptr() as *const c_char, x.as_ptr(), y.as_ptr(), x.len().min(y.len()) as i32, // "as" casts saturate as of Rust 1.45. This is safe here. @@ -114,7 +126,7 @@ impl PlotScatter { /// Struct to provide bar plotting functionality. pub struct PlotBars { /// Label to show in the legend for this line - label: String, + label: CString, /// Width of the bars, in plot coordinate terms bar_width: f64, @@ -126,9 +138,13 @@ pub struct PlotBars { impl PlotBars { /// Create a new bar plot to be shown. Defaults to drawing vertical bars. /// Does not draw anything yet. + /// + /// # Panics + /// Will panic if the label string contains internal null bytes. pub fn new(label: &str) -> Self { Self { - label: label.to_owned(), + label: CString::new(label) + .unwrap_or_else(|_| panic!("Label string has internal null bytes: {}", label)), bar_width: 0.67, // Default value taken from C++ implot horizontal_bars: false, } @@ -164,18 +180,34 @@ impl PlotBars { let (plot_function, x, y); if self.horizontal_bars { plot_function = sys::ImPlot_PlotBarsHdoublePtrdoublePtr - as unsafe extern "C" fn(*const c_char, *const f64, *const f64, i32, f64, i32, i32); + as unsafe extern "C" fn( + *const c_char, + *const f64, + *const f64, + i32, + f64, + i32, + i32, + ); x = bar_values; y = axis_positions; } else { plot_function = sys::ImPlot_PlotBarsdoublePtrdoublePtr - as unsafe extern "C" fn(*const c_char, *const f64, *const f64, i32, f64, i32, i32); + as unsafe extern "C" fn( + *const c_char, + *const f64, + *const f64, + i32, + f64, + i32, + i32, + ); x = axis_positions; y = bar_values; }; plot_function( - im_str!("{}", self.label).as_ptr() as *const c_char, + self.label.as_ptr() as *const c_char, x.as_ptr(), y.as_ptr(), number_of_points as i32, // "as" casts saturate as of Rust 1.45. This is safe here. @@ -190,7 +222,7 @@ impl PlotBars { /// Struct to provide functionality for adding text within a plot pub struct PlotText { /// Label to show in plot - label: String, + label: CString, /// X component of the pixel offset to be used. Will be used independently of the actual plot /// scaling. Defaults to 0. @@ -203,9 +235,13 @@ pub struct PlotText { impl PlotText { /// Create a new text label to be shown. Does not draw anything yet. + /// + /// # Panics + /// Will panic if the label string contains internal null bytes. pub fn new(label: &str) -> Self { Self { - label: label.into(), + label: CString::new(label) + .unwrap_or_else(|_| panic!("Label string has internal null bytes: {}", label)), pixel_offset_x: 0.0, pixel_offset_y: 0.0, } @@ -223,13 +259,13 @@ impl PlotText { /// closures passed to [`Plot::build()`](struct.Plot.html#method.build) pub fn plot(&self, x: f64, y: f64, vertical: bool) { // If there is nothing to show, don't do anything - if self.label.is_empty() { + if self.label.as_bytes().is_empty() { return; } unsafe { sys::ImPlot_PlotText( - im_str!("{}", self.label).as_ptr() as *const c_char, + self.label.as_ptr() as *const c_char, x, y, vertical, @@ -245,7 +281,7 @@ impl PlotText { /// Struct to provide functionality for creating headmaps. pub struct PlotHeatmap { /// Label to show in plot - label: String, + label: CString, /// Scale range of the values shown. If this is set to `None`, the scale /// is computed based on the values given to the `plot` function. If there @@ -255,7 +291,7 @@ pub struct PlotHeatmap { /// Label C style format string, this is shown when a a value point is hovered. /// None means don't show a label. The label is stored directly as an ImString because /// that is what's needed for the plot call anyway. Conversion is done in the setter. - label_format: Option, + label_format: Option, /// Lower left point for the bounding rectangle. This is called `bounds_min` in the C++ code. drawarea_lower_left: ImPlotPoint, @@ -271,9 +307,10 @@ impl PlotHeatmap { /// anything yet. pub fn new(label: &str) -> Self { Self { - label: label.to_owned(), + label: CString::new(label) + .unwrap_or_else(|_| panic!("Label string has internal null bytes: {}", label)), scale_range: None, - label_format: Some(im_str!("%.1f").to_owned()), + label_format: Some(CString::new("%.1f").unwrap()), drawarea_lower_left: ImPlotPoint { x: 0.0, y: 0.0 }, drawarea_upper_right: ImPlotPoint { x: 1.0, y: 1.0 }, } @@ -286,8 +323,14 @@ impl PlotHeatmap { } /// Specify the label format for hovered data points.. `None` means no label is shown. + /// + /// # Panics + /// Will panic if the label format string contains internal null bytes. pub fn with_label_format(mut self, label_format: Option<&str>) -> Self { - self.label_format = label_format.map(|x| im_str!("{}", x)); + self.label_format = label_format.map(|x| { + CString::new(x) + .unwrap_or_else(|_| panic!("Format label string has internal null bytes: {}", x)) + }); self } @@ -314,7 +357,7 @@ impl PlotHeatmap { unsafe { sys::ImPlot_PlotHeatmapdoublePtr( - im_str!("{}", self.label).as_ptr() as *const c_char, + self.label.as_ptr() as *const c_char, values.as_ptr(), number_of_rows as i32, // Not sure why C++ code uses a signed value here number_of_cols as i32, // Not sure why C++ code uses a signed value here @@ -337,7 +380,7 @@ impl PlotHeatmap { /// Struct to provide stem plotting functionality. pub struct PlotStems { /// Label to show in the legend for this line - label: String, + label: CString, /// Reference value for the y value, which the stems are "with respect to" reference_y: f64, @@ -348,7 +391,8 @@ impl PlotStems { /// [`PlotStems::plot`] on the struct for that. pub fn new(label: &str) -> Self { Self { - label: label.to_owned(), + label: CString::new(label) + .unwrap_or_else(|_| panic!("Label string has internal null bytes: {}", label)), reference_y: 0.0, // Default value taken from C++ implot } } @@ -370,7 +414,7 @@ impl PlotStems { } unsafe { sys::ImPlot_PlotStemsdoublePtrdoublePtr( - im_str!("{}", self.label).as_ptr() as *const c_char, + self.label.as_ptr() as *const c_char, axis_positions.as_ptr(), stem_values.as_ptr(), number_of_points as i32, // "as" casts saturate as of Rust 1.45. This is safe here.