Added marker, stylevar and querying support

This commit is contained in:
4bb4 2020-08-30 11:01:28 +02:00
parent a43a58d819
commit a257332f59
3 changed files with 225 additions and 61 deletions

View file

@ -23,6 +23,9 @@ If you spot any design inconsistencies or papercuts, feel free to open an issue.
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.
Note that the API is not stabilized yet and expected to change as development progresses.
Once there are actual releases on crates.io, semantic versioning will be followed.
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 a subset of the functionality for plots are implemented. for plot creation as well a subset of the functionality for plots are implemented.
See below for an overview of the progress. See below for an overview of the progress.
@ -46,20 +49,20 @@ See below for an overview of the progress.
- [ ] Plot customization - [ ] Plot customization
- [x] Axis flags - [x] Axis flags
- [x] Styling colors - [x] Styling colors
- [ ] Markers - [x] Styling variables
- [ ] Styling variables
- [ ] Colormaps - [ ] Colormaps
- [ ] Plot querying - [ ] Plot querying
- [x] is hovered - [x] is hovered
- [x] mouse position in plot - [x] mouse position in plot
- [x] plot limits - [x] plot limits
- [ ] is queried - [x] is queried
- [ ] GetPlotQuery - [x] get plot query
- [ ] Choice of y axis
- [ ] Utils - [ ] Utils
- [x] Plot limit setting - [x] Plot limit setting
- [ ] imgui-rs style safe push/pop stacks - [x] imgui-rs style safe push/pop stacks
- [ ] Plot tick setting - [ ] Plot tick setting
- [ ] Plot y axis setting for subsequent elements - [ ] Set 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

View file

@ -1,10 +1,14 @@
// This is a somewhat messy example that currently just gets used to test out functionality as it
// is built. It will be taken apart into separate examples with clearer demo purposes later.
use imgui::*; use imgui::*;
use implot::{ use implot::{
get_plot_limits, get_plot_mouse_position, is_plot_hovered, pop_style_color, push_style_color, get_plot_limits, get_plot_mouse_position, get_plot_query, is_plot_hovered, is_plot_queried,
push_style_color, push_style_var_f32, push_style_var_u32,
}; };
use implot::{ use implot::{
AxisFlags, ImPlotLimits, ImPlotPoint, ImPlotRange, Plot, PlotColorElement, PlotFlags, PlotLine, AxisFlags, ImPlotLimits, ImPlotPoint, ImPlotRange, Marker, Plot, PlotColorElement, PlotFlags,
PlotText, PlotLine, PlotText, StyleVar,
}; };
mod support; mod support;
@ -29,9 +33,10 @@ fn main() {
// Create some containers for exfiltrating data from the closure below // Create some containers for exfiltrating data from the closure below
let mut hover_pos: Option<ImPlotPoint> = None; let mut hover_pos: Option<ImPlotPoint> = None;
let mut plot_limits: Option<ImPlotLimits> = None; let mut plot_limits: Option<ImPlotLimits> = None;
let mut query_limits: Option<ImPlotLimits> = None;
// Draw a plot // Draw a plot
push_style_color(&PlotColorElement::PLOT_BG, 1.0, 1.0, 1.0, 0.2); let style = push_style_color(&PlotColorElement::PlotBg, 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")
@ -48,8 +53,15 @@ fn main() {
.with_y_axis_flags(&(AxisFlags::DEFAULT | AxisFlags::INVERT)) .with_y_axis_flags(&(AxisFlags::DEFAULT | AxisFlags::INVERT))
.build(|| { .build(|| {
// Line plotting // Line plotting
let markerchoice =
push_style_var_u32(&StyleVar::Marker, Marker::CROSS.bits());
PlotLine::new("Left eye").plot(&vec![2.0, 2.0], &vec![2.0, 1.0]); PlotLine::new("Left eye").plot(&vec![2.0, 2.0], &vec![2.0, 1.0]);
markerchoice.pop();
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(&vec![4.0, 4.0], &vec![2.0, 1.0]);
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];
let y_values = vec![1.0, 0.0, 0.0, 1.0]; let y_values = vec![1.0, 0.0, 0.0, 1.0];
PlotLine::new("Mouth").plot(&x_values, &y_values); PlotLine::new("Mouth").plot(&x_values, &y_values);
@ -63,6 +75,10 @@ fn main() {
if is_plot_hovered() { if is_plot_hovered() {
hover_pos = Some(get_plot_mouse_position()); hover_pos = Some(get_plot_mouse_position());
} }
if is_plot_queried() {
query_limits = Some(get_plot_query());
}
plot_limits = Some(get_plot_limits()); plot_limits = Some(get_plot_limits());
}); });
@ -73,18 +89,12 @@ fn main() {
ui.text(im_str!("hovered at {}, {}", pos.x, pos.y)); ui.text(im_str!("hovered at {}, {}", pos.x, pos.y));
} }
if let Some(limits) = plot_limits { if let Some(limits) = plot_limits {
ui.text(im_str!( ui.text(im_str!("Plot limits are {:#?}", limits));
"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 let Some(query) = query_limits {
ui.text(im_str!("Query limits are {:#?}", query));
}
style.pop();
}); });
if showing_demo { if showing_demo {

View file

@ -9,6 +9,7 @@
//! //!
pub extern crate implot_sys as sys; pub extern crate implot_sys as sys;
use bitflags::bitflags; use bitflags::bitflags;
use std::convert::TryFrom;
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 // TODO(4bb4) facade-wrap these
@ -18,6 +19,9 @@ 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 -------------------------------------------------------------------------- // --- Enum definitions --------------------------------------------------------------------------
// Things that are to be combined like flags are done using bitflags, and things that are meant
// as enumerations in the traditional sense are plain enums.
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)]
@ -82,40 +86,89 @@ bitflags! {
} }
bitflags! { bitflags! {
/// Axis flags. Documentation copied from implot.h for convenience.
#[repr(transparent)]
pub struct Marker: u32 {
/// no marker
const NONE = sys::ImPlotMarker__ImPlotMarker_None;
/// a circle marker will be rendered at each point
const CIRCLE = sys::ImPlotMarker__ImPlotMarker_Circle;
/// a square maker will be rendered at each point
const SQUARE = sys::ImPlotMarker__ImPlotMarker_Square;
/// a diamond marker will be rendered at each point
const DIAMOND = sys::ImPlotMarker__ImPlotMarker_Diamond;
/// an upward-pointing triangle marker will up rendered at each point
const UP = sys::ImPlotMarker__ImPlotMarker_Up;
/// an downward-pointing triangle marker will up rendered at each point
const DOWN = sys::ImPlotMarker__ImPlotMarker_Down;
/// an leftward-pointing triangle marker will up rendered at each point
const LEFT = sys::ImPlotMarker__ImPlotMarker_Left;
/// an rightward-pointing triangle marker will up rendered at each point
const RIGHT = sys::ImPlotMarker__ImPlotMarker_Right;
/// a cross marker will be rendered at each point (not filled)
const CROSS = sys::ImPlotMarker__ImPlotMarker_Cross;
/// a plus marker will be rendered at each point (not filled)
const PLUS = sys::ImPlotMarker__ImPlotMarker_Plus;
/// a asterisk marker will be rendered at each point (not filled)
const ASTERISK = sys::ImPlotMarker__ImPlotMarker_Asterisk;
}
}
/// Colorable plot elements. These are called "ImPlotCol" in ImPlot itself, but I found that /// 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 /// name somewhat confusing because we are not referring to colors, but _which_ thing can
/// be colored - hence I added the "Element". /// be colored - hence I added the "Element".
#[repr(transparent)] #[repr(u32)]
pub struct PlotColorElement: u32 { #[derive(Copy, Clone, Debug)]
pub enum PlotColorElement {
/// Plot line/outline color (defaults to next unused color in current colormap) /// Plot line/outline color (defaults to next unused color in current colormap)
const LINE = sys::ImPlotCol__ImPlotCol_Line; Line = sys::ImPlotCol__ImPlotCol_Line,
/// Plot fill color for bars (defaults to the current line color) /// Plot fill color for bars (defaults to the current line color)
const FILL = sys::ImPlotCol__ImPlotCol_Fill; Fill = sys::ImPlotCol__ImPlotCol_Fill,
/// Marker outline color (defaults to the current line color) /// Marker outline color (defaults to the current line color)
const MARKER_OUTLINE = sys::ImPlotCol__ImPlotCol_MarkerOutline; MarkerOutline = sys::ImPlotCol__ImPlotCol_MarkerOutline,
/// Marker fill color (defaults to the current line color) /// Marker fill color (defaults to the current line color)
const MARKER_FILL = sys::ImPlotCol__ImPlotCol_MarkerFill; MarkerFill = sys::ImPlotCol__ImPlotCol_MarkerFill,
/// Error bar color (defaults to text color) /// Error bar color (defaults to text color)
const ERROR_BAR = sys::ImPlotCol__ImPlotCol_ErrorBar; ErrorBar = sys::ImPlotCol__ImPlotCol_ErrorBar,
/// Plot frame background color (defaults to FRAME_BG) /// Plot frame background color (defaults to FRAME_BG)
const FRAME_BG = sys::ImPlotCol__ImPlotCol_FrameBg; FrameBg = sys::ImPlotCol__ImPlotCol_FrameBg,
/// Plot area background color (defaults to WINDOW_BG) /// Plot area background color (defaults to WINDOW_BG)
const PLOT_BG = sys::ImPlotCol__ImPlotCol_PlotBg; PlotBg = sys::ImPlotCol__ImPlotCol_PlotBg,
/// Plot area border color (defaults to text color) /// Plot area border color (defaults to text color)
const PLOT_BORDER = sys::ImPlotCol__ImPlotCol_PlotBorder; PlotBorder = sys::ImPlotCol__ImPlotCol_PlotBorder,
/// X-axis grid/label color (defaults to 25% text color) /// X-axis grid/label color (defaults to 25% text color)
const X_AXIS = sys::ImPlotCol__ImPlotCol_XAxis; XAxis = sys::ImPlotCol__ImPlotCol_XAxis,
/// Y-axis grid/label color (defaults to 25% text color) /// Y-axis grid/label color (defaults to 25% text color)
const Y_AXIS = sys::ImPlotCol__ImPlotCol_YAxis; YAxis = sys::ImPlotCol__ImPlotCol_YAxis,
/// 2nd y-axis grid/label color (defaults to 25% text color) /// 2nd y-axis grid/label color (defaults to 25% text color)
const Y_AXIS2 = sys::ImPlotCol__ImPlotCol_YAxis2; YAxis2 = sys::ImPlotCol__ImPlotCol_YAxis2,
/// 3rd y-axis grid/label color (defaults to 25% text color) /// 3rd y-axis grid/label color (defaults to 25% text color)
const Y_AXIS3 = sys::ImPlotCol__ImPlotCol_YAxis3; YAxis3 = sys::ImPlotCol__ImPlotCol_YAxis3,
/// Box-selection color (defaults to yellow) /// Box-selection color (defaults to yellow)
const SELECTION = sys::ImPlotCol__ImPlotCol_Selection; Selection = sys::ImPlotCol__ImPlotCol_Selection,
/// Box-query color (defaults to green) /// Box-query color (defaults to green)
const QUERY = sys::ImPlotCol__ImPlotCol_Query; Query = sys::ImPlotCol__ImPlotCol_Query,
} }
#[repr(u32)]
#[derive(Copy, Clone, Debug)]
pub enum StyleVar {
/// f32, line weight in pixels
LineWeight = sys::ImPlotStyleVar__ImPlotStyleVar_LineWeight,
/// u32, marker specification
Marker = sys::ImPlotStyleVar__ImPlotStyleVar_Marker,
/// f32, marker size in pixels (roughly the marker's "radius")
MarkerSize = sys::ImPlotStyleVar__ImPlotStyleVar_MarkerSize,
/// f32, outline weight of markers in pixels
MarkerWeight = sys::ImPlotStyleVar__ImPlotStyleVar_MarkerWeight,
/// f32, error bar whisker width in pixels
ErrorBarSize = sys::ImPlotStyleVar__ImPlotStyleVar_ErrorBarSize,
/// f32, error bar whisker weight in pixels
ErrorBarWeight = sys::ImPlotStyleVar__ImPlotStyleVar_ErrorBarWeight,
/// f32, digital channels bit height (at 1) in pixels
DigitalBitHeight = sys::ImPlotStyleVar__ImPlotStyleVar_DigitalBitHeight,
/// f32, digital channels bit padding gap in pixels
DigitalBitGap = sys::ImPlotStyleVar__ImPlotStyleVar_DigitalBitGap,
} }
// --- Main plot structure ----------------------------------------------------------------------- // --- Main plot structure -----------------------------------------------------------------------
@ -448,12 +501,24 @@ impl PlotText {
// Currently not in a struct yet. imgui-rs has some smarts about dealing with stacks, in particular // 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. // 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. /// 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) /// 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) { /// The return value is a token that gets used for removing the style color from the stack again:
// TODO this is actually unsafe, safe-wrap this like in imgui-rs' stacks.rs /// ```no_run
/// # use implot::{push_style_color, PlotColorElement};
/// let pushed_var = push_style_color(&PlotColorElement::Line, 1.0, 1.0, 1.0, 0.2);
/// // Plot some things
/// pushed_var.pop();
/// ```
pub fn push_style_color(
element: &PlotColorElement,
red: f32,
green: f32,
blue: f32,
alpha: f32,
) -> StyleColorToken {
unsafe { unsafe {
sys::ImPlot_PushStyleColorVec4( sys::ImPlot_PushStyleColorVec4(
element.bits() as sys::ImPlotCol, *element as sys::ImPlotCol,
sys::ImVec4 { sys::ImVec4 {
x: red, x: red,
y: green, y: green,
@ -462,12 +527,86 @@ pub fn push_style_color(element: &PlotColorElement, red: f32, green: f32, blue:
}, },
); );
} }
StyleColorToken { was_popped: false }
} }
/// Pop a given number of previously-pushed style color from the stack. /// Tracks a change pushed to the style color stack
pub fn pop_style_color(count: i32) { pub struct StyleColorToken {
// TODO this is actually unsafe, safe-wrap this like in imgui-rs' stacks.rs /// Whether this token has been popped or not.
unsafe { sys::ImPlot_PopStyleColor(count) } /// TODO(4bb4) figure out if it is a good idea to warn about this not being popped when it is
/// dropped - this may not be a good idea since users may want to push some style vars for
/// longer durations.
was_popped: bool,
}
impl StyleColorToken {
pub fn pop(mut self) {
if self.was_popped {
panic!("Attempted to pop a style color token twice.")
}
self.was_popped = true;
unsafe {
sys::ImPlot_PopStyleColor(1);
}
}
}
/// Push a f32 style variable to the stack. The returned token is used for removing
/// the variable from the stack again:
/// ```no_run
/// # use implot::{push_style_var_f32, StyleVar};
/// let pushed_var = push_style_var_f32(&StyleVar::LineWeight, 11.0);
/// // Plot some things
/// pushed_var.pop();
/// ```
pub fn push_style_var_f32(element: &StyleVar, value: f32) -> StyleVarToken {
unsafe {
sys::ImPlot_PushStyleVarFloat(*element as sys::ImPlotStyleVar, value);
}
StyleVarToken { was_popped: false }
}
/// Push an u32 style variable to the stack. The only u32 style variable is Marker
/// at the moment, for that, use something like
/// ```no_run
/// # use implot::{push_style_var_u32, StyleVar, Marker};
/// let markerchoice = push_style_var_u32(&StyleVar::Marker, Marker::CROSS.bits());
/// // plot things
/// markerchoice.pop()
/// ```
pub fn push_style_var_u32(element: &StyleVar, value: u32) -> StyleVarToken {
// It is a bit funky that we take an i32 here, but the enum that gets created
// by bindgen contains u32 values, so we do the same but convert them to the
// internal i32 values here. Since this could overflow if a too large u32 value
// was passed, we do a safe conversion here, panicking if it fails.
let value_i32 =
i32::try_from(value).expect("Invalid style variable passed, has to fit in an i32");
unsafe {
sys::ImPlot_PushStyleVarInt(*element as sys::ImPlotStyleVar, value_i32);
}
StyleVarToken { was_popped: false }
}
/// Tracks a change pushed to the style variable stack
pub struct StyleVarToken {
/// Whether this token has been popped or not.
/// TODO(4bb4) figure out if it is a good idea to warn about this not being popped when it is
/// dropped - this may not be a good idea since users may want to push some style vars for
/// longer durations.
was_popped: bool,
}
impl StyleVarToken {
/// Pop this token from the stack.
pub fn pop(mut self) {
if self.was_popped {
panic!("Attempted to pop a style var token twice.")
}
self.was_popped = true;
unsafe {
sys::ImPlot_PopStyleVar(1);
}
}
} }
// --- Miscellaneous ----------------------------------------------------------------------------- // --- Miscellaneous -----------------------------------------------------------------------------
@ -476,6 +615,11 @@ pub fn is_plot_hovered() -> bool {
unsafe { sys::ImPlot_IsPlotHovered() } unsafe { sys::ImPlot_IsPlotHovered() }
} }
/// Returns true if the current or most recent plot is queried
pub fn is_plot_queried() -> bool {
unsafe { sys::ImPlot_IsPlotQueried() }
}
/// Returns the mouse position in x,y coordinates of the current or most recent plot. Currently /// 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 /// pertains to whatever Y axis was most recently selected. TODO(4bb4) add y axis selection
pub fn get_plot_mouse_position() -> ImPlotPoint { pub fn get_plot_mouse_position() -> ImPlotPoint {
@ -490,6 +634,13 @@ pub fn get_plot_limits() -> ImPlotLimits {
unsafe { sys::ImPlot_GetPlotLimits(y_axis_selection) } unsafe { sys::ImPlot_GetPlotLimits(y_axis_selection) }
} }
/// Returns the query limits 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_query() -> ImPlotLimits {
let y_axis_selection = 0;
unsafe { sys::ImPlot_GetPlotQuery(y_axis_selection) }
}
// --- Demo window ------------------------------------------------------------------------------- // --- 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