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
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
for plot creation as well a subset of the functionality for plots are implemented.
See below for an overview of the progress.
@ -46,20 +49,20 @@ See below for an overview of the progress.
- [ ] Plot customization
- [x] Axis flags
- [x] Styling colors
- [ ] Markers
- [ ] Styling variables
- [x] Styling variables
- [ ] Colormaps
- [ ] Plot querying
- [x] is hovered
- [x] mouse position in plot
- [x] plot limits
- [ ] is queried
- [ ] GetPlotQuery
- [x] is queried
- [x] get plot query
- [ ] Choice of y axis
- [ ] Utils
- [x] Plot limit setting
- [ ] imgui-rs style safe push/pop stacks
- [x] imgui-rs style safe push/pop stacks
- [ ] Plot tick setting
- [ ] Plot y axis setting for subsequent elements
- [ ] Set Y axis setting for subsequent elements
- [ ] Plot position and size reading
- [ ] Pixel to plot 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 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::{
AxisFlags, ImPlotLimits, ImPlotPoint, ImPlotRange, Plot, PlotColorElement, PlotFlags, PlotLine,
PlotText,
AxisFlags, ImPlotLimits, ImPlotPoint, ImPlotRange, Marker, Plot, PlotColorElement, PlotFlags,
PlotLine, PlotText, StyleVar,
};
mod support;
@ -29,9 +33,10 @@ fn main() {
// Create some containers for exfiltrating data from the closure below
let mut hover_pos: Option<ImPlotPoint> = None;
let mut plot_limits: Option<ImPlotLimits> = None;
let mut query_limits: Option<ImPlotLimits> = None;
// 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")
.size(400.0, 300.0)
.x_label("awesome x label")
@ -48,8 +53,15 @@ fn main() {
.with_y_axis_flags(&(AxisFlags::DEFAULT | AxisFlags::INVERT))
.build(|| {
// 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]);
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]);
lineweight.pop();
let x_values = vec![1.0, 2.0, 4.0, 5.0];
let y_values = vec![1.0, 0.0, 0.0, 1.0];
PlotLine::new("Mouth").plot(&x_values, &y_values);
@ -63,6 +75,10 @@ fn main() {
if is_plot_hovered() {
hover_pos = Some(get_plot_mouse_position());
}
if is_plot_queried() {
query_limits = Some(get_plot_query());
}
plot_limits = Some(get_plot_limits());
});
@ -73,18 +89,12 @@ fn main() {
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
));
ui.text(im_str!("Plot limits are {:#?}", limits));
}
pop_style_color(1);
if let Some(query) = query_limits {
ui.text(im_str!("Query limits are {:#?}", query));
}
style.pop();
});
if showing_demo {

View file

@ -9,6 +9,7 @@
//!
pub extern crate implot_sys as sys;
use bitflags::bitflags;
use std::convert::TryFrom;
use sys::imgui::im_str;
pub use sys::imgui::Condition;
// 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;
// --- 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! {
/// Window hover check option flags. Documentation copied from implot.h for convenience.
#[repr(transparent)]
@ -82,42 +86,91 @@ 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".
/// Axis flags. Documentation copied from implot.h for convenience.
#[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;
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
/// name somewhat confusing because we are not referring to colors, but _which_ thing can
/// be colored - hence I added the "Element".
#[repr(u32)]
#[derive(Copy, Clone, Debug)]
pub enum PlotColorElement {
/// Plot line/outline color (defaults to next unused color in current colormap)
Line = sys::ImPlotCol__ImPlotCol_Line,
/// Plot fill color for bars (defaults to the current line color)
Fill = sys::ImPlotCol__ImPlotCol_Fill,
/// Marker outline color (defaults to the current line color)
MarkerOutline = sys::ImPlotCol__ImPlotCol_MarkerOutline,
/// Marker fill color (defaults to the current line color)
MarkerFill = sys::ImPlotCol__ImPlotCol_MarkerFill,
/// Error bar color (defaults to text color)
ErrorBar = sys::ImPlotCol__ImPlotCol_ErrorBar,
/// Plot frame background color (defaults to FRAME_BG)
FrameBg = sys::ImPlotCol__ImPlotCol_FrameBg,
/// Plot area background color (defaults to WINDOW_BG)
PlotBg = sys::ImPlotCol__ImPlotCol_PlotBg,
/// Plot area border color (defaults to text color)
PlotBorder = sys::ImPlotCol__ImPlotCol_PlotBorder,
/// X-axis grid/label color (defaults to 25% text color)
XAxis = sys::ImPlotCol__ImPlotCol_XAxis,
/// Y-axis grid/label color (defaults to 25% text color)
YAxis = sys::ImPlotCol__ImPlotCol_YAxis,
/// 2nd y-axis grid/label color (defaults to 25% text color)
YAxis2 = sys::ImPlotCol__ImPlotCol_YAxis2,
/// 3rd y-axis grid/label color (defaults to 25% text color)
YAxis3 = sys::ImPlotCol__ImPlotCol_YAxis3,
/// Box-selection color (defaults to yellow)
Selection = sys::ImPlotCol__ImPlotCol_Selection,
/// Box-query color (defaults to green)
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 -----------------------------------------------------------------------
/// Struct to represent an ImPlot. This is the main construct used to contain all kinds of plots in ImPlot.
///
@ -448,12 +501,24 @@ impl PlotText {
// 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
/// The components should be between 0.0 (no intensity) and 1.0 (full intensity).
/// The return value is a token that gets used for removing the style color from the stack again:
/// ```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 {
sys::ImPlot_PushStyleColorVec4(
element.bits() as sys::ImPlotCol,
*element as sys::ImPlotCol,
sys::ImVec4 {
x: red,
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.
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) }
/// Tracks a change pushed to the style color stack
pub struct StyleColorToken {
/// 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 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 -----------------------------------------------------------------------------
@ -476,6 +615,11 @@ pub fn is_plot_hovered() -> bool {
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
/// pertains to whatever Y axis was most recently selected. TODO(4bb4) add y axis selection
pub fn get_plot_mouse_position() -> ImPlotPoint {
@ -490,6 +634,13 @@ pub fn get_plot_limits() -> ImPlotLimits {
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 -------------------------------------------------------------------------------
/// 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