Removed im_str and ImString usage

This commit is contained in:
4bb4 2021-10-03 12:26:08 +02:00
parent f132811e93
commit 4401d696b1
12 changed files with 248 additions and 192 deletions

View file

@ -1,11 +1,11 @@
//! This example demonstrates how bar plots are to be used. For more general //! This example demonstrates how bar plots are to be used. For more general
//! features of the libray, see the line_plots example. //! features of the libray, see the line_plots example.
use imgui::{im_str, CollapsingHeader, Ui}; use imgui::{CollapsingHeader, Ui};
use implot::{Plot, PlotBars, PlotUi}; use implot::{Plot, PlotBars, PlotUi};
pub fn show_basic_vertical_plot(ui: &Ui, plot_ui: &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(); let content_width = ui.window_content_region_width();
Plot::new("Vertical bar plot") Plot::new("Vertical bar plot")
// The size call could also be omitted, though the defaults don't consider window // 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) { 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(); let content_width = ui.window_content_region_width();
Plot::new("Horizontal bar plot") Plot::new("Horizontal bar plot")
// The size call could also be omitted, though the defaults don't consider window // 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) { pub fn show_demo_headers(ui: &Ui, plot_ui: &PlotUi) {
if CollapsingHeader::new(im_str!("Bar plots: Basic vertical")).build(&ui) { if CollapsingHeader::new("Bar plots: Basic vertical").build(ui) {
show_basic_vertical_plot(&ui, &plot_ui); show_basic_vertical_plot(ui, plot_ui);
} }
if CollapsingHeader::new(im_str!("Bar plots: Basic horizontal")).build(&ui) { if CollapsingHeader::new("Bar plots: Basic horizontal").build(ui) {
show_basic_horizontal_plot(&ui, &plot_ui); show_basic_horizontal_plot(ui, plot_ui);
} }
} }

View file

@ -1,11 +1,11 @@
//! This example demonstrates how heatmaps are to be used. For more general //! This example demonstrates how heatmaps are to be used. For more general
//! features of the libray, see the line_plots example. //! 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}; use implot::{ImPlotPoint, Plot, PlotHeatmap, PlotUi};
pub fn show_basic_heatmap(ui: &Ui, plot_ui: &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(); let content_width = ui.window_content_region_width();
Plot::new("Heatmap plot") Plot::new("Heatmap plot")
// The size call could also be omitted, though the defaults don't consider window // 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) { pub fn show_demo_headers(ui: &Ui, plot_ui: &PlotUi) {
if CollapsingHeader::new(im_str!("Heatmap: Basic")).build(&ui) { if CollapsingHeader::new("Heatmap: Basic").build(ui) {
show_basic_heatmap(&ui, &plot_ui); show_basic_heatmap(ui, plot_ui);
} }
} }

View file

@ -6,7 +6,7 @@ pub mod stairs_plots;
mod stem_plots; mod stem_plots;
pub mod text_plots; pub mod text_plots;
use imgui::{im_str, Condition, Ui, Window}; use imgui::{Condition, Ui, Window};
use implot::PlotUi; use implot::PlotUi;
/// State of the demo code /// 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 // 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 // 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. // 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) .size([430.0, 450.0], Condition::FirstUseEver)
.build(ui, || { .build(ui, || {
ui.text(im_str!("Hello from implot-rs!")); ui.text("Hello from implot-rs!");
ui.text_wrapped(im_str!( ui.text_wrapped(
"The headers here demo the plotting features of the library.\ "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\ 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\ Check out the demo from ImPlot itself first for instructions on how to\
interact with ImPlot plots." interact with ImPlot plots.",
)); );
ui.separator(); ui.separator();
ui.text(im_str!("Bar plots:")); ui.text("Bar plots:");
bar_plots::show_demo_headers(ui, plot_ui); bar_plots::show_demo_headers(ui, plot_ui);
ui.separator(); ui.separator();
ui.text(im_str!("Line plots:")); ui.text("Line plots:");
// The line plots demo is stateful // The line plots demo is stateful
self.line_plots.show_demo_headers(ui, plot_ui); self.line_plots.show_demo_headers(ui, plot_ui);
ui.separator(); ui.separator();
ui.text(im_str!("Scatter plots:")); ui.text("Scatter plots:");
scatter_plots::show_demo_headers(ui, plot_ui); scatter_plots::show_demo_headers(ui, plot_ui);
ui.separator(); ui.separator();
ui.text(im_str!("Text plots:")); ui.text("Text plots:");
text_plots::show_demo_headers(ui, plot_ui); text_plots::show_demo_headers(ui, plot_ui);
ui.separator(); ui.separator();
ui.text(im_str!("Stairs plots:")); ui.text("Stairs plots:");
stairs_plots::show_demo_headers(ui, plot_ui); stairs_plots::show_demo_headers(ui, plot_ui);
ui.separator(); ui.separator();
ui.text(im_str!("Heatmaps:")); ui.text("Heatmaps:");
heatmaps::show_demo_headers(ui, plot_ui); heatmaps::show_demo_headers(ui, plot_ui);
ui.separator(); ui.separator();
ui.text(im_str!("Stem plots:")); ui.text("Stem plots:");
stem_plots::show_demo_headers(ui, plot_ui); stem_plots::show_demo_headers(ui, plot_ui);
}); });
} }
} }
impl Default for DemoState {
fn default() -> Self {
Self::new()
}
}

View file

@ -1,7 +1,7 @@
//! This example demonstrates how line plots are to be used, along with some querying features //! This example demonstrates how line plots are to be used, along with some querying features
//! that will be applicable to all kinds of plots. //! that will be applicable to all kinds of plots.
use imgui::{im_str, CollapsingHeader, Condition, Ui}; use imgui::{CollapsingHeader, Condition, Ui};
use implot::{ use implot::{
get_plot_limits, get_plot_mouse_position, get_plot_query, is_legend_entry_hovered, 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, 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) { pub fn show_basic_plot(ui: &Ui, plot_ui: &PlotUi) {
ui.text(im_str!( ui.text("This header just plots a line with as little code as possible.");
"This header just plots a line with as little code as possible."
));
let content_width = ui.window_content_region_width(); let content_width = ui.window_content_region_width();
Plot::new("Simple line plot") Plot::new("Simple line plot")
// The size call could also be omitted, though the defaults don't consider window // 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) { pub fn show_two_yaxis_plot(ui: &Ui, plot_ui: &PlotUi) {
ui.text(im_str!( ui.text("This header shows how to create a plot with multiple Y axes.");
"This header shows how to create a plot with multiple Y axes."
));
let content_width = ui.window_content_region_width(); let content_width = ui.window_content_region_width();
Plot::new("Multiple Y axis plots") Plot::new("Multiple Y axis plots")
// The size call could also be omitted, though the defaults don't consider window // 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) { 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(); let content_width = ui.window_content_region_width();
Plot::new("Axis equal line plot") Plot::new("Axis equal line plot")
// The size call could also be omitted, though the defaults don't consider window // 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) { pub fn show_configurable_plot(ui: &Ui, plot_ui: &PlotUi) {
ui.text(im_str!( ui.text("This header demos what we can configure about plots.");
"This header demos what we can configure about plots."
));
// Settings for the plot // Settings for the plot
// - X and Y size in pixels // - X and Y size in pixels
@ -127,8 +121,8 @@ impl LinePlotDemoState {
// Axis labels // Axis labels
Plot::new("Configured line plot") Plot::new("Configured line plot")
.size([x_size, y_size]) .size([x_size, y_size])
.x_label(&x_label) .x_label(x_label)
.y_label(&y_label) .y_label(y_label)
.x_limits( .x_limits(
ImPlotRange { ImPlotRange {
Min: x_min, Min: x_min,
@ -156,14 +150,12 @@ impl LinePlotDemoState {
.with_y_axis_flags(YAxisChoice::First, &y_axis_flags) .with_y_axis_flags(YAxisChoice::First, &y_axis_flags)
.with_legend_location(&PlotLocation::West, &PlotOrientation::Horizontal, true) .with_legend_location(&PlotLocation::West, &PlotOrientation::Horizontal, true)
.build(plot_ui, || { .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) { pub fn show_query_features_plot(ui: &Ui, plot_ui: &PlotUi) {
ui.text(im_str!( ui.text("This header demos how to use the querying features.");
"This header demos how to use the querying features."
));
let content_width = ui.window_content_region_width(); let content_width = ui.window_content_region_width();
// Create some containers for exfiltrating data from the closure below // 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 // 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("Legend1").plot(&[2.0, 2.0], &[2.0, 1.0]);
PlotLine::new("Legend2").plot(&vec![0.0, 0.0], &vec![1.0, 1.0]); PlotLine::new("Legend2").plot(&[0.0, 0.0], &[1.0, 1.0]);
legend1_hovered = is_legend_entry_hovered("Legend1"); legend1_hovered = is_legend_entry_hovered("Legend1");
legend2_hovered = is_legend_entry_hovered("Legend2"); legend2_hovered = is_legend_entry_hovered("Legend2");
@ -217,43 +209,39 @@ impl LinePlotDemoState {
// things like is_plot_hovered or get_plot_mouse_position() outside // things like is_plot_hovered or get_plot_mouse_position() outside
// of an actual Plot is not allowed. // of an actual Plot is not allowed.
if let Some(pos) = hover_pos_plot { 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 { if let Some(pixel_position) = hover_pos_pixels {
// Try out converting plot mouse position to pixel position // Try out converting plot mouse position to pixel position
ui.text(im_str!( ui.text(format!(
"pixel pos from plot: {}, {}", "pixel pos from plot: {}, {}",
pixel_position.x, pixel_position.x, pixel_position.y
pixel_position.y
)); ));
ui.text(im_str!( ui.text(format!(
"pixel pos from imgui: {}, {}", "pixel pos from imgui: {}, {}",
ui.io().mouse_pos[0], ui.io().mouse_pos[0],
ui.io().mouse_pos[1] ui.io().mouse_pos[1]
)); ));
} }
if let Some(limits) = plot_limits { 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 { 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: {}", "Legend hovering - 1: {}, 2: {}",
legend1_hovered, legend1_hovered, legend2_hovered
legend2_hovered
)); ));
// Try out converting pixel position to plot position // Try out converting pixel position to plot position
if let Some(pos) = hover_pos_from_pixels { 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) { pub fn show_style_plot(ui: &Ui, plot_ui: &PlotUi) {
ui.text(im_str!( ui.text("This header demos how to use the styling features.");
"This header demos how to use the styling features."
));
let content_width = ui.window_content_region_width(); let content_width = ui.window_content_region_width();
// The style stack works the same as for other imgui things - we can push // 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 // Markers can be selected as shown here. The markers are internally represented
// as an u32, hence this calling style. // as an u32, hence this calling style.
let markerchoice = push_style_var_i32(&StyleVar::Marker, Marker::Cross as i32); 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. // Calling pop() on the return value of the push above will undo the marker choice.
markerchoice.pop(); markerchoice.pop();
// Line weights can be set the same way, along with some other things - see // Line weights can be set the same way, along with some other things - see
// the docs of StyleVar for more info. // the docs of StyleVar for more info.
let lineweight = push_style_var_f32(&StyleVar::LineWeight, 5.0); 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(); lineweight.pop();
let x_values = vec![1.0, 2.0, 4.0, 5.0]; 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) { 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(); let content_width = ui.window_content_region_width();
// Select a colormap from the presets. The presets are listed in the Colormap enum // Select a colormap from the presets. The presets are listed in the Colormap enum
@ -311,9 +299,7 @@ impl LinePlotDemoState {
.build(plot_ui, || { .build(plot_ui, || {
(1..10) (1..10)
.map(|x| x as f64 * 0.1) .map(|x| x as f64 * 0.1)
.map(|x| { .map(|x| PlotLine::new(&format!("{:3.3}", x)).plot(&[0.1, 0.9], &[x, x]))
PlotLine::new(&format!("{:3.3}", x)).plot(&vec![0.1, 0.9], &vec![x, x])
})
.count(); .count();
}); });
@ -340,9 +326,7 @@ impl LinePlotDemoState {
.build(plot_ui, || { .build(plot_ui, || {
(1..10) (1..10)
.map(|x| x as f64 * 0.1) .map(|x| x as f64 * 0.1)
.map(|x| { .map(|x| PlotLine::new(&format!("{:3.3}", x)).plot(&[0.1, 0.9], &[x, x]))
PlotLine::new(&format!("{:3.3}", x)).plot(&vec![0.1, 0.9], &vec![x, x])
})
.count(); .count();
}); });
@ -352,9 +336,7 @@ impl LinePlotDemoState {
} }
pub fn show_conversions_plot(ui: &Ui, plot_ui: &PlotUi) { pub fn show_conversions_plot(ui: &Ui, plot_ui: &PlotUi) {
ui.text(im_str!( ui.text("This header demonstrates (in code) how to convert various ranges into ImRange");
"This header demonstrates (in code) how to convert various ranges into ImRange"
));
let content_width = ui.window_content_region_width(); let content_width = ui.window_content_region_width();
Plot::new("Simple line plot, conversion 1") Plot::new("Simple line plot, conversion 1")
.size([content_width, 300.0]) .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) { pub fn show_linked_x_axis_plots(&mut self, ui: &Ui, plot_ui: &PlotUi) {
ui.text(im_str!( ui.text("These plots have their X axes linked, but not the Y axes");
"These plots have their X axes linked, but not the Y axes"
));
let content_width = ui.window_content_region_width(); let content_width = ui.window_content_region_width();
Plot::new("Linked plot 1") Plot::new("Linked plot 1")
.size([content_width, 300.0]) .size([content_width, 300.0])
@ -392,32 +372,38 @@ impl LinePlotDemoState {
} }
pub fn show_demo_headers(&mut self, ui: &Ui, plot_ui: &PlotUi) { pub fn show_demo_headers(&mut self, ui: &Ui, plot_ui: &PlotUi) {
if CollapsingHeader::new(im_str!("Line plot: Basic")).build(&ui) { if CollapsingHeader::new("Line plot: Basic").build(ui) {
Self::show_basic_plot(&ui, &plot_ui); Self::show_basic_plot(ui, plot_ui);
} }
if CollapsingHeader::new(im_str!("Line plot: Configured")).build(&ui) { if CollapsingHeader::new("Line plot: Configured").build(ui) {
Self::show_configurable_plot(&ui, &plot_ui); Self::show_configurable_plot(ui, plot_ui);
} }
if CollapsingHeader::new(im_str!("Line Plot: Plot queries")).build(&ui) { if CollapsingHeader::new("Line Plot: Plot queries").build(ui) {
Self::show_query_features_plot(&ui, &plot_ui); Self::show_query_features_plot(ui, plot_ui);
} }
if CollapsingHeader::new(im_str!("Line plot: Plot styling")).build(&ui) { if CollapsingHeader::new("Line plot: Plot styling").build(ui) {
Self::show_style_plot(&ui, &plot_ui); Self::show_style_plot(ui, plot_ui);
} }
if CollapsingHeader::new(im_str!("Line plot: Colormaps")).build(&ui) { if CollapsingHeader::new("Line plot: Colormaps").build(ui) {
Self::show_colormaps_plot(&ui, &plot_ui); Self::show_colormaps_plot(ui, plot_ui);
} }
if CollapsingHeader::new(im_str!("Line plot: Multiple Y Axes")).build(&ui) { if CollapsingHeader::new("Line plot: Multiple Y Axes").build(ui) {
Self::show_two_yaxis_plot(&ui, &plot_ui); Self::show_two_yaxis_plot(ui, plot_ui);
} }
if CollapsingHeader::new(im_str!("Line plot: \"Axis equal\"")).build(&ui) { if CollapsingHeader::new("Line plot: \"Axis equal\"").build(ui) {
Self::show_axis_equal_plot(&ui, &plot_ui); Self::show_axis_equal_plot(ui, plot_ui);
} }
if CollapsingHeader::new(im_str!("Line plot: Range conversions")).build(&ui) { if CollapsingHeader::new("Line plot: Range conversions").build(ui) {
Self::show_conversions_plot(&ui, &plot_ui); Self::show_conversions_plot(ui, plot_ui);
} }
if CollapsingHeader::new(im_str!("Line plot: Linked plots")).build(&ui) { if CollapsingHeader::new("Line plot: Linked plots").build(ui) {
self.show_linked_x_axis_plots(&ui, &plot_ui); self.show_linked_x_axis_plots(ui, plot_ui);
} }
} }
} }
impl Default for LinePlotDemoState {
fn default() -> Self {
Self::new()
}
}

View file

@ -1,13 +1,11 @@
//! This example demonstrates how scatter plots are to be used. For more general //! This example demonstrates how scatter plots are to be used. For more general
//! features of the libray, see the line_plots example. //! 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}; 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) { pub fn show_basic_plot(ui: &Ui, plot_ui: &PlotUi) {
ui.text(im_str!( ui.text("This header just draws a scatter plot with as little code as possible.");
"This header just draws a scatter plot with as little code as possible."
));
let content_width = ui.window_content_region_width(); let content_width = ui.window_content_region_width();
Plot::new("Simple scatter plot") Plot::new("Simple scatter plot")
// The size call could also be omitted, though the defaults don't consider window // 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) { pub fn show_custom_markers_plot(ui: &Ui, plot_ui: &PlotUi) {
ui.text(im_str!( ui.text("This header shows how markers can be used in scatter plots.");
"This header shows how markers can be used in scatter plots."
));
let content_width = ui.window_content_region_width(); let content_width = ui.window_content_region_width();
Plot::new("Multi-marker scatter plot") Plot::new("Multi-marker scatter plot")
// The size call could also be omitted, though the defaults don't consider window // 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) { pub fn show_demo_headers(ui: &Ui, plot_ui: &PlotUi) {
if CollapsingHeader::new(im_str!("Basic scatter plot")).build(&ui) { if CollapsingHeader::new("Basic scatter plot").build(ui) {
show_basic_plot(&ui, &plot_ui); show_basic_plot(ui, plot_ui);
} }
if CollapsingHeader::new(im_str!("Custom markers")).build(&ui) { if CollapsingHeader::new("Custom markers").build(ui) {
show_custom_markers_plot(&ui, &plot_ui); show_custom_markers_plot(ui, plot_ui);
} }
} }

View file

@ -1,13 +1,11 @@
//! This example demonstrates how stairs plots are to be used. They are almost the same as line //! 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. //! 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}; use implot::{Plot, PlotStairs, PlotUi};
pub fn show_basic_plot(ui: &Ui, plot_ui: &PlotUi) { pub fn show_basic_plot(ui: &Ui, plot_ui: &PlotUi) {
ui.text_wrapped(im_str!( ui.text_wrapped("This header just plots a stairs-style line with as little code as possible.");
"This header just plots a stairs-style line with as little code as possible."
));
let content_width = ui.window_content_region_width(); let content_width = ui.window_content_region_width();
Plot::new("Simple stairs plot") Plot::new("Simple stairs plot")
// The size call could also be omitted, though the defaults don't consider window // 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) { pub fn show_demo_headers(ui: &Ui, plot_ui: &PlotUi) {
if CollapsingHeader::new(im_str!("Stairs plot: Basic")).build(&ui) { if CollapsingHeader::new("Stairs plot: Basic").build(ui) {
show_basic_plot(&ui, &plot_ui); show_basic_plot(ui, plot_ui);
} }
} }

View file

@ -1,11 +1,11 @@
//! This example demonstrates how stem plots are to be used. For more general //! This example demonstrates how stem plots are to be used. For more general
//! features of the libray, see the line_plots example. //! features of the libray, see the line_plots example.
use imgui::{im_str, CollapsingHeader, Ui}; use imgui::{CollapsingHeader, Ui};
use implot::{Plot, PlotStems, PlotUi}; use implot::{Plot, PlotStems, PlotUi};
pub fn show_basic_plot(ui: &Ui, plot_ui: &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(); let content_width = ui.window_content_region_width();
Plot::new("Stem plot") Plot::new("Stem plot")
// The size call could also be omitted, though the defaults don't consider window // 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) { pub fn show_demo_headers(ui: &Ui, plot_ui: &PlotUi) {
if CollapsingHeader::new(im_str!("Stem plots")).build(&ui) { if CollapsingHeader::new("Stem plots").build(ui) {
show_basic_plot(&ui, &plot_ui); show_basic_plot(ui, plot_ui);
} }
} }

View file

@ -1,13 +1,11 @@
//! This example demonstrates how the text plotting features are to be used. For more general //! This example demonstrates how the text plotting features are to be used. For more general
//! features of the libray, see the line_plots example. //! features of the libray, see the line_plots example.
use imgui::{im_str, CollapsingHeader, Ui}; use imgui::{CollapsingHeader, Ui};
use implot::{Plot, PlotText, PlotUi}; use implot::{Plot, PlotText, PlotUi};
pub fn show_basic_plot(ui: &Ui, plot_ui: &PlotUi) { pub fn show_basic_plot(ui: &Ui, plot_ui: &PlotUi) {
ui.text(im_str!( ui.text("This header just plots some text with as little code as possible.");
"This header just plots some text with as little code as possible."
));
let content_width = ui.window_content_region_width(); let content_width = ui.window_content_region_width();
Plot::new("Simple text plot") Plot::new("Simple text plot")
// The size call could also be omitted, though the defaults don't consider window // 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) { pub fn show_demo_headers(ui: &Ui, plot_ui: &PlotUi) {
if CollapsingHeader::new(im_str!("Text plot: Basic")).build(&ui) { if CollapsingHeader::new("Text plot: Basic").build(ui) {
show_basic_plot(&ui, &plot_ui); show_basic_plot(ui, plot_ui);
} }
} }

View file

@ -1,4 +1,4 @@
use imgui::{im_str, Condition, Window}; use imgui::{Condition, Window};
use implot::Context; use implot::Context;
// The actual backend-specific code is in this. // The actual backend-specific code is in this.
@ -22,23 +22,20 @@ fn main() {
demo_state.show_demos(ui, &plot_ui); 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) .size([430.0, 450.0], Condition::FirstUseEver)
.build(ui, || { .build(ui, || {
ui.checkbox(im_str!("Show C++ ImPlot demo window"), &mut showing_demo); ui.checkbox("Show C++ ImPlot demo window", &mut showing_demo);
ui.checkbox( ui.checkbox("Show Rust ImPlot demo windows", &mut showing_rust_demo);
im_str!("Show Rust ImPlot demo windows"),
&mut showing_rust_demo,
);
// TODO(4bb4) ... move windows by default so this is less confusing // 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\ "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\ 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 \ 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 \ implemented yet. Feel free to open an issue if you are missing something \
in particular. in particular.
" ",
)); );
}); });
}); });
} }

View file

@ -1,4 +1,4 @@
use imgui::{im_str, Condition, Window}; use imgui::{Condition, Window};
use implot::Context; use implot::Context;
// The actual backend-specific code is in this. // The actual backend-specific code is in this.
@ -22,23 +22,20 @@ fn main() {
demo_state.show_demos(ui, &plot_ui); 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) .size([430.0, 450.0], Condition::FirstUseEver)
.build(ui, || { .build(ui, || {
ui.checkbox(im_str!("Show C++ ImPlot demo window"), &mut showing_demo); ui.checkbox("Show C++ ImPlot demo window", &mut showing_demo);
ui.checkbox( ui.checkbox("Show Rust ImPlot demo windows", &mut showing_rust_demo);
im_str!("Show Rust ImPlot demo windows"),
&mut showing_rust_demo,
);
// TODO(4bb4) ... move windows by default so this is less confusing // 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\ "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\ 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 \ 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 \ implemented yet. Feel free to open an issue if you are missing something \
in particular. in particular.
" ",
)); );
}); });
}); });
} }

View file

@ -5,10 +5,10 @@
use crate::{Context, PlotLocation, PlotOrientation, PlotUi, YAxisChoice, NUMBER_OF_Y_AXES}; use crate::{Context, PlotLocation, PlotOrientation, PlotUi, YAxisChoice, NUMBER_OF_Y_AXES};
use bitflags::bitflags; use bitflags::bitflags;
pub use imgui::Condition; pub use imgui::Condition;
use imgui::{im_str, ImString};
use implot_sys as sys; use implot_sys as sys;
use std::{cell::RefCell, rc::Rc}; use std::ffi::CString;
use std::os::raw::c_char; use std::os::raw::c_char;
use std::{cell::RefCell, rc::Rc};
pub use sys::{ImPlotLimits, ImPlotPoint, ImPlotRange, ImVec2, ImVec4}; pub use sys::{ImPlotLimits, ImPlotPoint, ImPlotRange, ImVec2, ImVec4};
const DEFAULT_PLOT_SIZE_X: f32 = 400.0; 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 /// (If you are coming from the C++ implementation or the C bindings: build() calls both
/// begin() and end() internally) /// begin() and end() internally)
pub struct Plot { pub struct Plot {
/// Title of the plot, shown on top. Stored as ImString because that's what we'll use /// Title of the plot, shown on top. Stored as CString because that's what we'll use
/// afterwards, and this ensures the ImString itself will stay alive long enough for the plot. /// afterwards, and this ensures the CString itself will stay alive long enough for the plot.
title: ImString, title: CString,
/// Size of the plot in [x, y] direction, in the same units imgui uses. /// Size of the plot in [x, y] direction, in the same units imgui uses.
size: [f32; 2], size: [f32; 2],
/// Label of the x axis, shown on the bottom. Stored as ImString because that's what we'll use /// Label of the x axis, shown on the bottom. Stored as CString because that's what we'll use
/// afterwards, and this ensures the ImString itself will stay alive long enough for the plot. /// afterwards, and this ensures the CString itself will stay alive long enough for the plot.
x_label: ImString, x_label: CString,
/// Label of the y axis, shown on the left. Stored as ImString because that's what we'll use /// Label of the y axis, shown on the left. Stored as CString because that's what we'll use
/// afterwards, and this ensures the ImString itself will stay alive long enough for the plot. /// afterwards, and this ensures the CString itself will stay alive long enough for the plot.
y_label: ImString, y_label: CString,
/// X axis limits, if present /// X axis limits, if present
x_limits: Option<AxisLimitSpecification>, x_limits: Option<AxisLimitSpecification>,
/// Y axis limits, if present /// 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 /// 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 /// 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. /// 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 /// convert to null-terminated data anyway, we may as well do that directly instead of cloning
/// Strings and converting them afterwards. /// Strings and converting them afterwards.
x_tick_labels: Option<Vec<ImString>>, x_tick_labels: Option<Vec<CString>>,
/// Whether to also show the default X ticks when showing custom ticks or not /// Whether to also show the default X ticks when showing custom ticks or not
show_x_default_ticks: bool, show_x_default_ticks: bool,
/// Positions for custom Y axis ticks, if any /// 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 /// 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 /// 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. /// 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 /// convert to null-terminated data anyway, we may as well do that directly instead of cloning
/// Strings and converting them afterwards. /// Strings and converting them afterwards.
y_tick_labels: [Option<Vec<ImString>>; NUMBER_OF_Y_AXES], y_tick_labels: [Option<Vec<CString>>; NUMBER_OF_Y_AXES],
/// Whether to also show the default Y ticks when showing custom ticks or not /// Whether to also show the default Y ticks when showing custom ticks or not
show_y_default_ticks: [bool; NUMBER_OF_Y_AXES], show_y_default_ticks: [bool; NUMBER_OF_Y_AXES],
/// Configuration for the legend, if specified. The tuple contains location, orientation /// Configuration for the legend, if specified. The tuple contains location, orientation
@ -158,18 +158,23 @@ pub struct Plot {
impl Plot { impl Plot {
/// Create a new plot with some defaults set. Does not draw anything yet. /// 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 { pub fn new(title: &str) -> Self {
// Needed for initialization, see https://github.com/rust-lang/rust/issues/49147 // Needed for initialization, see https://github.com/rust-lang/rust/issues/49147
const POS_NONE: Option<Vec<f64>> = None; const POS_NONE: Option<Vec<f64>> = None;
const TICK_NONE: Option<Vec<ImString>> = None; const TICK_NONE: Option<Vec<CString>> = None;
// TODO(4bb4) question these defaults, maybe remove some of them // TODO(4bb4) question these defaults, maybe remove some of them
Self { 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], size: [DEFAULT_PLOT_SIZE_X, DEFAULT_PLOT_SIZE_Y],
x_label: im_str!("").into(), x_label: CString::new("").unwrap(),
y_label: im_str!("").into(), y_label: CString::new("").unwrap(),
x_limits: None, x_limits: None,
y_limits: Default::default(), y_limits: Default::default(),
x_tick_positions: None, x_tick_positions: None,
@ -194,16 +199,24 @@ impl Plot {
} }
/// Set the x label of the plot /// Set the x label of the plot
///
/// # Panics
/// Will panic if the label string contains internal null bytes.
#[inline] #[inline]
pub fn x_label(mut self, label: &str) -> Self { 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 self
} }
/// Set the y label of the plot /// Set the y label of the plot
///
/// # Panics
/// Will panic if the label string contains internal null bytes.
#[inline] #[inline]
pub fn y_label(mut self, label: &str) -> Self { 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 self
} }
@ -338,6 +351,9 @@ impl Plot {
/// Set X ticks with labels for the plot. The vector contains one position and label /// 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` /// each in the form of a tuple `(label_position, label_string)`. The `show_default`
/// setting determines whether the default ticks are also shown. /// setting determines whether the default ticks are also shown.
///
/// # Panics
/// Will panic if any of the tick label strings contain internal null bytes.
#[inline] #[inline]
pub fn x_ticks_with_labels( pub fn x_ticks_with_labels(
mut self, mut self,
@ -345,7 +361,15 @@ impl Plot {
show_default: bool, show_default: bool,
) -> Self { ) -> Self {
self.x_tick_positions = Some(tick_labels.iter().map(|x| x.0).collect()); 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.show_x_default_ticks = show_default;
self self
} }
@ -353,6 +377,9 @@ impl Plot {
/// Set Y ticks with labels for the plot. The vector contains one position and label /// 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` /// each in the form of a tuple `(label_position, label_string)`. The `show_default`
/// setting determines whether the default ticks are also shown. /// setting determines whether the default ticks are also shown.
///
/// # Panics
/// Will panic if any of the tick label strings contain internal null bytes.
#[inline] #[inline]
pub fn y_ticks_with_labels( pub fn y_ticks_with_labels(
mut self, mut self,
@ -362,8 +389,15 @@ impl Plot {
) -> Self { ) -> Self {
let axis_index = y_axis_choice as usize; 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_positions[axis_index] = Some(tick_labels.iter().map(|x| x.0).collect());
self.y_tick_labels[axis_index] = self.y_tick_labels[axis_index] = Some(
Some(tick_labels.iter().map(|x| im_str!("{}", x.1)).collect()); 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.show_y_default_ticks[axis_index] = show_default;
self self
} }
@ -618,7 +652,7 @@ impl Plot {
pub struct PlotToken { pub struct PlotToken {
context: *const Context, context: *const Context,
/// For better error messages /// For better error messages
plot_title: ImString, plot_title: CString,
} }
impl PlotToken { impl PlotToken {
@ -634,7 +668,7 @@ impl Drop for PlotToken {
fn drop(&mut self) { fn drop(&mut self) {
if !self.context.is_null() && !std::thread::panicking() { if !self.context.is_null() && !std::thread::panicking() {
panic!( panic!(
"Warning: A PlotToken for plot \"{}\" was not called end() on", "Warning: A PlotToken for plot \"{:?}\" was not called end() on",
self.plot_title self.plot_title
); );
} }

View file

@ -4,7 +4,7 @@
//! as lines, bars, scatter plots and text in a plot. For the module to create plots themselves, //! as lines, bars, scatter plots and text in a plot. For the module to create plots themselves,
//! see `plot`. //! see `plot`.
use crate::sys; use crate::sys;
use imgui::{im_str, ImString}; use std::ffi::CString;
use std::os::raw::c_char; use std::os::raw::c_char;
pub use crate::sys::ImPlotPoint; 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. /// Struct to provide functionality for plotting a line in a plot.
pub struct PlotLine { pub struct PlotLine {
/// Label to show in the legend for this line /// Label to show in the legend for this line
label: String, label: CString,
} }
impl PlotLine { impl PlotLine {
/// Create a new line to be plotted. Does not draw anything yet. /// 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 { pub fn new(label: &str) -> Self {
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 { unsafe {
sys::ImPlot_PlotLinedoublePtrdoublePtr( sys::ImPlot_PlotLinedoublePtrdoublePtr(
im_str!("{}", self.label).as_ptr() as *const c_char, self.label.as_ptr() as *const c_char,
x.as_ptr(), x.as_ptr(),
y.as_ptr(), y.as_ptr(),
x.len().min(y.len()) as i32, // "as" casts saturate as of Rust 1.45. This is safe here. 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. /// Struct to provide functionality for plotting a line in a plot with stairs style.
pub struct PlotStairs { pub struct PlotStairs {
/// Label to show in the legend for this line /// Label to show in the legend for this line
label: String, label: CString,
} }
impl PlotStairs { impl PlotStairs {
/// Create a new line to be plotted. Does not draw anything yet. /// 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 { pub fn new(label: &str) -> Self {
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 { unsafe {
sys::ImPlot_PlotStairsdoublePtrdoublePtr( sys::ImPlot_PlotStairsdoublePtrdoublePtr(
im_str!("{}", self.label).as_ptr() as *const c_char, self.label.as_ptr() as *const c_char,
x.as_ptr(), x.as_ptr(),
y.as_ptr(), y.as_ptr(),
x.len().min(y.len()) as i32, // "as" casts saturate as of Rust 1.45. This is safe here. 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 /// Struct to provide functionality for creating a scatter plot
pub struct PlotScatter { pub struct PlotScatter {
/// Label to show in the legend for this scatter plot /// 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 { impl PlotScatter {
/// Create a new scatter plot to be shown. Does not draw anything yet. /// Create a new scatter plot to be shown. Does not draw anything yet.
pub fn new(label: &str) -> Self { pub fn new(label: &str) -> Self {
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 { unsafe {
sys::ImPlot_PlotScatterdoublePtrdoublePtr( sys::ImPlot_PlotScatterdoublePtrdoublePtr(
im_str!("{}", self.label).as_ptr() as *const c_char, self.label.as_ptr() as *const c_char,
x.as_ptr(), x.as_ptr(),
y.as_ptr(), y.as_ptr(),
x.len().min(y.len()) as i32, // "as" casts saturate as of Rust 1.45. This is safe here. 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. /// Struct to provide bar plotting functionality.
pub struct PlotBars { pub struct PlotBars {
/// Label to show in the legend for this line /// Label to show in the legend for this line
label: String, label: CString,
/// Width of the bars, in plot coordinate terms /// Width of the bars, in plot coordinate terms
bar_width: f64, bar_width: f64,
@ -126,9 +138,13 @@ pub struct PlotBars {
impl PlotBars { impl PlotBars {
/// Create a new bar plot to be shown. Defaults to drawing vertical bars. /// Create a new bar plot to be shown. Defaults to drawing vertical bars.
/// Does not draw anything yet. /// Does not draw anything yet.
///
/// # Panics
/// Will panic if the label string contains internal null bytes.
pub fn new(label: &str) -> Self { pub fn new(label: &str) -> Self {
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 bar_width: 0.67, // Default value taken from C++ implot
horizontal_bars: false, horizontal_bars: false,
} }
@ -164,18 +180,34 @@ impl PlotBars {
let (plot_function, x, y); let (plot_function, x, y);
if self.horizontal_bars { if self.horizontal_bars {
plot_function = sys::ImPlot_PlotBarsHdoublePtrdoublePtr 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; x = bar_values;
y = axis_positions; y = axis_positions;
} else { } else {
plot_function = sys::ImPlot_PlotBarsdoublePtrdoublePtr 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; x = axis_positions;
y = bar_values; y = bar_values;
}; };
plot_function( plot_function(
im_str!("{}", self.label).as_ptr() as *const c_char, self.label.as_ptr() as *const c_char,
x.as_ptr(), x.as_ptr(),
y.as_ptr(), y.as_ptr(),
number_of_points as i32, // "as" casts saturate as of Rust 1.45. This is safe here. 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 /// Struct to provide functionality for adding text within a plot
pub struct PlotText { pub struct PlotText {
/// Label to show in plot /// 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 /// X component of the pixel offset to be used. Will be used independently of the actual plot
/// scaling. Defaults to 0. /// scaling. Defaults to 0.
@ -203,9 +235,13 @@ pub struct PlotText {
impl PlotText { impl PlotText {
/// Create a new text label to be shown. Does not draw anything yet. /// 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 { pub fn new(label: &str) -> Self {
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_x: 0.0,
pixel_offset_y: 0.0, pixel_offset_y: 0.0,
} }
@ -223,13 +259,13 @@ impl PlotText {
/// closures passed to [`Plot::build()`](struct.Plot.html#method.build) /// closures passed to [`Plot::build()`](struct.Plot.html#method.build)
pub fn plot(&self, x: f64, y: f64, vertical: bool) { pub fn plot(&self, x: f64, y: f64, vertical: bool) {
// If there is nothing to show, don't do anything // If there is nothing to show, don't do anything
if self.label.is_empty() { if self.label.as_bytes().is_empty() {
return; return;
} }
unsafe { unsafe {
sys::ImPlot_PlotText( sys::ImPlot_PlotText(
im_str!("{}", self.label).as_ptr() as *const c_char, self.label.as_ptr() as *const c_char,
x, x,
y, y,
vertical, vertical,
@ -245,7 +281,7 @@ impl PlotText {
/// Struct to provide functionality for creating headmaps. /// Struct to provide functionality for creating headmaps.
pub struct PlotHeatmap { pub struct PlotHeatmap {
/// Label to show in plot /// Label to show in plot
label: String, label: CString,
/// Scale range of the values shown. If this is set to `None`, the scale /// 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 /// 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. /// 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 /// 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. /// that is what's needed for the plot call anyway. Conversion is done in the setter.
label_format: Option<ImString>, label_format: Option<CString>,
/// Lower left point for the bounding rectangle. This is called `bounds_min` in the C++ code. /// Lower left point for the bounding rectangle. This is called `bounds_min` in the C++ code.
drawarea_lower_left: ImPlotPoint, drawarea_lower_left: ImPlotPoint,
@ -271,9 +307,10 @@ impl PlotHeatmap {
/// anything yet. /// anything yet.
pub fn new(label: &str) -> Self { pub fn new(label: &str) -> Self {
Self { Self {
label: label.to_owned(), label: CString::new(label)
.unwrap_or_else(|_| panic!("Label string has internal null bytes: {}", label)),
scale_range: None, 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_lower_left: ImPlotPoint { x: 0.0, y: 0.0 },
drawarea_upper_right: ImPlotPoint { x: 1.0, y: 1.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. /// 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 { 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 self
} }
@ -314,7 +357,7 @@ impl PlotHeatmap {
unsafe { unsafe {
sys::ImPlot_PlotHeatmapdoublePtr( sys::ImPlot_PlotHeatmapdoublePtr(
im_str!("{}", self.label).as_ptr() as *const c_char, self.label.as_ptr() as *const c_char,
values.as_ptr(), values.as_ptr(),
number_of_rows as i32, // Not sure why C++ code uses a signed value here 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 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. /// Struct to provide stem plotting functionality.
pub struct PlotStems { pub struct PlotStems {
/// Label to show in the legend for this line /// 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 value for the y value, which the stems are "with respect to"
reference_y: f64, reference_y: f64,
@ -348,7 +391,8 @@ impl PlotStems {
/// [`PlotStems::plot`] on the struct for that. /// [`PlotStems::plot`] on the struct for that.
pub fn new(label: &str) -> Self { pub fn new(label: &str) -> Self {
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 reference_y: 0.0, // Default value taken from C++ implot
} }
} }
@ -370,7 +414,7 @@ impl PlotStems {
} }
unsafe { unsafe {
sys::ImPlot_PlotStemsdoublePtrdoublePtr( 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(), axis_positions.as_ptr(),
stem_values.as_ptr(), stem_values.as_ptr(),
number_of_points as i32, // "as" casts saturate as of Rust 1.45. This is safe here. number_of_points as i32, // "as" casts saturate as of Rust 1.45. This is safe here.