diff --git a/implot-sys/build.rs b/implot-sys/build.rs index bbafbbc..5fb680a 100644 --- a/implot-sys/build.rs +++ b/implot-sys/build.rs @@ -5,9 +5,10 @@ // for now, but expected to diverge from that over time. use std::{env, fs, io, path::Path}; -const CPP_FILES: [&str; 2] = [ +const CPP_FILES: [&str; 3] = [ "third-party/cimplot/cimplot.cpp", "third-party/cimplot/implot/implot.cpp", + "third-party/cimplot/implot/implot_demo.cpp", // Could remove this if demo not used ]; fn assert_file_exists(path: &str) -> io::Result<()> { diff --git a/src/lib.rs b/src/lib.rs index 6fbf772..d85e68e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,11 +1,30 @@ //! # Rust bindings to ImPlot //! -//! This crate contains idiomatic bindings to the C++ implot library, which -//! use the bindings exposed by the `implot-sys` crate. +//! This crate contains idiomatic bindings to the C++ [implot library](https://github.com/epezent/implot), +//! which use the bindings exposed by the `implot-sys` crate. An attempt is made to keep +//! documentation here somewhat self-contained, but when in doubt, the documentation of implot +//! itself (in particular also the demo code [here](https://github.com/epezent/implot/blob/master/implot_demo.cpp)) +//! should help as well. +//! +//! pub extern crate implot_sys as sys; use sys::imgui::im_str; -/// Struct to represent an 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: +/// ```rust +/// # // This doctest fails because we don't have an imgui context to run things in here +/// # use implot; +/// implot::Plot::new("my title") +/// .size(300.0, 200.0) // other things such as .x_label("some_label") can be added too +/// .build( || { +/// // Do things such as plotting lines +/// }); +/// +/// ``` +/// (If you are coming from the C++ implementation or the C bindings: build() calls both +/// begin() and end() internally) pub struct Plot { /// Title of the plot, shown on top. title: String, @@ -13,10 +32,10 @@ pub struct Plot { x_label: String, /// Label of the y axis, shown on the left y_label: String, - /// Size of the plot in x direction, in pixels. - size_x: u32, - /// Size of the plot in y direction, in pixels. - size_y: u32, + /// Size of the plot in x direction, in the same units imgui uses. + size_x: f32, + /// Size of the plot in y direction, in the same units imgui uses. + size_y: f32, /// Flags relating to the plot TODO(4bb4) make those into bitflags plot_flags: sys::ImPlotFlags, /// Flags relating to the first x axis of the plot TODO(4bb4) make those into bitflags @@ -33,25 +52,48 @@ pub struct Plot { impl Plot { /// Create a new plot with some defaults set. Does not draw anything yet. - pub fn new() -> Self { + pub fn new(title: &str) -> Self { // TODO(4bb4) question these defaults, maybe remove some of them Self { - title: "".to_owned(), + title: title.to_owned(), x_label: "".to_owned(), y_label: "".to_owned(), - size_x: 400, - size_y: 400, - plot_flags: 0xFF, - x_flags: 7, - y_flags: 7, - x2_flags: 0, - y2_flags: 0, + size_x: 400.0, + size_y: 400.0, + plot_flags: 0xFF, // TODO(4bb4) define the defaults better + x_flags: 7, // TODO(4bb4) define the defaults better + y_flags: 7, // TODO(4bb4) define the defaults better + x2_flags: 0, // TODO(4bb4) define the defaults better + y2_flags: 0, // TODO(4bb4) define the defaults better } } + /// Sets the plot size, given as [size_x, size_y]. Units are the same as + /// what imgui uses. TODO(4b4) ... which is? I'm not sure it's pixels + #[inline] + pub fn size(mut self, size_x: f32, size_y: f32) -> Self { + self.size_x = size_x; + self.size_y = size_y; + self + } + + /// Set the x label of the plot + #[inline] + pub fn x_label(mut self, label: &str) -> Self { + self.x_label = label.to_owned(); + self + } + + /// Set the y label of the plot + #[inline] + pub fn y_label(mut self, label: &str) -> Self { + self.y_label = label.to_owned(); + self + } + /// Attempt to show the plot. Only do things with it and call `end()` after that - /// if this returns `true`. - pub fn begin(&self) -> bool { + /// if this returns `true`. Not to be used directly, use `build` instead. + fn begin(&self) -> bool { unsafe { sys::ImPlot_BeginPlot( im_str!("{}", self.title).as_ptr(), @@ -70,14 +112,25 @@ impl Plot { } } - /// End a previously-`begin()`ed plot. Only call if `begin()` returned `true`. - pub fn end(&self) { + /// End (this) plot. This gets called from build() + fn end(&self) { unsafe { sys::ImPlot_EndPlot() } } + + /// Creates a window and runs a closure to construct the contents. + /// + /// Note: the closure is not called if ImPlot::BeginPlot() returned + /// false - TODO(4bb4) figure out if this is if things are not rendered + pub fn build(self, f: F) { + if self.begin() { + f(); + self.end() + } + } } // TODO(4bb4) convert to struct and add methods to set title and flags -/// Plot a line. Use this between Plot::begin() and Plot::end(). +/// Plot a line. Use this in closures passed to [`Plot::build()`](struct.Plot.html#method.build) pub fn plot_line(x: &Vec, y: &Vec, label: &str) { unsafe { implot_sys::ImPlot_PlotLinedoublePtrdoublePtr( @@ -90,3 +143,13 @@ pub fn plot_line(x: &Vec, y: &Vec, label: &str) { ); } } + +/// 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 +/// already - if you find something missing you'd really like, raise an issue. +// This requires implot_demo.cpp to be in the list of sources in implot-sys. +pub fn show_demo_window(show: &mut bool) { + unsafe { + implot_sys::ImPlot_ShowDemoWindow(show); + } +} diff --git a/testexample/Cargo.toml b/testexample/Cargo.toml index d2e28d8..b6ae13d 100644 --- a/testexample/Cargo.toml +++ b/testexample/Cargo.toml @@ -1,11 +1,11 @@ [package] -name = "imgui-examples" +name = "implot-examples" version = "0.0.0" edition = "2018" -authors = ["Joonas Javanainen ", "imgui-rs contributors"] -description = "imgui crate examples using Glium backend" -homepage = "https://github.com/Gekkio/imgui-rs" -repository = "https://github.com/Gekkio/imgui-rs" +authors = ["Sandro Merkli", "implot-rs contributors"] +description = "implot examples, with backend code from the imgui examples in imgui-examples" +homepage = "https://github.com/4bb4/implot-rs" +repository = "https://github.com/4bb4/implot-rs" license = "MIT/Apache-2.0" publish = false diff --git a/testexample/src/main.rs b/testexample/src/main.rs index 72f04bd..c7fb9f1 100644 --- a/testexample/src/main.rs +++ b/testexample/src/main.rs @@ -5,30 +5,38 @@ mod support; fn main() { let system = support::init(file!()); + let mut showing_demo = false; system.main_loop(move |_, ui| { + // Create the window from time imgui example, just... with an added plot Window::new(im_str!("Hello world")) - .size([300.0, 110.0], Condition::FirstUseEver) + .size([430.0, 450.0], Condition::FirstUseEver) .build(ui, || { - ui.text(im_str!("Hello world!")); - ui.text(im_str!("こんにちは世界!")); - ui.text(im_str!("This...is...imgui-rs!")); + ui.text(im_str!("Hello from implot-rs!")); ui.separator(); let mouse_pos = ui.io().mouse_pos; ui.text(format!( "Mouse Position: ({:.1},{:.1})", mouse_pos[0], mouse_pos[1] )); + ui.checkbox(im_str!("Show demo"), &mut showing_demo); - // Demo some implot stuff :D - 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 plot = implot::Plot::new(); - if plot.begin() { - implot::plot_line(&vec![2.0, 2.0], &vec![2.0, 1.0], "Left eye"); - implot::plot_line(&vec![4.0, 4.0], &vec![2.0, 1.0], "Right eye"); - implot::plot_line(&x_values, &y_values, "Mouth"); - plot.end(); - } + // Draw a plot + implot::Plot::new("Demo plot") + .size(400.0, 300.0) + .x_label("awesome x label") + .y_label("awesome y label") + .build(|| { + implot::plot_line(&vec![2.0, 2.0], &vec![2.0, 1.0], "Left eye"); + implot::plot_line(&vec![4.0, 4.0], &vec![2.0, 1.0], "Right eye"); + + let x_values = vec![1.0, 2.0, 4.0, 5.0]; + let y_values = vec![1.0, 0.0, 0.0, 1.0]; + implot::plot_line(&x_values, &y_values, "Mouth"); + }); }); + + if showing_demo { + implot::show_demo_window(&mut showing_demo); + } }); } diff --git a/testexample/src/support/mod.rs b/testexample/src/support/mod.rs index 33c8d0f..64e0950 100644 --- a/testexample/src/support/mod.rs +++ b/testexample/src/support/mod.rs @@ -8,7 +8,7 @@ use glium::glutin::event::{Event, WindowEvent}; use glium::glutin::event_loop::{ControlFlow, EventLoop}; use glium::glutin::window::WindowBuilder; use glium::{Display, Surface}; -use imgui::{Context, FontConfig, FontGlyphRanges, FontSource, Ui}; +use imgui::{Context, FontConfig, FontSource, Ui}; use imgui_glium_renderer::Renderer; use imgui_winit_support::{HiDpiMode, WinitPlatform}; use std::time::Instant;