Added plot style colors and some misc utils. See comments.
- Also exposed the sys crate's ImPlotRange, ImPlotLimits and ImPlotPoint to the user as well as changing the limit-setting interface to using those. I'm not super sure about doing this yet though, because it is more verbose for no real reason to the user and for the purposes of the abstraction it may be better to add facade types anyway. - There is no protection against calling things like `is_hovered` from outside a plot. Will need to think about how to make this impossible by design - we could for example pass an object to Plot's closure that has these methods, and that object is not created anywhere else.
This commit is contained in:
parent
90f7dba1a7
commit
a43a58d819
3 changed files with 163 additions and 25 deletions
23
README.md
23
README.md
|
@ -12,13 +12,20 @@ https://github.com/Gekkio/imgui-rs/pull/339 makes it into a release.
|
||||||
|
|
||||||
The sys crate compiles implot, so a C++ compiler will also be required.
|
The sys crate compiles implot, so a C++ compiler will also be required.
|
||||||
|
|
||||||
|
## Design approach
|
||||||
|
This repo tries to follow the approaches and style used in `imgui-rs` somewhat closely,
|
||||||
|
because implot is to be used within imgui programs, and hence keeping the interfaces
|
||||||
|
and design philosophies close should make it easier to do that.
|
||||||
|
|
||||||
|
If you spot any design inconsistencies or papercuts, feel free to open an issue.
|
||||||
|
|
||||||
## Status
|
## Status
|
||||||
Currently a work in progress. The author is open to collaboration, if you'd like to
|
Currently a work in progress. The author is open to collaboration, if you'd like to
|
||||||
help, feel free to reach out via a Github issue.
|
help, feel free to reach out via a Github issue.
|
||||||
|
|
||||||
At this point, raw bindings are working in implot-sys, and more idiomatic interfaces
|
At this point, raw bindings are working in implot-sys, and more idiomatic interfaces
|
||||||
for plot creation as well as adding lines to plots are implemented. Everything else
|
for plot creation as well a subset of the functionality for plots are implemented.
|
||||||
is still being built.
|
See below for an overview of the progress.
|
||||||
|
|
||||||
- [x] "BeginPlot"
|
- [x] "BeginPlot"
|
||||||
- [x] Basic hello world
|
- [x] Basic hello world
|
||||||
|
@ -37,23 +44,23 @@ is still being built.
|
||||||
- [ ] Pie chart
|
- [ ] Pie chart
|
||||||
- [ ] Digital data
|
- [ ] Digital data
|
||||||
- [ ] Plot customization
|
- [ ] Plot customization
|
||||||
- [ ] Enums
|
|
||||||
- [x] Axis flags
|
- [x] Axis flags
|
||||||
|
- [x] Styling colors
|
||||||
- [ ] Markers
|
- [ ] Markers
|
||||||
- [ ] Styling colors
|
|
||||||
- [ ] Styling variables
|
- [ ] Styling variables
|
||||||
- [ ] Colormaps
|
- [ ] Colormaps
|
||||||
- [ ] Plot querying
|
- [ ] Plot querying
|
||||||
- [ ] is hovered
|
- [x] is hovered
|
||||||
- [ ] mouse position
|
- [x] mouse position in plot
|
||||||
- [ ] mouse limits
|
- [x] plot limits
|
||||||
- [ ] is queried
|
- [ ] is queried
|
||||||
- [ ] GetPlotQuery
|
- [ ] GetPlotQuery
|
||||||
- [ ] Utils
|
- [ ] Utils
|
||||||
- [x] Plot limit setting
|
- [x] Plot limit setting
|
||||||
|
- [ ] imgui-rs style safe push/pop stacks
|
||||||
- [ ] Plot tick setting
|
- [ ] Plot tick setting
|
||||||
- [ ] Plot y axis setting for subsequent elements
|
- [ ] Plot y axis setting for subsequent elements
|
||||||
- [ ] plot position and size reading
|
- [ ] Plot position and size reading
|
||||||
- [ ] Pixel to plot position
|
- [ ] Pixel to plot position
|
||||||
- [ ] Plot to pixel position
|
- [ ] Plot to pixel position
|
||||||
- [ ] Push/pop plotclip rect (?)
|
- [ ] Push/pop plotclip rect (?)
|
||||||
|
|
|
@ -1,5 +1,11 @@
|
||||||
use imgui::*;
|
use imgui::*;
|
||||||
use implot::{AxisFlags, Plot, PlotFlags, PlotLine, PlotText};
|
use implot::{
|
||||||
|
get_plot_limits, get_plot_mouse_position, is_plot_hovered, pop_style_color, push_style_color,
|
||||||
|
};
|
||||||
|
use implot::{
|
||||||
|
AxisFlags, ImPlotLimits, ImPlotPoint, ImPlotRange, Plot, PlotColorElement, PlotFlags, PlotLine,
|
||||||
|
PlotText,
|
||||||
|
};
|
||||||
|
|
||||||
mod support;
|
mod support;
|
||||||
|
|
||||||
|
@ -20,13 +26,24 @@ fn main() {
|
||||||
));
|
));
|
||||||
ui.checkbox(im_str!("Show demo"), &mut showing_demo);
|
ui.checkbox(im_str!("Show demo"), &mut showing_demo);
|
||||||
|
|
||||||
|
// Create some containers for exfiltrating data from the closure below
|
||||||
|
let mut hover_pos: Option<ImPlotPoint> = None;
|
||||||
|
let mut plot_limits: Option<ImPlotLimits> = None;
|
||||||
|
|
||||||
// Draw a plot
|
// Draw a plot
|
||||||
|
push_style_color(&PlotColorElement::PLOT_BG, 1.0, 1.0, 1.0, 0.2);
|
||||||
Plot::new("Demo plot")
|
Plot::new("Demo plot")
|
||||||
.size(400.0, 300.0)
|
.size(400.0, 300.0)
|
||||||
.x_label("awesome x label")
|
.x_label("awesome x label")
|
||||||
.y_label("awesome y label")
|
.y_label("awesome y label")
|
||||||
.x_limits(0.0, 6.0, Condition::FirstUseEver)
|
.x_limits(&ImPlotRange { Min: 0.0, Max: 6.0 }, Condition::FirstUseEver)
|
||||||
.y_limits(-1.0, 3.0, Condition::FirstUseEver)
|
.y_limits(
|
||||||
|
&ImPlotRange {
|
||||||
|
Min: -1.0,
|
||||||
|
Max: 3.0,
|
||||||
|
},
|
||||||
|
Condition::FirstUseEver,
|
||||||
|
)
|
||||||
.with_plot_flags(&(PlotFlags::DEFAULT))
|
.with_plot_flags(&(PlotFlags::DEFAULT))
|
||||||
.with_y_axis_flags(&(AxisFlags::DEFAULT | AxisFlags::INVERT))
|
.with_y_axis_flags(&(AxisFlags::DEFAULT | AxisFlags::INVERT))
|
||||||
.build(|| {
|
.build(|| {
|
||||||
|
@ -43,7 +60,31 @@ fn main() {
|
||||||
.with_pixel_offset(10.0, 30.0)
|
.with_pixel_offset(10.0, 30.0)
|
||||||
.plot(2.0, 2.0, false);
|
.plot(2.0, 2.0, false);
|
||||||
PlotText::new("Vertical Text!").plot(0.1, 2.5, true);
|
PlotText::new("Vertical Text!").plot(0.1, 2.5, true);
|
||||||
|
if is_plot_hovered() {
|
||||||
|
hover_pos = Some(get_plot_mouse_position());
|
||||||
|
}
|
||||||
|
plot_limits = Some(get_plot_limits());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Print some previously-exfiltrated info. This is because calling
|
||||||
|
// things like is_plot_hovered or get_plot_mouse_position() outside
|
||||||
|
// of an actual Plot is not allowed.
|
||||||
|
if let Some(pos) = hover_pos {
|
||||||
|
ui.text(im_str!("hovered at {}, {}", pos.x, pos.y));
|
||||||
|
}
|
||||||
|
if let Some(limits) = plot_limits {
|
||||||
|
ui.text(im_str!(
|
||||||
|
"X limits are {:+10.3}, {:+10.3}",
|
||||||
|
limits.X.Min,
|
||||||
|
limits.X.Max
|
||||||
|
));
|
||||||
|
ui.text(im_str!(
|
||||||
|
"Y limits are {:+10.3}, {:+10.3}",
|
||||||
|
limits.Y.Min,
|
||||||
|
limits.Y.Max
|
||||||
|
));
|
||||||
|
}
|
||||||
|
pop_style_color(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
if showing_demo {
|
if showing_demo {
|
||||||
|
|
110
src/lib.rs
110
src/lib.rs
|
@ -11,10 +11,13 @@ pub extern crate implot_sys as sys;
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
use sys::imgui::im_str;
|
use sys::imgui::im_str;
|
||||||
pub use sys::imgui::Condition;
|
pub use sys::imgui::Condition;
|
||||||
|
// TODO(4bb4) facade-wrap these
|
||||||
|
pub use sys::{ImPlotLimits, ImPlotPoint, ImPlotRange};
|
||||||
|
|
||||||
const DEFAULT_PLOT_SIZE_X: f32 = 400.0;
|
const DEFAULT_PLOT_SIZE_X: f32 = 400.0;
|
||||||
const DEFAULT_PLOT_SIZE_Y: f32 = 400.0;
|
const DEFAULT_PLOT_SIZE_Y: f32 = 400.0;
|
||||||
|
|
||||||
|
// --- Enum definitions --------------------------------------------------------------------------
|
||||||
bitflags! {
|
bitflags! {
|
||||||
/// Window hover check option flags. Documentation copied from implot.h for convenience.
|
/// Window hover check option flags. Documentation copied from implot.h for convenience.
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
|
@ -78,6 +81,44 @@ bitflags! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
/// Colorable plot elements. These are called "ImPlotCol" in ImPlot itself, but I found that
|
||||||
|
/// name somewhat confusing because we are not referring to colors, but _which_ thing can
|
||||||
|
/// be colored - hence I added the "Element".
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct PlotColorElement: u32 {
|
||||||
|
/// Plot line/outline color (defaults to next unused color in current colormap)
|
||||||
|
const LINE = sys::ImPlotCol__ImPlotCol_Line;
|
||||||
|
/// Plot fill color for bars (defaults to the current line color)
|
||||||
|
const FILL = sys::ImPlotCol__ImPlotCol_Fill;
|
||||||
|
/// Marker outline color (defaults to the current line color)
|
||||||
|
const MARKER_OUTLINE = sys::ImPlotCol__ImPlotCol_MarkerOutline;
|
||||||
|
/// Marker fill color (defaults to the current line color)
|
||||||
|
const MARKER_FILL = sys::ImPlotCol__ImPlotCol_MarkerFill;
|
||||||
|
/// Error bar color (defaults to text color)
|
||||||
|
const ERROR_BAR = sys::ImPlotCol__ImPlotCol_ErrorBar;
|
||||||
|
/// Plot frame background color (defaults to FRAME_BG)
|
||||||
|
const FRAME_BG = sys::ImPlotCol__ImPlotCol_FrameBg;
|
||||||
|
/// Plot area background color (defaults to WINDOW_BG)
|
||||||
|
const PLOT_BG = sys::ImPlotCol__ImPlotCol_PlotBg;
|
||||||
|
/// Plot area border color (defaults to text color)
|
||||||
|
const PLOT_BORDER = sys::ImPlotCol__ImPlotCol_PlotBorder;
|
||||||
|
/// X-axis grid/label color (defaults to 25% text color)
|
||||||
|
const X_AXIS = sys::ImPlotCol__ImPlotCol_XAxis;
|
||||||
|
/// Y-axis grid/label color (defaults to 25% text color)
|
||||||
|
const Y_AXIS = sys::ImPlotCol__ImPlotCol_YAxis;
|
||||||
|
/// 2nd y-axis grid/label color (defaults to 25% text color)
|
||||||
|
const Y_AXIS2 = sys::ImPlotCol__ImPlotCol_YAxis2;
|
||||||
|
/// 3rd y-axis grid/label color (defaults to 25% text color)
|
||||||
|
const Y_AXIS3 = sys::ImPlotCol__ImPlotCol_YAxis3;
|
||||||
|
/// Box-selection color (defaults to yellow)
|
||||||
|
const SELECTION = sys::ImPlotCol__ImPlotCol_Selection;
|
||||||
|
/// Box-query color (defaults to green)
|
||||||
|
const QUERY = sys::ImPlotCol__ImPlotCol_Query;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Main plot structure -----------------------------------------------------------------------
|
||||||
/// Struct to represent an ImPlot. This is the main construct used to contain all kinds of plots in ImPlot.
|
/// Struct to represent an ImPlot. This is the main construct used to contain all kinds of plots in ImPlot.
|
||||||
///
|
///
|
||||||
/// `Plot` is to be used (within an imgui window) with the following pattern:
|
/// `Plot` is to be used (within an imgui window) with the following pattern:
|
||||||
|
@ -104,9 +145,9 @@ pub struct Plot {
|
||||||
/// Label of the y axis, shown on the left
|
/// Label of the y axis, shown on the left
|
||||||
y_label: String,
|
y_label: String,
|
||||||
/// X axis limits, if present
|
/// X axis limits, if present
|
||||||
x_limits: Option<[f64; 2]>,
|
x_limits: Option<ImPlotRange>,
|
||||||
/// Y axis limits, if present
|
/// Y axis limits, if present
|
||||||
y_limits: Option<[f64; 2]>,
|
y_limits: Option<ImPlotRange>,
|
||||||
/// Condition on which the x limits are set
|
/// Condition on which the x limits are set
|
||||||
x_limit_condition: Option<Condition>,
|
x_limit_condition: Option<Condition>,
|
||||||
/// Condition on which the y limits are set (first y axis for now)
|
/// Condition on which the y limits are set (first y axis for now)
|
||||||
|
@ -172,16 +213,16 @@ impl Plot {
|
||||||
|
|
||||||
/// Set the x limits of the plot
|
/// Set the x limits of the plot
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn x_limits(mut self, x_min: f64, x_max: f64, condition: Condition) -> Self {
|
pub fn x_limits(mut self, limits: &ImPlotRange, condition: Condition) -> Self {
|
||||||
self.x_limits = Some([x_min, x_max]);
|
self.x_limits = Some(*limits);
|
||||||
self.x_limit_condition = Some(condition);
|
self.x_limit_condition = Some(condition);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the y limits of the plot
|
/// Set the y limits of the plot
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn y_limits(mut self, y_min: f64, y_max: f64, condition: Condition) -> Self {
|
pub fn y_limits(mut self, limits: &ImPlotRange, condition: Condition) -> Self {
|
||||||
self.y_limits = Some([y_min, y_max]);
|
self.y_limits = Some(*limits);
|
||||||
self.y_limit_condition = Some(condition);
|
self.y_limit_condition = Some(condition);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -231,17 +272,18 @@ impl Plot {
|
||||||
pub fn begin(&self) -> Option<PlotToken> {
|
pub fn begin(&self) -> Option<PlotToken> {
|
||||||
if let (Some(limits), Some(condition)) = (self.x_limits, self.x_limit_condition) {
|
if let (Some(limits), Some(condition)) = (self.x_limits, self.x_limit_condition) {
|
||||||
unsafe {
|
unsafe {
|
||||||
sys::ImPlot_SetNextPlotLimitsX(limits[0], limits[1], condition as sys::ImGuiCond);
|
sys::ImPlot_SetNextPlotLimitsX(limits.Min, limits.Max, condition as sys::ImGuiCond);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let (Some(limits), Some(condition)) = (self.y_limits, self.y_limit_condition) {
|
if let (Some(limits), Some(condition)) = (self.y_limits, self.y_limit_condition) {
|
||||||
// TODO(4bb4) allow for specification of multiple y limits, not just the first
|
// TODO(4bb4) allow for specification of multiple y limits, not just the first
|
||||||
|
let selected_y_axis = 0;
|
||||||
unsafe {
|
unsafe {
|
||||||
sys::ImPlot_SetNextPlotLimitsY(
|
sys::ImPlot_SetNextPlotLimitsY(
|
||||||
limits[0],
|
limits.Min,
|
||||||
limits[1],
|
limits.Max,
|
||||||
condition as sys::ImGuiCond,
|
condition as sys::ImGuiCond,
|
||||||
0,
|
selected_y_axis,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -313,6 +355,7 @@ impl Drop for PlotToken {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Actual plotting functionality -------------------------------------------------------------
|
||||||
/// 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
|
||||||
|
@ -401,6 +444,53 @@ impl PlotText {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Push/pop utils -------------------------------------------------------------------------
|
||||||
|
// Currently not in a struct yet. imgui-rs has some smarts about dealing with stacks, in particular
|
||||||
|
// leak detection, which I'd like to replicate here at some point.
|
||||||
|
/// Push a style color to the stack, giving an element and the four components of the color.
|
||||||
|
/// The components should be between 0.0 (no intensity) and 1.0 (full intensity)
|
||||||
|
pub fn push_style_color(element: &PlotColorElement, red: f32, green: f32, blue: f32, alpha: f32) {
|
||||||
|
// TODO this is actually unsafe, safe-wrap this like in imgui-rs' stacks.rs
|
||||||
|
unsafe {
|
||||||
|
sys::ImPlot_PushStyleColorVec4(
|
||||||
|
element.bits() as sys::ImPlotCol,
|
||||||
|
sys::ImVec4 {
|
||||||
|
x: red,
|
||||||
|
y: green,
|
||||||
|
z: blue,
|
||||||
|
w: alpha,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Pop a given number of previously-pushed style color from the stack.
|
||||||
|
pub fn pop_style_color(count: i32) {
|
||||||
|
// TODO this is actually unsafe, safe-wrap this like in imgui-rs' stacks.rs
|
||||||
|
unsafe { sys::ImPlot_PopStyleColor(count) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Miscellaneous -----------------------------------------------------------------------------
|
||||||
|
/// Returns true if the plot area in the current or most recent plot is hovered.
|
||||||
|
pub fn is_plot_hovered() -> bool {
|
||||||
|
unsafe { sys::ImPlot_IsPlotHovered() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the mouse position in x,y coordinates of the current or most recent plot. Currently
|
||||||
|
/// pertains to whatever Y axis was most recently selected. TODO(4bb4) add y axis selection
|
||||||
|
pub fn get_plot_mouse_position() -> ImPlotPoint {
|
||||||
|
let y_axis_selection = 0;
|
||||||
|
unsafe { sys::ImPlot_GetPlotMousePos(y_axis_selection) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the current or most recent plot axis range. Currently pertains to whatever Y axis was
|
||||||
|
/// most recently selected. TODO(4bb4) add y axis selection
|
||||||
|
pub fn get_plot_limits() -> ImPlotLimits {
|
||||||
|
let y_axis_selection = 0;
|
||||||
|
unsafe { sys::ImPlot_GetPlotLimits(y_axis_selection) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Demo window -------------------------------------------------------------------------------
|
||||||
/// Show the demo window for poking around what functionality implot has to
|
/// Show the demo window for poking around what functionality implot has to
|
||||||
/// offer. Note that not all of this is necessarily implemented in implot-rs
|
/// offer. Note that not all of this is necessarily implemented in implot-rs
|
||||||
/// already - if you find something missing you'd really like, raise an issue.
|
/// already - if you find something missing you'd really like, raise an issue.
|
||||||
|
|
Loading…
Reference in a new issue