From b6a7cae830d078e318e85096aee5a6abd5549a54 Mon Sep 17 00:00:00 2001 From: 4bb4 <67376761+4bb4@users.noreply.github.com> Date: Fri, 30 Oct 2020 14:35:50 +0100 Subject: [PATCH] Brought WebGPU demo into same structure as Glium demo --- implot-examples/README.md | 4 +- implot-examples/implot-glium-demo/src/main.rs | 40 +++ .../implot-glium-demo/src/support/mod.rs | 2 +- implot-examples/implot-wgpu-demo/src/main.rs | 259 ++---------------- .../implot-wgpu-demo/src/support/clipboard.rs | 24 ++ .../implot-wgpu-demo/src/support/mod.rs | 233 ++++++++++++++++ implot-examples/implot-wgpu-demo/src/ui.rs | 232 ---------------- 7 files changed, 329 insertions(+), 465 deletions(-) create mode 100644 implot-examples/implot-glium-demo/src/main.rs create mode 100644 implot-examples/implot-wgpu-demo/src/support/clipboard.rs create mode 100644 implot-examples/implot-wgpu-demo/src/support/mod.rs delete mode 100644 implot-examples/implot-wgpu-demo/src/ui.rs diff --git a/implot-examples/README.md b/implot-examples/README.md index 58290ba..e267f2d 100644 --- a/implot-examples/README.md +++ b/implot-examples/README.md @@ -8,9 +8,7 @@ Things are structured as follows: * [implot-glium-demo](implot-glium-demo/) is an example for using `implot-rs` in conjunction with a [Glium](https://github.com/glium/glium) backend. * [implot-wgpu-demo](implot-wgpu-demo/) is an example for using `implot-rs` in -conjunction with a [WebGPU](https://github.com/gfx-rs/wgpu) backend (work in progress, this -uses wgpu, but does currently not make use of `examples-shared` yet and has not been refactored -to look the same as the glium example structurally) +conjunction with a [WebGPU](https://github.com/gfx-rs/wgpu) backend If you want to just copy-paste code to start with, copy `examples-shared` along with your favourite backend example crate. The glium backend code is largely taken from imgui-rs. diff --git a/implot-examples/implot-glium-demo/src/main.rs b/implot-examples/implot-glium-demo/src/main.rs new file mode 100644 index 0000000..a3dbaed --- /dev/null +++ b/implot-examples/implot-glium-demo/src/main.rs @@ -0,0 +1,40 @@ +use examples_shared; +use imgui::{im_str, Condition, Window}; +use implot::Context; + +// the actual implot samples are in there TODO(4bb4) move to using examples-shared instead +mod support; + +fn main() { + let system = support::init(file!()); + let mut showing_demo = false; + let mut showing_rust_demo = true; + let plotcontext = Context::create(); + system.main_loop(move |_, ui| { + // The context is moved into the closure after creation so plot_ui is valid. + let plot_ui = plotcontext.get_plot_ui(); + + if showing_demo { + implot::show_demo_window(&mut showing_demo); + } + + if showing_rust_demo { + examples_shared::show_demos(ui, &plot_ui); + } + + Window::new(im_str!("Welcome to the ImPlot-rs demo!")) + .size([430.0, 450.0], Condition::FirstUseEver) + .build(ui, || { + ui.checkbox(im_str!("Show C++ ImPlot demo window"), &mut showing_demo); + ui.checkbox( + im_str!("Show Rust ImPlot demo windows"), + &mut showing_rust_demo, + ); + // TODO(4bb4) ... move windows by default so this is less confusing + ui.text_wrapped(im_str!( + "Note that the windows are stacked, so move this one out of the way to see\ + the ones beneath it." + )); + }); + }); +} diff --git a/implot-examples/implot-glium-demo/src/support/mod.rs b/implot-examples/implot-glium-demo/src/support/mod.rs index 64e0950..7c521d8 100644 --- a/implot-examples/implot-glium-demo/src/support/mod.rs +++ b/implot-examples/implot-glium-demo/src/support/mod.rs @@ -19,8 +19,8 @@ pub struct System { pub event_loop: EventLoop<()>, pub display: glium::Display, pub imgui: Context, - pub platform: WinitPlatform, pub renderer: Renderer, + pub platform: WinitPlatform, pub font_size: f32, } diff --git a/implot-examples/implot-wgpu-demo/src/main.rs b/implot-examples/implot-wgpu-demo/src/main.rs index e6412ea..a3dbaed 100644 --- a/implot-examples/implot-wgpu-demo/src/main.rs +++ b/implot-examples/implot-wgpu-demo/src/main.rs @@ -1,239 +1,40 @@ -use futures::executor::block_on; -use imgui::*; -use imgui_wgpu::RendererConfig; -use std::time::Instant; -use winit::{ - dpi::LogicalSize, - event::{Event, WindowEvent}, - event_loop::{ControlFlow, EventLoop}, - window::Window, -}; +use examples_shared; +use imgui::{im_str, Condition, Window}; +use implot::Context; // the actual implot samples are in there TODO(4bb4) move to using examples-shared instead -mod ui; +mod support; fn main() { - // --- Backend setup ---------------------------------------------------------------- - // Set up window and GPU - let event_loop = EventLoop::new(); - let instance = wgpu::Instance::new(wgpu::BackendBit::PRIMARY); - - let (window, size, surface) = { - let window = Window::new(&event_loop).unwrap(); - window.set_inner_size(LogicalSize { - width: 1280.0, - height: 720.0, - }); - window.set_title(&"implot-wgpu".to_string()); - let size = window.inner_size(); - - let surface = unsafe { instance.create_surface(&window) }; - - (window, size, surface) - }; - - let adapter = block_on(instance.request_adapter(&wgpu::RequestAdapterOptions { - power_preference: wgpu::PowerPreference::HighPerformance, - compatible_surface: Some(&surface), - })) - .unwrap(); - - let (device, queue) = block_on(adapter.request_device( - &wgpu::DeviceDescriptor { - features: wgpu::Features::empty(), - limits: wgpu::Limits::default(), - shader_validation: false, - }, - None, - )) - .unwrap(); - - // Set up swap chain - let mut sc_desc = wgpu::SwapChainDescriptor { - usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT, - format: wgpu::TextureFormat::Bgra8Unorm, - width: size.width, - height: size.height, - present_mode: wgpu::PresentMode::Mailbox, - }; - - let mut swap_chain = device.create_swap_chain(&surface, &sc_desc); - - // Set up dear imgui - let mut imgui = imgui::Context::create(); - let implot = implot::Context::create(); - - let mut platform = imgui_winit_support::WinitPlatform::init(&mut imgui); - platform.attach_window( - imgui.io_mut(), - &window, - imgui_winit_support::HiDpiMode::Default, - ); - imgui.set_ini_filename(None); - - let mut hidpi_factor = window.scale_factor(); - - let font_size = (13.0 * hidpi_factor) as f32; - imgui.io_mut().font_global_scale = (1.0 / hidpi_factor) as f32; - - imgui.fonts().add_font(&[FontSource::DefaultFontData { - config: Some(imgui::FontConfig { - oversample_h: 1, - pixel_snap_h: true, - size_pixels: font_size, - ..Default::default() - }), - }]); - - // - // Set up dear imgui wgpu renderer - // - let mut renderer = RendererConfig::new() - .set_texture_format(sc_desc.format) - .build(&mut imgui, &device, &queue); - - let mut last_frame = Instant::now(); - let mut last_cursor = None; - + let system = support::init(file!()); let mut showing_demo = false; - let mut make_fullscreen = false; + let mut showing_rust_demo = true; + let plotcontext = Context::create(); + system.main_loop(move |_, ui| { + // The context is moved into the closure after creation so plot_ui is valid. + let plot_ui = plotcontext.get_plot_ui(); - // --- Event loop ------------------------------------------------------------------- - event_loop.run(move |event, _, control_flow| { - *control_flow = ControlFlow::Poll; - - let plot_ui = implot.get_plot_ui(); - match event { - Event::WindowEvent { - event: WindowEvent::ScaleFactorChanged { scale_factor, .. }, - .. - } => { - hidpi_factor = scale_factor; - } - Event::WindowEvent { - event: WindowEvent::Resized(size), - .. - } => { - // Recreate the swap chain with the new size - sc_desc.width = size.width; - sc_desc.height = size.height; - swap_chain = device.create_swap_chain(&surface, &sc_desc); - } - Event::WindowEvent { - event: WindowEvent::CloseRequested, - .. - } => *control_flow = ControlFlow::Exit, - Event::MainEventsCleared => window.request_redraw(), - Event::RedrawEventsCleared => { - let now = Instant::now(); - imgui.io_mut().update_delta_time(now - last_frame); - last_frame = now; - - let frame = match swap_chain.get_current_frame() { - Ok(frame) => frame, - Err(e) => { - eprintln!("dropped frame: {:?}", e); - return; - } - }; - - platform - .prepare_frame(imgui.io_mut(), &window) - .expect("Failed to prepare frame"); - let ui = imgui.frame(); - - // --- Actual drawing code ---------------------------------------------- - { - let window = imgui::Window::new(im_str!("Hello implot")); - let window = if make_fullscreen { - let border = 10.0; - window.position([0.0, 0.0], Condition::Always).size( - [ - sc_desc.width as f32 / hidpi_factor as f32 - border, - sc_desc.height as f32 / hidpi_factor as f32 - border, - ], - Condition::Always, - ) - } else { - window.size([400.0, 300.0], Condition::FirstUseEver) - }; - - window.build(&ui, || { - ui.text(im_str!("Hello from implot-rs!")); - ui.text_wrapped(im_str!( - "The headers here demo the line plotting features of the library. \ - Have a look at the example source code to see how they are implemented.\n\ - Check out the demo from ImPlot itself first \ - (by enabling the 'Show demo' checkbox) for instructions \ - on how to interact with ImPlot plots." - )); - - ui.checkbox(im_str!("Show demo"), &mut showing_demo); - ui.checkbox( - im_str!("make the implot window fill the whole outer window"), - &mut make_fullscreen, - ); - - // Show individual examples in collapsed headers - if CollapsingHeader::new(im_str!("Basic lineplot")).build(&ui) { - ui::show_basic_plot(&ui, &plot_ui); - } - if CollapsingHeader::new(im_str!("Configurable lineplot")).build(&ui) { - ui::show_configurable_plot(&ui, &plot_ui); - } - if CollapsingHeader::new(im_str!("Querying a plot")).build(&ui) { - ui::show_query_features_plot(&ui, &plot_ui); - } - if CollapsingHeader::new(im_str!("Styling a plot")).build(&ui) { - ui::show_style_plot(&ui, &plot_ui); - } - if CollapsingHeader::new(im_str!("Colormap selection")).build(&ui) { - ui::show_colormaps_plot(&ui, &plot_ui); - } - }); - } - - if showing_demo { - implot::show_demo_window(&mut showing_demo); - } - - // --- Post-drawing rendering code -------------------------------------- - let mut encoder: wgpu::CommandEncoder = - device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }); - - if last_cursor != Some(ui.mouse_cursor()) { - last_cursor = Some(ui.mouse_cursor()); - platform.prepare_render(&ui, &window); - } - - let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor { - attachment: &frame.output.view, - resolve_target: None, - ops: wgpu::Operations { - load: wgpu::LoadOp::Clear(wgpu::Color { - r: 0.1, - g: 0.4, - b: 0.3, - a: 1.0, - }), - store: true, - }, - }], - depth_stencil_attachment: None, - }); - - renderer - .render(ui.render(), &queue, &device, &mut rpass) - .expect("Rendering failed"); - - drop(rpass); // renders to screen on drop, will probaly be changed in wgpu 0.7 or later - - queue.submit(Some(encoder.finish())); - } - _ => (), + if showing_demo { + implot::show_demo_window(&mut showing_demo); } - platform.handle_event(imgui.io_mut(), &window, &event); + if showing_rust_demo { + examples_shared::show_demos(ui, &plot_ui); + } + + Window::new(im_str!("Welcome to the ImPlot-rs demo!")) + .size([430.0, 450.0], Condition::FirstUseEver) + .build(ui, || { + ui.checkbox(im_str!("Show C++ ImPlot demo window"), &mut showing_demo); + ui.checkbox( + im_str!("Show Rust ImPlot demo windows"), + &mut showing_rust_demo, + ); + // TODO(4bb4) ... move windows by default so this is less confusing + ui.text_wrapped(im_str!( + "Note that the windows are stacked, so move this one out of the way to see\ + the ones beneath it." + )); + }); }); } diff --git a/implot-examples/implot-wgpu-demo/src/support/clipboard.rs b/implot-examples/implot-wgpu-demo/src/support/clipboard.rs new file mode 100644 index 0000000..7268798 --- /dev/null +++ b/implot-examples/implot-wgpu-demo/src/support/clipboard.rs @@ -0,0 +1,24 @@ +// Taken directly from imgui-rs examples at +// +// https://github.com/Gekkio/imgui-rs/tree/master/imgui-examples/examples/support +// +// Not my code. Originally by Joonas Javanainen and the ImGUI-rs contributors +use clipboard::{ClipboardContext, ClipboardProvider}; +use imgui::{ClipboardBackend, ImStr, ImString}; + +pub struct ClipboardSupport(ClipboardContext); + +pub fn init() -> Option { + ClipboardContext::new() + .ok() + .map(|ctx| ClipboardSupport(ctx)) +} + +impl ClipboardBackend for ClipboardSupport { + fn get(&mut self) -> Option { + self.0.get_contents().ok().map(|text| text.into()) + } + fn set(&mut self, text: &ImStr) { + let _ = self.0.set_contents(text.to_str().to_owned()); + } +} diff --git a/implot-examples/implot-wgpu-demo/src/support/mod.rs b/implot-examples/implot-wgpu-demo/src/support/mod.rs new file mode 100644 index 0000000..a514204 --- /dev/null +++ b/implot-examples/implot-wgpu-demo/src/support/mod.rs @@ -0,0 +1,233 @@ +use futures::executor::block_on; +use imgui::{Context, FontSource, Ui}; +use imgui_wgpu::{Renderer, RendererConfig}; +use imgui_winit_support::WinitPlatform; +use std::time::Instant; +use winit::{ + dpi::LogicalSize, + event::{Event, WindowEvent}, + event_loop::{ControlFlow, EventLoop}, + window::Window, +}; + +pub struct System { + pub event_loop: EventLoop<()>, + pub imgui: Context, + pub renderer: Renderer, + pub platform: WinitPlatform, + pub font_size: f32, + pub hidpi_factor: f64, + pub sc_desc: wgpu::SwapChainDescriptor, + pub swap_chain: wgpu::SwapChain, + pub window: Window, + pub device: wgpu::Device, + pub queue: wgpu::Queue, + pub surface: wgpu::Surface, +} + +pub fn init(title: &str) -> System { + // Set up window and GPU + let event_loop = EventLoop::new(); + let instance = wgpu::Instance::new(wgpu::BackendBit::PRIMARY); + + let (window, size, surface) = { + let window = Window::new(&event_loop).unwrap(); + window.set_inner_size(LogicalSize { + width: 1280.0, + height: 720.0, + }); + window.set_title(title); + let size = window.inner_size(); + + let surface = unsafe { instance.create_surface(&window) }; + + (window, size, surface) + }; + + let adapter = block_on(instance.request_adapter(&wgpu::RequestAdapterOptions { + power_preference: wgpu::PowerPreference::HighPerformance, + compatible_surface: Some(&surface), + })) + .unwrap(); + + let (device, queue) = block_on(adapter.request_device( + &wgpu::DeviceDescriptor { + features: wgpu::Features::empty(), + limits: wgpu::Limits::default(), + shader_validation: false, + }, + None, + )) + .unwrap(); + + // Set up swap chain + let sc_desc = wgpu::SwapChainDescriptor { + usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT, + format: wgpu::TextureFormat::Bgra8Unorm, + width: size.width, + height: size.height, + present_mode: wgpu::PresentMode::Mailbox, + }; + + let swap_chain = device.create_swap_chain(&surface, &sc_desc); + + // Set up dear imgui + let mut imgui = imgui::Context::create(); + + let mut platform = imgui_winit_support::WinitPlatform::init(&mut imgui); + platform.attach_window( + imgui.io_mut(), + &window, + imgui_winit_support::HiDpiMode::Default, + ); + imgui.set_ini_filename(None); + + let hidpi_factor = window.scale_factor(); + + let font_size = (13.0 * hidpi_factor) as f32; + imgui.io_mut().font_global_scale = (1.0 / hidpi_factor) as f32; + + imgui.fonts().add_font(&[FontSource::DefaultFontData { + config: Some(imgui::FontConfig { + oversample_h: 1, + pixel_snap_h: true, + size_pixels: font_size, + ..Default::default() + }), + }]); + + // + // Set up dear imgui wgpu renderer + // + let renderer = RendererConfig::new() + .set_texture_format(sc_desc.format) + .build(&mut imgui, &device, &queue); + + System { + event_loop, + imgui, + renderer, + platform, + font_size, + hidpi_factor, + sc_desc, + swap_chain, + window, + device, + queue, + surface, + } +} + +impl System { + pub fn main_loop(self, mut run_ui: F) { + let System { + event_loop, + mut imgui, + mut renderer, + // Currently not used, but was used pre-refactor + // mut hidpi_factor, + mut sc_desc, + mut platform, + window, + mut swap_chain, + device, + queue, + surface, + .. + } = self; + let mut last_frame = Instant::now(); + let mut last_cursor = None; + + event_loop.run(move |event, _, control_flow| { + *control_flow = ControlFlow::Poll; + + match event { + Event::WindowEvent { + event: WindowEvent::ScaleFactorChanged { scale_factor, .. }, + .. + } => { + // This + let _hidpi_factor = scale_factor; + } + Event::WindowEvent { + event: WindowEvent::Resized(size), + .. + } => { + // Recreate the swap chain with the new size + sc_desc.width = size.width; + sc_desc.height = size.height; + swap_chain = device.create_swap_chain(&surface, &sc_desc); + } + Event::WindowEvent { + event: WindowEvent::CloseRequested, + .. + } => *control_flow = ControlFlow::Exit, + Event::MainEventsCleared => window.request_redraw(), + Event::RedrawEventsCleared => { + let now = Instant::now(); + imgui.io_mut().update_delta_time(now - last_frame); + last_frame = now; + + let frame = match swap_chain.get_current_frame() { + Ok(frame) => frame, + Err(e) => { + eprintln!("dropped frame: {:?}", e); + return; + } + }; + + platform + .prepare_frame(imgui.io_mut(), &window) + .expect("Failed to prepare frame"); + let mut ui = imgui.frame(); + + // --- Actual drawing code ---------------------------------------------- + let mut run = true; + run_ui(&mut run, &mut ui); + if !run { + *control_flow = ControlFlow::Exit; + } + + // --- Post-drawing rendering code -------------------------------------- + let mut encoder: wgpu::CommandEncoder = device + .create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }); + + if last_cursor != Some(ui.mouse_cursor()) { + last_cursor = Some(ui.mouse_cursor()); + platform.prepare_render(&ui, &window); + } + + let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor { + attachment: &frame.output.view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Clear(wgpu::Color { + // TODO(4bb4) remove hardcoded values here + r: 0.1, + g: 0.4, + b: 0.3, + a: 1.0, + }), + store: true, + }, + }], + depth_stencil_attachment: None, + }); + + renderer + .render(ui.render(), &queue, &device, &mut rpass) + .expect("Rendering failed"); + + drop(rpass); // renders to screen on drop, will probaly be changed in wgpu 0.7 or later + + queue.submit(Some(encoder.finish())); + } + _ => (), + } + + platform.handle_event(imgui.io_mut(), &window, &event); + }) + } +} diff --git a/implot-examples/implot-wgpu-demo/src/ui.rs b/implot-examples/implot-wgpu-demo/src/ui.rs deleted file mode 100644 index 4655779..0000000 --- a/implot-examples/implot-wgpu-demo/src/ui.rs +++ /dev/null @@ -1,232 +0,0 @@ -use imgui::{im_str, Condition, Ui}; -use implot::{ - 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_i32, set_colormap_from_preset, - set_colormap_from_vec, AxisFlags, Colormap, ImPlotLimits, ImPlotPoint, ImPlotRange, ImVec4, - Marker, Plot, PlotColorElement, PlotFlags, PlotLine, PlotUi, StyleVar, YAxisChoice, -}; - -pub fn show_basic_plot(ui: &Ui, plot_ui: &PlotUi) { - ui.text(im_str!( - "This header just plots a line with as little code as possible." - )); - let content_width = ui.window_content_region_width(); - Plot::new("Simple line plot") - // The size call could also be omitted, though the defaults don't consider window - // width, which is why we're not doing so here. - .size(content_width, 300.0) - .build(plot_ui, || { - // If this is called outside a plot build callback, the program will panic. - let x_positions = vec![0.1, 0.9]; - let y_positions = vec![0.1, 0.9]; - PlotLine::new("legend label").plot(&x_positions, &y_positions); - }); -} - -pub fn show_configurable_plot(ui: &Ui, plot_ui: &PlotUi) { - ui.text(im_str!( - "This header demos what we can configure about plots." - )); - - // Settings for the plot - // - X and Y size in pixels - let x_size = 300.0; - let y_size = 200.0; - // - Strings for the axis labels - let x_label = "X label"; - let y_label = "Y label!"; - // - Plot limits - let x_min = 2.0; - let x_max = 3.0; - let y_min = 1.0; - let y_max = 2.0; - // - Plot flags, see the PlotFlags docs for more info - let plot_flags = PlotFlags::NONE; - // - Axis flags, see the AxisFlags docs for more info. All flags are bitflags-created, - // so they support a bunch of convenient operations, see https://docs.rs/bitflags - let x_axis_flags = AxisFlags::NONE; - let y_axis_flags = AxisFlags::NONE; - - // - Unlabelled X axis ticks - let x_ticks = vec![2.2, 2.5, 2.8]; - - // - Labelled Y axis ticks - let y_ticks = vec![(1.1, "A".to_owned()), (1.4, "B".to_owned())]; - - // Axis labels - Plot::new("Configured line plot") - .size(x_size, y_size) - .x_label(&x_label) - .y_label(&y_label) - .x_limits( - &ImPlotRange { - Min: x_min, - Max: x_max, - }, - // Always means that the limits stay what we force them to here, even if the user - // scrolls or drags in the plot with the mouse. FirstUseEver sets the limits the - // first time the plot is drawn, but the user can then modify them and the change - // will stick. - Condition::Always, - ) - .y_limits( - &ImPlotRange { - Min: y_min, - Max: y_max, - }, - YAxisChoice::First, - Condition::Always, - ) - .x_ticks(&x_ticks, false) - .y_ticks_with_labels(YAxisChoice::First, &y_ticks, false) - // If any of these flag setting calls are omitted, the defaults are used. - .with_plot_flags(&plot_flags) - .with_x_axis_flags(&x_axis_flags) - .with_y_axis_flags(YAxisChoice::First, &y_axis_flags) - .build(plot_ui, || { - PlotLine::new("A line").plot(&vec![2.1, 2.9], &vec![1.1, 1.9]); - }); -} - -pub fn show_query_features_plot(ui: &Ui, plot_ui: &PlotUi) { - ui.text(im_str!( - "This header demos how to use the querying features." - )); - let content_width = ui.window_content_region_width(); - - // Create some containers for exfiltrating data from the closure below - let mut hover_pos: Option = None; - let mut plot_limits: Option = None; - let mut query_limits: Option = None; - - // Draw a plot - Plot::new("Plot querying") - .size(content_width, 300.0) - .x_limits(&ImPlotRange { Min: 0.0, Max: 5.0 }, Condition::FirstUseEver) - .y_limits( - &ImPlotRange { Min: 0.0, Max: 5.0 }, - YAxisChoice::First, - Condition::FirstUseEver, - ) - .with_plot_flags(&(PlotFlags::NONE | PlotFlags::QUERY)) - .build(plot_ui, || { - if is_plot_hovered() { - hover_pos = Some(get_plot_mouse_position(None)); - } - - if is_plot_queried() { - query_limits = Some(get_plot_query(None)); - } - plot_limits = Some(get_plot_limits(None)); - }); - - // 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!("Plot limits are {:#?}", limits)); - } - if let Some(query) = query_limits { - ui.text(im_str!("Query limits are {:#?}", query)); - } -} - -pub fn show_style_plot(ui: &Ui, plot_ui: &PlotUi) { - ui.text(im_str!( - "This header demos how to use the styling features." - )); - let content_width = ui.window_content_region_width(); - - // The style stack works the same as for other imgui things - we can push - // things to have them apply, then pop again to undo the change. In implot-rs, - // pushing returns a value on which we have to call .pop() later. Pushing - // variables can be done outside of plot calls as well. - let style = push_style_color(&PlotColorElement::PlotBg, 1.0, 1.0, 1.0, 0.2); - Plot::new("Style demo plot") - .size(content_width, 300.0) - .x_limits(&ImPlotRange { Min: 0.0, Max: 6.0 }, Condition::Always) - .y_limits( - &ImPlotRange { - Min: -1.0, - Max: 3.0, - }, - YAxisChoice::First, - Condition::Always, - ) - .with_plot_flags(&(PlotFlags::NONE)) - .with_y_axis_flags(YAxisChoice::First, &(AxisFlags::NONE)) - .build(plot_ui, || { - // Markers can be selected as shown here. The markers are internally represented - // as an u32, hence this calling style. - 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]); - // Calling pop() on the return value of the push above will undo the marker choice. - markerchoice.pop(); - - // Line weights can be set the same way, along with some other things - see - // the docs of StyleVar for more info. - 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); - }); - - style.pop(); -} - -pub fn show_colormaps_plot(ui: &Ui, plot_ui: &PlotUi) { - ui.text(im_str!("This header demos how to select colormaps.")); - let content_width = ui.window_content_region_width(); - - // Select a colormap from the presets. The presets are listed in the Colormap enum - // and usually have something from 9 to 11 colors in them, with the second number - // being the option to resample the colormap to a custom number of colors if picked - // higher than 1. - set_colormap_from_preset(Colormap::Plasma, 1); - - Plot::new("Colormap demo plot") - .size(content_width, 300.0) - .build(plot_ui, || { - (1..10) - .map(|x| x as f64 * 0.1) - .map(|x| PlotLine::new(&format!("{:3.3}", x)).plot(&vec![0.1, 0.9], &vec![x, x])) - .count(); - }); - - // One can also specify a colormap as a vector of RGBA colors. ImPlot uses ImVec4 for this, - // so we follow suit. Make sure to set the last number (w in ImVec4) to 1.0 to see anything - - // it's the alpha channel. - set_colormap_from_vec(vec![ - ImVec4 { - x: 0.9, - y: 0.9, - z: 0.0, - w: 1.0, - }, - ImVec4 { - x: 0.0, - y: 0.9, - z: 0.9, - w: 1.0, - }, - ]); - - Plot::new("Colormap demo plot #2") - .size(content_width, 300.0) - .build(plot_ui, || { - (1..10) - .map(|x| x as f64 * 0.1) - .map(|x| PlotLine::new(&format!("{:3.3}", x)).plot(&vec![0.1, 0.9], &vec![x, x])) - .count(); - }); - - // Colormaps are not pushed, they are simply set, because they don't stack or anything. - // We can reset to the default by just setting the "Standard" preset. - set_colormap_from_preset(Colormap::Standard, 0); -}