├── .gitattributes ├── .github └── workflows │ └── rust.yml ├── .gitignore ├── .gitmodules ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE ├── README.md ├── demo.png ├── implot-examples ├── README.md ├── examples-shared │ ├── Cargo.toml │ └── src │ │ ├── bar_plots.rs │ │ ├── heatmaps.rs │ │ ├── lib.rs │ │ ├── line_plots.rs │ │ ├── scatter_plots.rs │ │ ├── stairs_plots.rs │ │ ├── stem_plots.rs │ │ └── text_plots.rs ├── implot-glium-demo │ ├── Cargo.lock │ ├── Cargo.toml │ └── src │ │ ├── main.rs │ │ └── support │ │ ├── clipboard.rs │ │ └── mod.rs └── implot-wgpu-demo │ ├── Cargo.lock │ ├── Cargo.toml │ └── src │ ├── main.rs │ └── support │ ├── clipboard.rs │ └── mod.rs ├── implot-sys-bindgen ├── Cargo.toml ├── build.rs └── src │ └── main.rs ├── implot-sys ├── Cargo.toml ├── build.rs └── src │ ├── bindings.rs │ └── lib.rs └── src ├── context.rs ├── lib.rs ├── plot.rs └── plot_elements.rs /.gitattributes: -------------------------------------------------------------------------------- 1 | implot-sys/src/bindings.rs linguist-generated=true 2 | -------------------------------------------------------------------------------- /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | 4 | on: 5 | push: 6 | branches: [ master ] 7 | pull_request: 8 | branches: [ master ] 9 | 10 | env: 11 | CARGO_TERM_COLOR: always 12 | 13 | jobs: 14 | build: 15 | 16 | runs-on: ubuntu-latest 17 | 18 | steps: 19 | - uses: actions/checkout@v2 20 | with: 21 | submodules: "recursive" 22 | 23 | - name: Install dependencies 24 | run: sudo apt-get update && sudo apt-get install -y libxcb-shape0-dev libxcb-xfixes0-dev 25 | - name: Build 26 | run: cargo build --verbose 27 | - name: Run idiomatic bindings tests 28 | run: cargo test --verbose 29 | - name: Run FFI tests 30 | run: cd implot-sys/ && cargo test --verbose 31 | - name: Build glium demo 32 | run: cd implot-examples/implot-glium-demo && cargo build 33 | - name: Build wgpu demo 34 | run: cd implot-examples/implot-wgpu-demo && cargo build 35 | 36 | build-win: 37 | runs-on: windows-latest 38 | 39 | steps: 40 | - uses: actions/checkout@v2 41 | with: 42 | submodules: "recursive" 43 | - name: Install latest rust toolchain 44 | uses: actions-rs/toolchain@v1 45 | with: 46 | toolchain: stable 47 | default: true 48 | override: true 49 | - name: Build 50 | run: cargo build --verbose 51 | - name: Run idiomatic bindings tests 52 | run: cargo test --verbose 53 | - name: Run FFI tests 54 | run: cd implot-sys/ && cargo test --verbose 55 | - name: Build glium demo 56 | run: cd implot-examples/implot-glium-demo && cargo build 57 | - name: Build wgpu demo 58 | run: cd implot-examples/implot-wgpu-demo && cargo build 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | **/target/ 4 | 5 | # Editor temporary files 6 | **/*.swp 7 | 8 | # These are backup files generated by rustfmt 9 | **/*.rs.bk 10 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "implot-sys/third-party/cimplot"] 2 | path = implot-sys/third-party/cimplot 3 | url = https://github.com/cimgui/cimplot 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v0.6.0 4 | ### General notes 5 | * Updated imgui-rs dependency to 0.7 (credit: @kylc) 6 | * Examples: updated wgpu dependency to 0.10 and imgui-wgpu to 0.17 (credit: @kylc) 7 | 8 | ### API changes 9 | * None, but the minor version is increased anyway because I consider the 10 | updated imgui-rs dependency an API change. 11 | 12 | ## v0.5.0 13 | ### General notes 14 | * Changed to using imgui types from `imgui-rs`. This improves compatibility 15 | with other code that uses `imgui-rs` directly (help by: @a1ien) 16 | * Reduced bindings size considerably by include-listing types (help by: @a1ien) 17 | * Removed direct dependency on `lazy_static` (credit: @a1ien) 18 | * Changed `i8` to `char` where appropriate (credit: @birktj) 19 | * Updated bindgen dependency to 0.57 20 | 21 | ### API changes 22 | * `Plot::size` now takes a `[f32; 2]` argument instead of two separate `f32` values 23 | * Added conversions from `Range`, `[f64; 2]`, `(f64, f64)` and `ImVec2` to `ImPlotRange` 24 | (credit: @a1ien) 25 | * `Plot::x_limits` and `Plot::y_limits` now take an `Into` argument for the 26 | limits. Combined with the above conversions, there are now more flexible ways to specify 27 | limits. 28 | * There are now convenience functions for setting the Y axis limits for individual axes, called 29 | `Plot::y1_limits`, `Plot::y2_limits` and `Plot::y3_limits`. 30 | * There is now a feature to set linked Y limits - `Plot::linked_y_limits`, along with 31 | convenience functions for the individual axes. 32 | 33 | ## v0.4.0 34 | * Setting axis ratio 35 | * Other minor additions 36 | * Pinned imgui versions more tightly 37 | 38 | ## v0.3.0 39 | * Heatmap support 40 | * Doc aliases (for Rust 1.48 and newer) 41 | * Simple style setters 42 | 43 | ## v0.2.0 44 | * More API coverage and minor improvements 45 | * Minor API breaks from v0.1.0. 46 | 47 | ## v0.1.0 48 | * Added metadata to Cargo.toml 49 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "implot" 3 | version = "0.6.0" 4 | edition = "2018" 5 | authors = ["Sandro Merkli", "implot-rs contributors"] 6 | description = "Rust bindings to https://github.com/epezent/implot" 7 | homepage = "https://github.com/4bb4/implot-rs" 8 | repository = "https://github.com/4bb4/implot-rs" 9 | license = "MIT/Apache-2.0" 10 | categories = ["gui", "api-bindings"] 11 | readme = "README.md" 12 | 13 | [dependencies] 14 | implot-sys = { version = "0.6.0", path = "implot-sys" } 15 | imgui = { version = "0.8.0" } 16 | bitflags = "1.0" 17 | parking_lot = "0.11" 18 | rustversion = "1.0.4" 19 | 20 | 21 | [workspace] 22 | members = [ 23 | "implot-sys", 24 | ] 25 | exclude = [ 26 | "implot-sys-bindgen", 27 | "implot-examples", 28 | "implot-wgpu-examples", 29 | ] 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # implot-rs 3 | 4 | Rust bindings for [ImPlot](https://github.com/epezent/implot), built by running 5 | [bindgen](https://github.com/rust-lang/rust-bindgen) on [cimplot](https://github.com/cimgui/cimplot). 6 | 7 | The bindings are currently based on ImPlot version 0.9-WIP (see 8 | [implot-sys/third-party](implot-sys/third-party) for the exact commit currently pointed to). 9 | The status section below provides detailed information on implementation status. 10 | 11 | [![Docs.rs documentation](https://docs.rs/implot/badge.svg)](https://docs.rs/implot/) 12 | ![Tests](https://github.com/4bb4/implot-rs/workflows/Tests/badge.svg) 13 | 14 | **Important note:** As long as the code is pre-1.0 release, the API is expected to have 15 | breaking changes between minor versions. Patch versions should be backwards compatible. 16 | After 1.0, semver will be followed more properly. 17 | 18 | ![demo](demo.png) 19 | 20 | ## Requirements 21 | imgui-rs requires minimum Rust version 1.40, so this project requires at least that. 22 | The sys crate compiles implot, so a C++ compiler will also be required. 23 | 24 | ## Examples 25 | Examples are being built in the `implot-examples` crate in this repo. To try them out, 26 | clone the repo, change into the `implot-examples` directory and try for example 27 | ``` 28 | cargo run --example line_plots 29 | ``` 30 | 31 | ## Documentation 32 | For released versions, see 33 | [![Docs.rs documentation](https://docs.rs/implot/badge.svg)](https://docs.rs/implot/). 34 | Make sure to look at the right release, since the API is still changing. 35 | For the master branch, the docs can be built by cloning this repository and then running 36 | ``` 37 | cargo doc --open 38 | ``` 39 | An effort is made to document everything as it is being added. Feel free to open an issue 40 | if documentation is unclear or lacking. Note that doc aliases are being added now, which 41 | means one should be able to look for things with the name they have in the C++ code and 42 | rustdoc should show the correspondingly-named item. Sometimes this is just a matter of 43 | changing camelcase to snake case, other times the idiomatic bindings do things a bit 44 | differently. These aliases only work with Rust 1.48 or newer. 45 | 46 | ## Implementation status 47 | Currently a work in progress, coverage of the C++ API is increased steadily. The author 48 | is open to collaboration, if you'd like to help, feel free to reach out via a Github issue. 49 | 50 | At this point, raw bindings are working in implot-sys, and more idiomatic interfaces 51 | for plot creation as well a subset of the functionality for plots are implemented. 52 | 53 | While the raw bindings have versions of most functions for different data types such as 54 | 32-bit or 64-bit floats and various integers, the higher-level bindings are currently only 55 | created for 64-bit floats. 56 | 57 | - [x] "BeginPlot" 58 | - [x] Basic hello world 59 | - [x] Plot flags 60 | - [ ] Plotting functionality 61 | - [x] Line plot 62 | - [x] Text plot 63 | - [x] Scatter plot 64 | - [x] Bar plot 65 | - [x] Vertical 66 | - [x] Horizontal 67 | - [x] Stairs plot 68 | - [x] Heatmap 69 | - [ ] Shaded plot 70 | - [ ] Stem plots 71 | - [ ] Images 72 | - [ ] Error bar plot 73 | - [ ] Vertical 74 | - [ ] Horizontal 75 | - [ ] Pie chart 76 | - [ ] Digital data 77 | - [ ] Annotations 78 | - [ ] Dragline 79 | - [ ] Dragpoint 80 | - [x] Plot customization 81 | - [x] Axis flags 82 | - [x] Styling colors 83 | - [x] Styling variables 84 | - [x] Colormaps 85 | - [x] Legend locations 86 | - [x] Plot querying 87 | - [x] is hovered 88 | - [x] mouse position in plot 89 | - [x] plot limits 90 | - [x] is queried 91 | - [x] get plot query 92 | - [x] are axes hovered 93 | - [x] Choice of y axis 94 | - [x] Are legend entries hovered 95 | - [ ] Utils 96 | - [x] Plot limit setting 97 | - [x] imgui-rs style safe push/pop stacks 98 | - [x] Plot tick setting 99 | - [x] Pixel to plot position 100 | - [x] Plot to pixel position 101 | - [x] Set Y axis setting for subsequent elements 102 | - [ ] Input remapping 103 | - [ ] Set non-default Y axis ticks and labels 104 | - [ ] Plot position and size reading 105 | - [ ] Push/pop plotclip rect (?) 106 | 107 | # Developer documentation 108 | ## Design approach 109 | This repo tries to follow the approaches and style used in `imgui-rs` somewhat closely, 110 | because implot is to be used within imgui programs, and hence keeping the interfaces 111 | and design philosophies close should make it easier to do that. 112 | 113 | If you spot any design inconsistencies or paper cuts, feel free to open an issue. 114 | -------------------------------------------------------------------------------- /demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4bb4/implot-rs/cdd38884468c234b33e5af302e60d70401e33bef/demo.png -------------------------------------------------------------------------------- /implot-examples/README.md: -------------------------------------------------------------------------------- 1 | # Examples 2 | 3 | This folder contains examples that demonstrate how to use the Rust bindings. 4 | Things are structured as follows: 5 | 6 | * [examples-shared](examples-shared/) is a library crate that contains the actual usage 7 | examples. It is used in the backend-specific crates. 8 | * [implot-glium-demo](implot-glium-demo/) is an example for using `implot-rs` in 9 | conjunction with a [Glium](https://github.com/glium/glium) backend. 10 | * [implot-wgpu-demo](implot-wgpu-demo/) is an example for using `implot-rs` in 11 | conjunction with a [WebGPU](https://github.com/gfx-rs/wgpu) backend 12 | 13 | If you want to just copy-paste code to start with, copy `examples-shared` along with 14 | your favourite backend example crate. The glium backend code is largely taken from imgui-rs. 15 | -------------------------------------------------------------------------------- /implot-examples/examples-shared/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "examples-shared" 3 | version = "0.1.0" 4 | authors = ["4bb4 <67376761+4bb4@users.noreply.github.com>"] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | implot = { path = "../../" } 11 | imgui = "0.8.0" 12 | -------------------------------------------------------------------------------- /implot-examples/examples-shared/src/bar_plots.rs: -------------------------------------------------------------------------------- 1 | //! This example demonstrates how bar plots are to be used. For more general 2 | //! features of the libray, see the line_plots example. 3 | 4 | use imgui::{CollapsingHeader, Ui}; 5 | use implot::{Plot, PlotBars, PlotUi}; 6 | 7 | pub fn show_basic_vertical_plot(ui: &Ui, plot_ui: &PlotUi) { 8 | ui.text("This header shows a simple vertical bar plot."); 9 | let content_width = ui.window_content_region_width(); 10 | Plot::new("Vertical bar plot") 11 | // The size call could also be omitted, though the defaults don't consider window 12 | // width, which is why we're not doing so here. 13 | .size([content_width, 300.0]) 14 | .build(plot_ui, || { 15 | // If this is called outside a plot build callback, the program will panic. 16 | let axis_positions = vec![0.2, 0.4, 0.6, 0.8]; 17 | let values = vec![0.1, 0.2, 0.3, 0.4]; 18 | PlotBars::new("legend label") 19 | .with_bar_width(0.1) 20 | .plot(&axis_positions, &values); 21 | }); 22 | } 23 | 24 | pub fn show_basic_horizontal_plot(ui: &Ui, plot_ui: &PlotUi) { 25 | ui.text("This header shows a simple horizontal bar plot."); 26 | let content_width = ui.window_content_region_width(); 27 | Plot::new("Horizontal bar plot") 28 | // The size call could also be omitted, though the defaults don't consider window 29 | // width, which is why we're not doing so here. 30 | .size([content_width, 300.0]) 31 | .build(plot_ui, || { 32 | // If this is called outside a plot build callback, the program will panic. 33 | let axis_positions = vec![0.2, 0.4, 0.6, 0.8]; 34 | let values = vec![0.1, 0.2, 0.3, 0.4]; 35 | PlotBars::new("legend label") 36 | .with_bar_width(0.05) 37 | .with_horizontal_bars() 38 | .plot(&axis_positions, &values); 39 | }); 40 | } 41 | 42 | pub fn show_demo_headers(ui: &Ui, plot_ui: &PlotUi) { 43 | if CollapsingHeader::new("Bar plots: Basic vertical").build(ui) { 44 | show_basic_vertical_plot(ui, plot_ui); 45 | } 46 | if CollapsingHeader::new("Bar plots: Basic horizontal").build(ui) { 47 | show_basic_horizontal_plot(ui, plot_ui); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /implot-examples/examples-shared/src/heatmaps.rs: -------------------------------------------------------------------------------- 1 | //! This example demonstrates how heatmaps are to be used. For more general 2 | //! features of the libray, see the line_plots example. 3 | 4 | use imgui::{CollapsingHeader, Ui}; 5 | use implot::{ImPlotPoint, Plot, PlotHeatmap, PlotUi}; 6 | 7 | pub fn show_basic_heatmap(ui: &Ui, plot_ui: &PlotUi) { 8 | ui.text("This header shows a simple heatmap"); 9 | let content_width = ui.window_content_region_width(); 10 | Plot::new("Heatmap plot") 11 | // The size call could also be omitted, though the defaults don't consider window 12 | // width, which is why we're not doing so here. 13 | .size([content_width, 300.0]) 14 | .build(plot_ui, || { 15 | let values = (0..100).map(|x| 0.1 * x as f64).collect::>(); 16 | PlotHeatmap::new("my favourite heatmap") 17 | // If you omit the with_scale call, the range will be computed based on the values 18 | .with_scale(0.0, 10.0) 19 | .with_drawing_area( 20 | ImPlotPoint { x: -1.0, y: -1.0 }, 21 | ImPlotPoint { x: 1.0, y: 1.0 }, 22 | ) 23 | .plot(&values, 10, 10); 24 | }); 25 | } 26 | 27 | pub fn show_demo_headers(ui: &Ui, plot_ui: &PlotUi) { 28 | if CollapsingHeader::new("Heatmap: Basic").build(ui) { 29 | show_basic_heatmap(ui, plot_ui); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /implot-examples/examples-shared/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod bar_plots; 2 | pub mod heatmaps; 3 | pub mod line_plots; 4 | pub mod scatter_plots; 5 | pub mod stairs_plots; 6 | mod stem_plots; 7 | pub mod text_plots; 8 | 9 | use imgui::{Condition, Ui, Window}; 10 | use implot::PlotUi; 11 | 12 | /// State of the demo code 13 | pub struct DemoState { 14 | /// State of the line plots demo 15 | line_plots: line_plots::LinePlotDemoState, 16 | } 17 | 18 | impl DemoState { 19 | /// Create a new demo code state object with default values in it. 20 | pub fn new() -> Self { 21 | Self { 22 | line_plots: line_plots::LinePlotDemoState::new(), 23 | } 24 | } 25 | 26 | /// Show all the demos 27 | pub fn show_demos(&mut self, ui: &Ui, plot_ui: &PlotUi) { 28 | // Most of the demos are currently still stateless, so the code here mostly just calls into 29 | // the modules. The line plots demo is stateful though. Things will be refactored soon to 30 | // make all the individual demos stateful to unify things more. 31 | Window::new("implot-rs demo") 32 | .size([430.0, 450.0], Condition::FirstUseEver) 33 | .build(ui, || { 34 | ui.text("Hello from implot-rs!"); 35 | ui.text_wrapped( 36 | "The headers here demo the plotting features of the library.\ 37 | Have a look at the example source code to see how they are implemented.\n\ 38 | Check out the demo from ImPlot itself first for instructions on how to\ 39 | interact with ImPlot plots.", 40 | ); 41 | 42 | ui.separator(); 43 | ui.text("Bar plots:"); 44 | bar_plots::show_demo_headers(ui, plot_ui); 45 | 46 | ui.separator(); 47 | ui.text("Line plots:"); 48 | // The line plots demo is stateful 49 | self.line_plots.show_demo_headers(ui, plot_ui); 50 | 51 | ui.separator(); 52 | ui.text("Scatter plots:"); 53 | scatter_plots::show_demo_headers(ui, plot_ui); 54 | 55 | ui.separator(); 56 | ui.text("Text plots:"); 57 | text_plots::show_demo_headers(ui, plot_ui); 58 | 59 | ui.separator(); 60 | ui.text("Stairs plots:"); 61 | stairs_plots::show_demo_headers(ui, plot_ui); 62 | 63 | ui.separator(); 64 | ui.text("Heatmaps:"); 65 | heatmaps::show_demo_headers(ui, plot_ui); 66 | 67 | ui.separator(); 68 | ui.text("Stem plots:"); 69 | stem_plots::show_demo_headers(ui, plot_ui); 70 | }); 71 | } 72 | } 73 | 74 | impl Default for DemoState { 75 | fn default() -> Self { 76 | Self::new() 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /implot-examples/examples-shared/src/line_plots.rs: -------------------------------------------------------------------------------- 1 | //! This example demonstrates how line plots are to be used, along with some querying features 2 | //! that will be applicable to all kinds of plots. 3 | 4 | use imgui::{CollapsingHeader, Condition, Ui}; 5 | use implot::{ 6 | get_plot_limits, get_plot_mouse_position, get_plot_query, is_legend_entry_hovered, 7 | is_plot_hovered, is_plot_queried, pixels_to_plot_vec2, plot_to_pixels_vec2, push_style_color, 8 | push_style_var_f32, push_style_var_i32, set_colormap_from_preset, set_colormap_from_vec, 9 | set_plot_y_axis, AxisFlags, Colormap, ImPlotLimits, ImPlotPoint, ImPlotRange, ImVec2, ImVec4, 10 | Marker, Plot, PlotColorElement, PlotFlags, PlotLine, PlotLocation, PlotOrientation, PlotUi, 11 | StyleVar, YAxisChoice, 12 | }; 13 | 14 | use std::{cell::RefCell, rc::Rc}; 15 | 16 | /// State of the line plots demo. 17 | pub struct LinePlotDemoState { 18 | linked_limits: Rc>, 19 | } 20 | 21 | impl LinePlotDemoState { 22 | /// Create a new line plots demo state object with default values in it. 23 | pub fn new() -> Self { 24 | Self { 25 | linked_limits: Rc::new(RefCell::new(ImPlotRange { Min: 0.0, Max: 1.0 })), 26 | } 27 | } 28 | 29 | pub fn show_basic_plot(ui: &Ui, plot_ui: &PlotUi) { 30 | ui.text("This header just plots a line with as little code as possible."); 31 | let content_width = ui.window_content_region_width(); 32 | Plot::new("Simple line plot") 33 | // The size call could also be omitted, though the defaults don't consider window 34 | // width, which is why we're not doing so here. 35 | .size([content_width, 300.0]) 36 | .build(plot_ui, || { 37 | // If this is called outside a plot build callback, the program will panic. 38 | let x_positions = vec![0.1, 0.9]; 39 | let y_positions = vec![0.1, 0.9]; 40 | PlotLine::new("legend label").plot(&x_positions, &y_positions); 41 | }); 42 | } 43 | 44 | pub fn show_two_yaxis_plot(ui: &Ui, plot_ui: &PlotUi) { 45 | ui.text("This header shows how to create a plot with multiple Y axes."); 46 | let content_width = ui.window_content_region_width(); 47 | Plot::new("Multiple Y axis plots") 48 | // The size call could also be omitted, though the defaults don't consider window 49 | // width, which is why we're not doing so here. 50 | .size([content_width, 300.0]) 51 | .with_plot_flags(&(PlotFlags::NONE | PlotFlags::Y_AXIS_2)) 52 | .y_limits( 53 | ImPlotRange { Min: 0.0, Max: 1.0 }, 54 | YAxisChoice::First, 55 | Condition::Always, 56 | ) 57 | .y_limits( 58 | // One can also use [f32; 2], (f32, f32) and ImVec2 for limit setting 59 | [1.0, 3.5], 60 | YAxisChoice::Second, 61 | Condition::Always, 62 | ) 63 | .build(plot_ui, || { 64 | let x_positions = vec![0.1, 0.9]; 65 | 66 | // The first Y axis is the default 67 | let y_positions = vec![0.1, 0.9]; 68 | PlotLine::new("legend label").plot(&x_positions, &y_positions); 69 | 70 | // Now we switch to the second axis for the next call 71 | set_plot_y_axis(YAxisChoice::Second); 72 | let y_positions = vec![3.3, 1.2]; 73 | PlotLine::new("legend label two").plot(&x_positions, &y_positions); 74 | }); 75 | } 76 | 77 | pub fn show_axis_equal_plot(ui: &Ui, plot_ui: &PlotUi) { 78 | ui.text("This plot has axis equal set (1:1 aspect ratio)."); 79 | let content_width = ui.window_content_region_width(); 80 | Plot::new("Axis equal line plot") 81 | // The size call could also be omitted, though the defaults don't consider window 82 | // width, which is why we're not doing so here. 83 | .size([content_width, 300.0]) 84 | .with_plot_flags(&(PlotFlags::NONE | PlotFlags::AXIS_EQUAL)) 85 | .build(plot_ui, || { 86 | // If this is called outside a plot build callback, the program will panic. 87 | let x_positions = vec![0.1, 0.9]; 88 | let y_positions = vec![0.1, 0.9]; 89 | PlotLine::new("legend label").plot(&x_positions, &y_positions); 90 | }); 91 | } 92 | 93 | pub fn show_configurable_plot(ui: &Ui, plot_ui: &PlotUi) { 94 | ui.text("This header demos what we can configure about plots."); 95 | 96 | // Settings for the plot 97 | // - X and Y size in pixels 98 | let x_size = 300.0; 99 | let y_size = 200.0; 100 | // - Strings for the axis labels 101 | let x_label = "X label!"; 102 | let y_label = "Y label!"; 103 | // - Plot limits 104 | let x_min = 2.0; 105 | let x_max = 3.0; 106 | let y_min = 1.0; 107 | let y_max = 2.0; 108 | // - Plot flags, see the PlotFlags docs for more info 109 | let plot_flags = PlotFlags::NONE; 110 | // - Axis flags, see the AxisFlags docs for more info. All flags are bitflags-created, 111 | // so they support a bunch of convenient operations, see https://docs.rs/bitflags 112 | let x_axis_flags = AxisFlags::NONE; 113 | let y_axis_flags = AxisFlags::NONE; 114 | 115 | // - Unlabelled X axis ticks 116 | let x_ticks = vec![2.2, 2.5, 2.8]; 117 | 118 | // - Labelled Y axis ticks 119 | let y_ticks = vec![(1.1, "A".to_owned()), (1.4, "B".to_owned())]; 120 | 121 | // Axis labels 122 | Plot::new("Configured line plot") 123 | .size([x_size, y_size]) 124 | .x_label(x_label) 125 | .y_label(y_label) 126 | .x_limits( 127 | ImPlotRange { 128 | Min: x_min, 129 | Max: x_max, 130 | }, 131 | // Always means that the limits stay what we force them to here, even if the user 132 | // scrolls or drags in the plot with the mouse. FirstUseEver sets the limits the 133 | // first time the plot is drawn, but the user can then modify them and the change 134 | // will stick. 135 | Condition::Always, 136 | ) 137 | .y_limits( 138 | ImPlotRange { 139 | Min: y_min, 140 | Max: y_max, 141 | }, 142 | YAxisChoice::First, 143 | Condition::Always, 144 | ) 145 | .x_ticks(&x_ticks, false) 146 | .y_ticks_with_labels(YAxisChoice::First, &y_ticks, false) 147 | // If any of these flag setting calls are omitted, the defaults are used. 148 | .with_plot_flags(&plot_flags) 149 | .with_x_axis_flags(&x_axis_flags) 150 | .with_y_axis_flags(YAxisChoice::First, &y_axis_flags) 151 | .with_legend_location(&PlotLocation::West, &PlotOrientation::Horizontal, true) 152 | .build(plot_ui, || { 153 | PlotLine::new("A line 2").plot(&[2.4, 2.9], &[1.1, 1.9]); 154 | }); 155 | } 156 | 157 | pub fn show_query_features_plot(ui: &Ui, plot_ui: &PlotUi) { 158 | ui.text("This header demos how to use the querying features."); 159 | let content_width = ui.window_content_region_width(); 160 | 161 | // Create some containers for exfiltrating data from the closure below 162 | let mut hover_pos_plot: Option = None; 163 | let mut hover_pos_pixels: Option = None; 164 | let mut hover_pos_from_pixels: Option = None; 165 | let mut plot_limits: Option = None; 166 | let mut query_limits: Option = None; 167 | let mut legend1_hovered = false; 168 | let mut legend2_hovered = false; 169 | 170 | // Draw a plot 171 | Plot::new("Plot querying") 172 | .size([content_width, 300.0]) 173 | .x_limits(ImPlotRange { Min: 0.0, Max: 5.0 }, Condition::FirstUseEver) 174 | .y_limits( 175 | ImPlotRange { Min: 0.0, Max: 5.0 }, 176 | YAxisChoice::First, 177 | Condition::FirstUseEver, 178 | ) 179 | .with_plot_flags(&(PlotFlags::NONE | PlotFlags::QUERY)) 180 | .build(plot_ui, || { 181 | if is_plot_hovered() { 182 | hover_pos_plot = Some(get_plot_mouse_position(None)); 183 | hover_pos_pixels = Some(plot_to_pixels_vec2(&(hover_pos_plot.unwrap()), None)); 184 | } 185 | 186 | // Getting the plot position from pixels also works when the plot is not hovered, 187 | // the coordinates are then simply outside the visible range. 188 | hover_pos_from_pixels = Some(pixels_to_plot_vec2( 189 | &ImVec2 { 190 | x: ui.io().mouse_pos[0], 191 | y: ui.io().mouse_pos[1], 192 | }, 193 | None, 194 | )); 195 | 196 | // Plot a line so we have a legend entry 197 | PlotLine::new("Legend1").plot(&[2.0, 2.0], &[2.0, 1.0]); 198 | PlotLine::new("Legend2").plot(&[0.0, 0.0], &[1.0, 1.0]); 199 | legend1_hovered = is_legend_entry_hovered("Legend1"); 200 | legend2_hovered = is_legend_entry_hovered("Legend2"); 201 | 202 | if is_plot_queried() { 203 | query_limits = Some(get_plot_query(None)); 204 | } 205 | plot_limits = Some(get_plot_limits(None)); 206 | }); 207 | 208 | // Print some previously-exfiltrated info. This is because calling 209 | // things like is_plot_hovered or get_plot_mouse_position() outside 210 | // of an actual Plot is not allowed. 211 | if let Some(pos) = hover_pos_plot { 212 | ui.text(format!("hovered at {}, {}", pos.x, pos.y)); 213 | } 214 | if let Some(pixel_position) = hover_pos_pixels { 215 | // Try out converting plot mouse position to pixel position 216 | ui.text(format!( 217 | "pixel pos from plot: {}, {}", 218 | pixel_position.x, pixel_position.y 219 | )); 220 | ui.text(format!( 221 | "pixel pos from imgui: {}, {}", 222 | ui.io().mouse_pos[0], 223 | ui.io().mouse_pos[1] 224 | )); 225 | } 226 | if let Some(limits) = plot_limits { 227 | ui.text(format!("Plot limits are {:#?}", limits)); 228 | } 229 | if let Some(query) = query_limits { 230 | ui.text(format!("Query limits are {:#?}", query)); 231 | } 232 | ui.text(format!( 233 | "Legend hovering - 1: {}, 2: {}", 234 | legend1_hovered, legend2_hovered 235 | )); 236 | 237 | // Try out converting pixel position to plot position 238 | if let Some(pos) = hover_pos_from_pixels { 239 | ui.text(format!("plot pos from imgui: {}, {}", pos.x, pos.y,)); 240 | } 241 | } 242 | 243 | pub fn show_style_plot(ui: &Ui, plot_ui: &PlotUi) { 244 | ui.text("This header demos how to use the styling features."); 245 | let content_width = ui.window_content_region_width(); 246 | 247 | // The style stack works the same as for other imgui things - we can push 248 | // things to have them apply, then pop again to undo the change. In implot-rs, 249 | // pushing returns a value on which we have to call .pop() later. Pushing 250 | // variables can be done outside of plot calls as well. 251 | let style = push_style_color(&PlotColorElement::PlotBg, 1.0, 1.0, 1.0, 0.2); 252 | Plot::new("Style demo plot") 253 | .size([content_width, 300.0]) 254 | .x_limits(ImPlotRange { Min: 0.0, Max: 6.0 }, Condition::Always) 255 | .y_limits( 256 | ImPlotRange { 257 | Min: -1.0, 258 | Max: 3.0, 259 | }, 260 | YAxisChoice::First, 261 | Condition::Always, 262 | ) 263 | .with_plot_flags(&(PlotFlags::NONE)) 264 | .with_y_axis_flags(YAxisChoice::First, &(AxisFlags::NONE)) 265 | .build(plot_ui, || { 266 | // Markers can be selected as shown here. The markers are internally represented 267 | // as an u32, hence this calling style. 268 | let markerchoice = push_style_var_i32(&StyleVar::Marker, Marker::Cross as i32); 269 | PlotLine::new("Left eye").plot(&[2.0, 2.0], &[2.0, 1.0]); 270 | // Calling pop() on the return value of the push above will undo the marker choice. 271 | markerchoice.pop(); 272 | 273 | // Line weights can be set the same way, along with some other things - see 274 | // the docs of StyleVar for more info. 275 | let lineweight = push_style_var_f32(&StyleVar::LineWeight, 5.0); 276 | PlotLine::new("Right eye").plot(&[4.0, 4.0], &[2.0, 1.0]); 277 | lineweight.pop(); 278 | 279 | let x_values = vec![1.0, 2.0, 4.0, 5.0]; 280 | let y_values = vec![1.0, 0.0, 0.0, 1.0]; 281 | PlotLine::new("Mouth").plot(&x_values, &y_values); 282 | }); 283 | 284 | style.pop(); 285 | } 286 | 287 | pub fn show_colormaps_plot(ui: &Ui, plot_ui: &PlotUi) { 288 | ui.text("This header demos how to select colormaps."); 289 | let content_width = ui.window_content_region_width(); 290 | 291 | // Select a colormap from the presets. The presets are listed in the Colormap enum 292 | // and usually have something from 9 to 11 colors in them, with the second number 293 | // being the option to resample the colormap to a custom number of colors if picked 294 | // higher than 1. 295 | set_colormap_from_preset(Colormap::Plasma, 1); 296 | 297 | Plot::new("Colormap demo plot") 298 | .size([content_width, 300.0]) 299 | .build(plot_ui, || { 300 | (1..10) 301 | .map(|x| x as f64 * 0.1) 302 | .map(|x| PlotLine::new(&format!("{:3.3}", x)).plot(&[0.1, 0.9], &[x, x])) 303 | .count(); 304 | }); 305 | 306 | // One can also specify a colormap as a vector of RGBA colors. ImPlot uses ImVec4 for this, 307 | // so we follow suit. Make sure to set the last number (w in ImVec4) to 1.0 to see anything - 308 | // it's the alpha channel. 309 | set_colormap_from_vec(vec![ 310 | ImVec4 { 311 | x: 0.9, 312 | y: 0.9, 313 | z: 0.0, 314 | w: 1.0, 315 | }, 316 | ImVec4 { 317 | x: 0.0, 318 | y: 0.9, 319 | z: 0.9, 320 | w: 1.0, 321 | }, 322 | ]); 323 | 324 | Plot::new("Colormap demo plot #2") 325 | .size([content_width, 300.0]) 326 | .build(plot_ui, || { 327 | (1..10) 328 | .map(|x| x as f64 * 0.1) 329 | .map(|x| PlotLine::new(&format!("{:3.3}", x)).plot(&[0.1, 0.9], &[x, x])) 330 | .count(); 331 | }); 332 | 333 | // Colormaps are not pushed, they are simply set, because they don't stack or anything. 334 | // We can reset to the default by just setting the "Standard" preset. 335 | set_colormap_from_preset(Colormap::Standard, 0); 336 | } 337 | 338 | pub fn show_conversions_plot(ui: &Ui, plot_ui: &PlotUi) { 339 | ui.text("This header demonstrates (in code) how to convert various ranges into ImRange"); 340 | let content_width = ui.window_content_region_width(); 341 | Plot::new("Simple line plot, conversion 1") 342 | .size([content_width, 300.0]) 343 | .x_limits(ImVec2 { x: 0.0, y: 1.0 }, Condition::Always) 344 | .y_limits([0.0, 1.0], YAxisChoice::First, Condition::Always) 345 | .build(plot_ui, || { 346 | // If this is called outside a plot build callback, the program will panic. 347 | let x_positions = vec![0.1, 0.9]; 348 | let y_positions = vec![0.1, 0.9]; 349 | PlotLine::new("legend label").plot(&x_positions, &y_positions); 350 | }); 351 | } 352 | 353 | pub fn show_linked_x_axis_plots(&mut self, ui: &Ui, plot_ui: &PlotUi) { 354 | ui.text("These plots have their X axes linked, but not the Y axes"); 355 | let content_width = ui.window_content_region_width(); 356 | Plot::new("Linked plot 1") 357 | .size([content_width, 300.0]) 358 | .linked_x_limits(self.linked_limits.clone()) 359 | .build(plot_ui, || { 360 | let x_positions = vec![0.1, 0.9]; 361 | let y_positions = vec![0.1, 0.9]; 362 | PlotLine::new("legend label").plot(&x_positions, &y_positions); 363 | }); 364 | Plot::new("Linked plot 2") 365 | .size([content_width, 300.0]) 366 | .linked_x_limits(self.linked_limits.clone()) 367 | .build(plot_ui, || { 368 | let x_positions = vec![0.1, 0.9]; 369 | let y_positions = vec![0.1, 0.9]; 370 | PlotLine::new("legend label").plot(&x_positions, &y_positions); 371 | }); 372 | } 373 | 374 | pub fn show_demo_headers(&mut self, ui: &Ui, plot_ui: &PlotUi) { 375 | if CollapsingHeader::new("Line plot: Basic").build(ui) { 376 | Self::show_basic_plot(ui, plot_ui); 377 | } 378 | if CollapsingHeader::new("Line plot: Configured").build(ui) { 379 | Self::show_configurable_plot(ui, plot_ui); 380 | } 381 | if CollapsingHeader::new("Line Plot: Plot queries").build(ui) { 382 | Self::show_query_features_plot(ui, plot_ui); 383 | } 384 | if CollapsingHeader::new("Line plot: Plot styling").build(ui) { 385 | Self::show_style_plot(ui, plot_ui); 386 | } 387 | if CollapsingHeader::new("Line plot: Colormaps").build(ui) { 388 | Self::show_colormaps_plot(ui, plot_ui); 389 | } 390 | if CollapsingHeader::new("Line plot: Multiple Y Axes").build(ui) { 391 | Self::show_two_yaxis_plot(ui, plot_ui); 392 | } 393 | if CollapsingHeader::new("Line plot: \"Axis equal\"").build(ui) { 394 | Self::show_axis_equal_plot(ui, plot_ui); 395 | } 396 | if CollapsingHeader::new("Line plot: Range conversions").build(ui) { 397 | Self::show_conversions_plot(ui, plot_ui); 398 | } 399 | if CollapsingHeader::new("Line plot: Linked plots").build(ui) { 400 | self.show_linked_x_axis_plots(ui, plot_ui); 401 | } 402 | } 403 | } 404 | 405 | impl Default for LinePlotDemoState { 406 | fn default() -> Self { 407 | Self::new() 408 | } 409 | } 410 | -------------------------------------------------------------------------------- /implot-examples/examples-shared/src/scatter_plots.rs: -------------------------------------------------------------------------------- 1 | //! This example demonstrates how scatter plots are to be used. For more general 2 | //! features of the libray, see the line_plots example. 3 | 4 | use imgui::{CollapsingHeader, Ui}; 5 | use implot::{push_style_var_f32, push_style_var_i32, Marker, Plot, PlotScatter, PlotUi, StyleVar}; 6 | 7 | pub fn show_basic_plot(ui: &Ui, plot_ui: &PlotUi) { 8 | ui.text("This header just draws a scatter plot with as little code as possible."); 9 | let content_width = ui.window_content_region_width(); 10 | Plot::new("Simple scatter plot") 11 | // The size call could also be omitted, though the defaults don't consider window 12 | // width, which is why we're not doing so here. 13 | .size([content_width, 300.0]) 14 | .build(plot_ui, || { 15 | // If this is called outside a plot build callback, the program will panic. 16 | let x_positions = vec![0.1, 0.2, 0.1, 0.5, 0.9]; 17 | let y_positions = vec![0.1, 0.1, 0.3, 0.3, 0.9]; 18 | PlotScatter::new("legend label").plot(&x_positions, &y_positions); 19 | }); 20 | } 21 | 22 | pub fn show_custom_markers_plot(ui: &Ui, plot_ui: &PlotUi) { 23 | ui.text("This header shows how markers can be used in scatter plots."); 24 | let content_width = ui.window_content_region_width(); 25 | Plot::new("Multi-marker scatter plot") 26 | // The size call could also be omitted, though the defaults don't consider window 27 | // width, which is why we're not doing so here. 28 | .size([content_width, 300.0]) 29 | .build(plot_ui, || { 30 | // Change to cross marker for one scatter plot call 31 | let x_positions = vec![0.1, 0.2, 0.1, 0.5, 0.9]; 32 | let y_positions = vec![0.1, 0.1, 0.3, 0.3, 0.9]; 33 | let markerchoice = push_style_var_i32(&StyleVar::Marker, Marker::Cross as i32); 34 | PlotScatter::new("legend label 1").plot(&x_positions, &y_positions); 35 | markerchoice.pop(); 36 | 37 | // One can combine things like marker size and markor choice 38 | let x_positions = vec![0.4, 0.1]; 39 | let y_positions = vec![0.5, 0.3]; 40 | let marker_choice = push_style_var_i32(&StyleVar::Marker, Marker::Diamond as i32); 41 | let marker_size = push_style_var_f32(&StyleVar::MarkerSize, 12.0); 42 | PlotScatter::new("legend label 2").plot(&x_positions, &y_positions); 43 | 44 | // TODO(4bb4) check if these have to be in reverse push order. Does not 45 | // seem to be the case. 46 | marker_size.pop(); 47 | marker_choice.pop(); 48 | }); 49 | } 50 | 51 | pub fn show_demo_headers(ui: &Ui, plot_ui: &PlotUi) { 52 | if CollapsingHeader::new("Basic scatter plot").build(ui) { 53 | show_basic_plot(ui, plot_ui); 54 | } 55 | 56 | if CollapsingHeader::new("Custom markers").build(ui) { 57 | show_custom_markers_plot(ui, plot_ui); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /implot-examples/examples-shared/src/stairs_plots.rs: -------------------------------------------------------------------------------- 1 | //! This example demonstrates how stairs plots are to be used. They are almost the same as line 2 | //! plots, so head over to the line plots example for more info. 3 | //! 4 | use imgui::{CollapsingHeader, Ui}; 5 | use implot::{Plot, PlotStairs, PlotUi}; 6 | 7 | pub fn show_basic_plot(ui: &Ui, plot_ui: &PlotUi) { 8 | ui.text_wrapped("This header just plots a stairs-style line with as little code as possible."); 9 | let content_width = ui.window_content_region_width(); 10 | Plot::new("Simple stairs plot") 11 | // The size call could also be omitted, though the defaults don't consider window 12 | // width, which is why we're not doing so here. 13 | .size([content_width, 300.0]) 14 | .build(plot_ui, || { 15 | // If this is called outside a plot build callback, the program will panic. 16 | let x_positions = vec![0.1, 0.2, 0.5]; 17 | let y_positions = vec![0.1, 0.3, 0.9]; 18 | PlotStairs::new("legend label").plot(&x_positions, &y_positions); 19 | }); 20 | } 21 | 22 | pub fn show_demo_headers(ui: &Ui, plot_ui: &PlotUi) { 23 | if CollapsingHeader::new("Stairs plot: Basic").build(ui) { 24 | show_basic_plot(ui, plot_ui); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /implot-examples/examples-shared/src/stem_plots.rs: -------------------------------------------------------------------------------- 1 | //! This example demonstrates how stem plots are to be used. For more general 2 | //! features of the libray, see the line_plots example. 3 | 4 | use imgui::{CollapsingHeader, Ui}; 5 | use implot::{Plot, PlotStems, PlotUi}; 6 | 7 | pub fn show_basic_plot(ui: &Ui, plot_ui: &PlotUi) { 8 | ui.text("This header shows a simple stem plot."); 9 | let content_width = ui.window_content_region_width(); 10 | Plot::new("Stem plot") 11 | // The size call could also be omitted, though the defaults don't consider window 12 | // width, which is why we're not doing so here. 13 | .size([content_width, 300.0]) 14 | .build(plot_ui, || { 15 | // If this is called outside a plot build callback, the program will panic. 16 | let axis_positions = vec![0.2, 0.4, 0.6, 0.8, 0.9, 0.93]; 17 | let values = vec![0.1, 0.2, 0.3, 0.4, 0.3, 0.8]; 18 | PlotStems::new("legend label") 19 | .with_reference_y(0.1) 20 | .plot(&axis_positions, &values); 21 | }); 22 | } 23 | 24 | pub fn show_demo_headers(ui: &Ui, plot_ui: &PlotUi) { 25 | if CollapsingHeader::new("Stem plots").build(ui) { 26 | show_basic_plot(ui, plot_ui); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /implot-examples/examples-shared/src/text_plots.rs: -------------------------------------------------------------------------------- 1 | //! This example demonstrates how the text plotting features are to be used. For more general 2 | //! features of the libray, see the line_plots example. 3 | 4 | use imgui::{CollapsingHeader, Ui}; 5 | use implot::{Plot, PlotText, PlotUi}; 6 | 7 | pub fn show_basic_plot(ui: &Ui, plot_ui: &PlotUi) { 8 | ui.text("This header just plots some text with as little code as possible."); 9 | let content_width = ui.window_content_region_width(); 10 | Plot::new("Simple text plot") 11 | // The size call could also be omitted, though the defaults don't consider window 12 | // width, which is why we're not doing so here. 13 | .size([content_width, 300.0]) 14 | .build(plot_ui, || { 15 | // The text passed to "new" is what gets displayed. 16 | let x_position: f64 = 0.5; 17 | let y_position: f64 = 0.2; 18 | let vertical: bool = false; 19 | PlotText::new("horizontal displayed text").plot(x_position, y_position, vertical); 20 | 21 | // The text passed to "new" is what gets displayed. 22 | let x_position: f64 = 0.2; 23 | let y_position: f64 = 0.2; 24 | let vertical: bool = true; 25 | PlotText::new("vertical displayed text").plot(x_position, y_position, vertical); 26 | }); 27 | } 28 | 29 | pub fn show_demo_headers(ui: &Ui, plot_ui: &PlotUi) { 30 | if CollapsingHeader::new("Text plot: Basic").build(ui) { 31 | show_basic_plot(ui, plot_ui); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /implot-examples/implot-glium-demo/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "ab_glyph_rasterizer" 7 | version = "0.1.4" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "d9fe5e32de01730eb1f6b7f5b51c17e03e2325bf40a74f754f04f130043affff" 10 | 11 | [[package]] 12 | name = "addr2line" 13 | version = "0.16.0" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "3e61f2b7f93d2c7d2b08263acaa4a363b3e276806c68af6134c44f523bf1aacd" 16 | dependencies = [ 17 | "gimli", 18 | ] 19 | 20 | [[package]] 21 | name = "adler" 22 | version = "1.0.2" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 25 | 26 | [[package]] 27 | name = "adler32" 28 | version = "1.2.0" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" 31 | 32 | [[package]] 33 | name = "andrew" 34 | version = "0.3.1" 35 | source = "registry+https://github.com/rust-lang/crates.io-index" 36 | checksum = "8c4afb09dd642feec8408e33f92f3ffc4052946f6b20f32fb99c1f58cd4fa7cf" 37 | dependencies = [ 38 | "bitflags", 39 | "rusttype", 40 | "walkdir", 41 | "xdg", 42 | "xml-rs", 43 | ] 44 | 45 | [[package]] 46 | name = "android_glue" 47 | version = "0.2.3" 48 | source = "registry+https://github.com/rust-lang/crates.io-index" 49 | checksum = "000444226fcff248f2bc4c7625be32c63caccfecc2723a2b9f78a7487a49c407" 50 | 51 | [[package]] 52 | name = "autocfg" 53 | version = "1.0.1" 54 | source = "registry+https://github.com/rust-lang/crates.io-index" 55 | checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" 56 | 57 | [[package]] 58 | name = "backtrace" 59 | version = "0.3.61" 60 | source = "registry+https://github.com/rust-lang/crates.io-index" 61 | checksum = "e7a905d892734eea339e896738c14b9afce22b5318f64b951e70bf3844419b01" 62 | dependencies = [ 63 | "addr2line", 64 | "cc", 65 | "cfg-if 1.0.0", 66 | "libc", 67 | "miniz_oxide 0.4.4", 68 | "object", 69 | "rustc-demangle", 70 | ] 71 | 72 | [[package]] 73 | name = "bitflags" 74 | version = "1.3.2" 75 | source = "registry+https://github.com/rust-lang/crates.io-index" 76 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 77 | 78 | [[package]] 79 | name = "block" 80 | version = "0.1.6" 81 | source = "registry+https://github.com/rust-lang/crates.io-index" 82 | checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" 83 | 84 | [[package]] 85 | name = "bytemuck" 86 | version = "1.7.2" 87 | source = "registry+https://github.com/rust-lang/crates.io-index" 88 | checksum = "72957246c41db82b8ef88a5486143830adeb8227ef9837740bdec67724cf2c5b" 89 | 90 | [[package]] 91 | name = "byteorder" 92 | version = "1.4.3" 93 | source = "registry+https://github.com/rust-lang/crates.io-index" 94 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 95 | 96 | [[package]] 97 | name = "calloop" 98 | version = "0.6.5" 99 | source = "registry+https://github.com/rust-lang/crates.io-index" 100 | checksum = "0b036167e76041694579972c28cf4877b4f92da222560ddb49008937b6a6727c" 101 | dependencies = [ 102 | "log", 103 | "nix 0.18.0", 104 | ] 105 | 106 | [[package]] 107 | name = "cc" 108 | version = "1.0.70" 109 | source = "registry+https://github.com/rust-lang/crates.io-index" 110 | checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0" 111 | 112 | [[package]] 113 | name = "cfg-if" 114 | version = "0.1.10" 115 | source = "registry+https://github.com/rust-lang/crates.io-index" 116 | checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 117 | 118 | [[package]] 119 | name = "cfg-if" 120 | version = "1.0.0" 121 | source = "registry+https://github.com/rust-lang/crates.io-index" 122 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 123 | 124 | [[package]] 125 | name = "cgl" 126 | version = "0.3.2" 127 | source = "registry+https://github.com/rust-lang/crates.io-index" 128 | checksum = "0ced0551234e87afee12411d535648dd89d2e7f34c78b753395567aff3d447ff" 129 | dependencies = [ 130 | "libc", 131 | ] 132 | 133 | [[package]] 134 | name = "chlorine" 135 | version = "1.0.7" 136 | source = "registry+https://github.com/rust-lang/crates.io-index" 137 | checksum = "bd650552110e39b7c5058986cf177decd3365841836578ac50a286094eac0be6" 138 | 139 | [[package]] 140 | name = "clipboard" 141 | version = "0.5.0" 142 | source = "registry+https://github.com/rust-lang/crates.io-index" 143 | checksum = "25a904646c0340239dcf7c51677b33928bf24fdf424b79a57909c0109075b2e7" 144 | dependencies = [ 145 | "clipboard-win", 146 | "objc", 147 | "objc-foundation", 148 | "objc_id", 149 | "x11-clipboard", 150 | ] 151 | 152 | [[package]] 153 | name = "clipboard-win" 154 | version = "2.2.0" 155 | source = "registry+https://github.com/rust-lang/crates.io-index" 156 | checksum = "e3a093d6fed558e5fe24c3dfc85a68bb68f1c824f440d3ba5aca189e2998786b" 157 | dependencies = [ 158 | "winapi", 159 | ] 160 | 161 | [[package]] 162 | name = "cocoa" 163 | version = "0.24.0" 164 | source = "registry+https://github.com/rust-lang/crates.io-index" 165 | checksum = "6f63902e9223530efb4e26ccd0cf55ec30d592d3b42e21a28defc42a9586e832" 166 | dependencies = [ 167 | "bitflags", 168 | "block", 169 | "cocoa-foundation", 170 | "core-foundation 0.9.1", 171 | "core-graphics 0.22.2", 172 | "foreign-types", 173 | "libc", 174 | "objc", 175 | ] 176 | 177 | [[package]] 178 | name = "cocoa-foundation" 179 | version = "0.1.0" 180 | source = "registry+https://github.com/rust-lang/crates.io-index" 181 | checksum = "7ade49b65d560ca58c403a479bb396592b155c0185eada742ee323d1d68d6318" 182 | dependencies = [ 183 | "bitflags", 184 | "block", 185 | "core-foundation 0.9.1", 186 | "core-graphics-types", 187 | "foreign-types", 188 | "libc", 189 | "objc", 190 | ] 191 | 192 | [[package]] 193 | name = "color_quant" 194 | version = "1.1.0" 195 | source = "registry+https://github.com/rust-lang/crates.io-index" 196 | checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" 197 | 198 | [[package]] 199 | name = "core-foundation" 200 | version = "0.7.0" 201 | source = "registry+https://github.com/rust-lang/crates.io-index" 202 | checksum = "57d24c7a13c43e870e37c1556b74555437870a04514f7685f5b354e090567171" 203 | dependencies = [ 204 | "core-foundation-sys 0.7.0", 205 | "libc", 206 | ] 207 | 208 | [[package]] 209 | name = "core-foundation" 210 | version = "0.9.1" 211 | source = "registry+https://github.com/rust-lang/crates.io-index" 212 | checksum = "0a89e2ae426ea83155dccf10c0fa6b1463ef6d5fcb44cee0b224a408fa640a62" 213 | dependencies = [ 214 | "core-foundation-sys 0.8.2", 215 | "libc", 216 | ] 217 | 218 | [[package]] 219 | name = "core-foundation-sys" 220 | version = "0.7.0" 221 | source = "registry+https://github.com/rust-lang/crates.io-index" 222 | checksum = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac" 223 | 224 | [[package]] 225 | name = "core-foundation-sys" 226 | version = "0.8.2" 227 | source = "registry+https://github.com/rust-lang/crates.io-index" 228 | checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b" 229 | 230 | [[package]] 231 | name = "core-graphics" 232 | version = "0.19.2" 233 | source = "registry+https://github.com/rust-lang/crates.io-index" 234 | checksum = "b3889374e6ea6ab25dba90bb5d96202f61108058361f6dc72e8b03e6f8bbe923" 235 | dependencies = [ 236 | "bitflags", 237 | "core-foundation 0.7.0", 238 | "foreign-types", 239 | "libc", 240 | ] 241 | 242 | [[package]] 243 | name = "core-graphics" 244 | version = "0.22.2" 245 | source = "registry+https://github.com/rust-lang/crates.io-index" 246 | checksum = "269f35f69b542b80e736a20a89a05215c0ce80c2c03c514abb2e318b78379d86" 247 | dependencies = [ 248 | "bitflags", 249 | "core-foundation 0.9.1", 250 | "core-graphics-types", 251 | "foreign-types", 252 | "libc", 253 | ] 254 | 255 | [[package]] 256 | name = "core-graphics-types" 257 | version = "0.1.1" 258 | source = "registry+https://github.com/rust-lang/crates.io-index" 259 | checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b" 260 | dependencies = [ 261 | "bitflags", 262 | "core-foundation 0.9.1", 263 | "foreign-types", 264 | "libc", 265 | ] 266 | 267 | [[package]] 268 | name = "core-video-sys" 269 | version = "0.1.4" 270 | source = "registry+https://github.com/rust-lang/crates.io-index" 271 | checksum = "34ecad23610ad9757664d644e369246edde1803fcb43ed72876565098a5d3828" 272 | dependencies = [ 273 | "cfg-if 0.1.10", 274 | "core-foundation-sys 0.7.0", 275 | "core-graphics 0.19.2", 276 | "libc", 277 | "objc", 278 | ] 279 | 280 | [[package]] 281 | name = "crc32fast" 282 | version = "1.2.1" 283 | source = "registry+https://github.com/rust-lang/crates.io-index" 284 | checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" 285 | dependencies = [ 286 | "cfg-if 1.0.0", 287 | ] 288 | 289 | [[package]] 290 | name = "crossbeam" 291 | version = "0.8.1" 292 | source = "registry+https://github.com/rust-lang/crates.io-index" 293 | checksum = "4ae5588f6b3c3cb05239e90bd110f257254aecd01e4635400391aeae07497845" 294 | dependencies = [ 295 | "cfg-if 1.0.0", 296 | "crossbeam-channel", 297 | "crossbeam-deque", 298 | "crossbeam-epoch", 299 | "crossbeam-queue", 300 | "crossbeam-utils", 301 | ] 302 | 303 | [[package]] 304 | name = "crossbeam-channel" 305 | version = "0.5.1" 306 | source = "registry+https://github.com/rust-lang/crates.io-index" 307 | checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" 308 | dependencies = [ 309 | "cfg-if 1.0.0", 310 | "crossbeam-utils", 311 | ] 312 | 313 | [[package]] 314 | name = "crossbeam-deque" 315 | version = "0.8.1" 316 | source = "registry+https://github.com/rust-lang/crates.io-index" 317 | checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" 318 | dependencies = [ 319 | "cfg-if 1.0.0", 320 | "crossbeam-epoch", 321 | "crossbeam-utils", 322 | ] 323 | 324 | [[package]] 325 | name = "crossbeam-epoch" 326 | version = "0.9.5" 327 | source = "registry+https://github.com/rust-lang/crates.io-index" 328 | checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd" 329 | dependencies = [ 330 | "cfg-if 1.0.0", 331 | "crossbeam-utils", 332 | "lazy_static", 333 | "memoffset", 334 | "scopeguard", 335 | ] 336 | 337 | [[package]] 338 | name = "crossbeam-queue" 339 | version = "0.3.2" 340 | source = "registry+https://github.com/rust-lang/crates.io-index" 341 | checksum = "9b10ddc024425c88c2ad148c1b0fd53f4c6d38db9697c9f1588381212fa657c9" 342 | dependencies = [ 343 | "cfg-if 1.0.0", 344 | "crossbeam-utils", 345 | ] 346 | 347 | [[package]] 348 | name = "crossbeam-utils" 349 | version = "0.8.5" 350 | source = "registry+https://github.com/rust-lang/crates.io-index" 351 | checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" 352 | dependencies = [ 353 | "cfg-if 1.0.0", 354 | "lazy_static", 355 | ] 356 | 357 | [[package]] 358 | name = "darling" 359 | version = "0.10.2" 360 | source = "registry+https://github.com/rust-lang/crates.io-index" 361 | checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858" 362 | dependencies = [ 363 | "darling_core", 364 | "darling_macro", 365 | ] 366 | 367 | [[package]] 368 | name = "darling_core" 369 | version = "0.10.2" 370 | source = "registry+https://github.com/rust-lang/crates.io-index" 371 | checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" 372 | dependencies = [ 373 | "fnv", 374 | "ident_case", 375 | "proc-macro2", 376 | "quote", 377 | "strsim", 378 | "syn", 379 | ] 380 | 381 | [[package]] 382 | name = "darling_macro" 383 | version = "0.10.2" 384 | source = "registry+https://github.com/rust-lang/crates.io-index" 385 | checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" 386 | dependencies = [ 387 | "darling_core", 388 | "quote", 389 | "syn", 390 | ] 391 | 392 | [[package]] 393 | name = "deflate" 394 | version = "0.8.6" 395 | source = "registry+https://github.com/rust-lang/crates.io-index" 396 | checksum = "73770f8e1fe7d64df17ca66ad28994a0a623ea497fa69486e14984e715c5d174" 397 | dependencies = [ 398 | "adler32", 399 | "byteorder", 400 | ] 401 | 402 | [[package]] 403 | name = "derivative" 404 | version = "2.2.0" 405 | source = "registry+https://github.com/rust-lang/crates.io-index" 406 | checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" 407 | dependencies = [ 408 | "proc-macro2", 409 | "quote", 410 | "syn", 411 | ] 412 | 413 | [[package]] 414 | name = "dispatch" 415 | version = "0.2.0" 416 | source = "registry+https://github.com/rust-lang/crates.io-index" 417 | checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" 418 | 419 | [[package]] 420 | name = "dlib" 421 | version = "0.4.2" 422 | source = "registry+https://github.com/rust-lang/crates.io-index" 423 | checksum = "b11f15d1e3268f140f68d390637d5e76d849782d971ae7063e0da69fe9709a76" 424 | dependencies = [ 425 | "libloading 0.6.7", 426 | ] 427 | 428 | [[package]] 429 | name = "dlib" 430 | version = "0.5.0" 431 | source = "registry+https://github.com/rust-lang/crates.io-index" 432 | checksum = "ac1b7517328c04c2aa68422fc60a41b92208182142ed04a25879c26c8f878794" 433 | dependencies = [ 434 | "libloading 0.7.0", 435 | ] 436 | 437 | [[package]] 438 | name = "downcast-rs" 439 | version = "1.2.0" 440 | source = "registry+https://github.com/rust-lang/crates.io-index" 441 | checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" 442 | 443 | [[package]] 444 | name = "either" 445 | version = "1.6.1" 446 | source = "registry+https://github.com/rust-lang/crates.io-index" 447 | checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" 448 | 449 | [[package]] 450 | name = "examples-shared" 451 | version = "0.1.0" 452 | dependencies = [ 453 | "imgui", 454 | "implot", 455 | ] 456 | 457 | [[package]] 458 | name = "fnv" 459 | version = "1.0.7" 460 | source = "registry+https://github.com/rust-lang/crates.io-index" 461 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 462 | 463 | [[package]] 464 | name = "foreign-types" 465 | version = "0.3.2" 466 | source = "registry+https://github.com/rust-lang/crates.io-index" 467 | checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" 468 | dependencies = [ 469 | "foreign-types-shared", 470 | ] 471 | 472 | [[package]] 473 | name = "foreign-types-shared" 474 | version = "0.1.1" 475 | source = "registry+https://github.com/rust-lang/crates.io-index" 476 | checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" 477 | 478 | [[package]] 479 | name = "gif" 480 | version = "0.11.2" 481 | source = "registry+https://github.com/rust-lang/crates.io-index" 482 | checksum = "5a668f699973d0f573d15749b7002a9ac9e1f9c6b220e7b165601334c173d8de" 483 | dependencies = [ 484 | "color_quant", 485 | "weezl", 486 | ] 487 | 488 | [[package]] 489 | name = "gimli" 490 | version = "0.25.0" 491 | source = "registry+https://github.com/rust-lang/crates.io-index" 492 | checksum = "f0a01e0497841a3b2db4f8afa483cce65f7e96a3498bd6c541734792aeac8fe7" 493 | 494 | [[package]] 495 | name = "gl_generator" 496 | version = "0.14.0" 497 | source = "registry+https://github.com/rust-lang/crates.io-index" 498 | checksum = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d" 499 | dependencies = [ 500 | "khronos_api", 501 | "log", 502 | "xml-rs", 503 | ] 504 | 505 | [[package]] 506 | name = "glium" 507 | version = "0.30.2" 508 | source = "registry+https://github.com/rust-lang/crates.io-index" 509 | checksum = "506a2aa1564891d447ae5d1ba37519a8efd6d01ea3e7952da81aa30430c90007" 510 | dependencies = [ 511 | "backtrace", 512 | "fnv", 513 | "gl_generator", 514 | "glutin", 515 | "lazy_static", 516 | "memoffset", 517 | "smallvec", 518 | "takeable-option", 519 | ] 520 | 521 | [[package]] 522 | name = "glutin" 523 | version = "0.27.0" 524 | source = "registry+https://github.com/rust-lang/crates.io-index" 525 | checksum = "762d6cd2e1b855d99668ebe591cc9058659d85ac39a9a2078000eb122ddba8f0" 526 | dependencies = [ 527 | "android_glue", 528 | "cgl", 529 | "cocoa", 530 | "core-foundation 0.9.1", 531 | "glutin_egl_sys", 532 | "glutin_emscripten_sys", 533 | "glutin_gles2_sys", 534 | "glutin_glx_sys", 535 | "glutin_wgl_sys", 536 | "lazy_static", 537 | "libloading 0.7.0", 538 | "log", 539 | "objc", 540 | "osmesa-sys", 541 | "parking_lot", 542 | "wayland-client", 543 | "wayland-egl", 544 | "winapi", 545 | "winit", 546 | ] 547 | 548 | [[package]] 549 | name = "glutin_egl_sys" 550 | version = "0.1.5" 551 | source = "registry+https://github.com/rust-lang/crates.io-index" 552 | checksum = "2abb6aa55523480c4adc5a56bbaa249992e2dddb2fc63dc96e04a3355364c211" 553 | dependencies = [ 554 | "gl_generator", 555 | "winapi", 556 | ] 557 | 558 | [[package]] 559 | name = "glutin_emscripten_sys" 560 | version = "0.1.1" 561 | source = "registry+https://github.com/rust-lang/crates.io-index" 562 | checksum = "80de4146df76e8a6c32b03007bc764ff3249dcaeb4f675d68a06caf1bac363f1" 563 | 564 | [[package]] 565 | name = "glutin_gles2_sys" 566 | version = "0.1.5" 567 | source = "registry+https://github.com/rust-lang/crates.io-index" 568 | checksum = "e8094e708b730a7c8a1954f4f8a31880af00eb8a1c5b5bf85d28a0a3c6d69103" 569 | dependencies = [ 570 | "gl_generator", 571 | "objc", 572 | ] 573 | 574 | [[package]] 575 | name = "glutin_glx_sys" 576 | version = "0.1.7" 577 | source = "registry+https://github.com/rust-lang/crates.io-index" 578 | checksum = "7e393c8fc02b807459410429150e9c4faffdb312d59b8c038566173c81991351" 579 | dependencies = [ 580 | "gl_generator", 581 | "x11-dl", 582 | ] 583 | 584 | [[package]] 585 | name = "glutin_wgl_sys" 586 | version = "0.1.5" 587 | source = "registry+https://github.com/rust-lang/crates.io-index" 588 | checksum = "3da5951a1569dbab865c6f2a863efafff193a93caf05538d193e9e3816d21696" 589 | dependencies = [ 590 | "gl_generator", 591 | ] 592 | 593 | [[package]] 594 | name = "hermit-abi" 595 | version = "0.1.19" 596 | source = "registry+https://github.com/rust-lang/crates.io-index" 597 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 598 | dependencies = [ 599 | "libc", 600 | ] 601 | 602 | [[package]] 603 | name = "ident_case" 604 | version = "1.0.1" 605 | source = "registry+https://github.com/rust-lang/crates.io-index" 606 | checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" 607 | 608 | [[package]] 609 | name = "image" 610 | version = "0.23.14" 611 | source = "registry+https://github.com/rust-lang/crates.io-index" 612 | checksum = "24ffcb7e7244a9bf19d35bf2883b9c080c4ced3c07a9895572178cdb8f13f6a1" 613 | dependencies = [ 614 | "bytemuck", 615 | "byteorder", 616 | "color_quant", 617 | "gif", 618 | "jpeg-decoder", 619 | "num-iter", 620 | "num-rational", 621 | "num-traits", 622 | "png", 623 | "scoped_threadpool", 624 | "tiff", 625 | ] 626 | 627 | [[package]] 628 | name = "imgui" 629 | version = "0.8.0" 630 | source = "registry+https://github.com/rust-lang/crates.io-index" 631 | checksum = "4edc4023dc7b1161e25ec9bcee478173f97d6f618a1d04eced2d559ce03119b4" 632 | dependencies = [ 633 | "bitflags", 634 | "imgui-sys", 635 | "parking_lot", 636 | ] 637 | 638 | [[package]] 639 | name = "imgui-glium-renderer" 640 | version = "0.8.0" 641 | source = "registry+https://github.com/rust-lang/crates.io-index" 642 | checksum = "dc90d919aaa1fb05e4c58f0c3dad4a65f9233c2026cf8a3c549f721f3092da2c" 643 | dependencies = [ 644 | "glium", 645 | "imgui", 646 | ] 647 | 648 | [[package]] 649 | name = "imgui-sys" 650 | version = "0.8.0" 651 | source = "registry+https://github.com/rust-lang/crates.io-index" 652 | checksum = "0914d5ebaec1086300b970defc7ed71edc2cf102bdc3dd75fd51179549d4455b" 653 | dependencies = [ 654 | "cc", 655 | "chlorine", 656 | ] 657 | 658 | [[package]] 659 | name = "imgui-winit-support" 660 | version = "0.8.0" 661 | source = "registry+https://github.com/rust-lang/crates.io-index" 662 | checksum = "86a8c368182829141da5d22c352684d01e64359daa1a4550df4a2976836aa8e3" 663 | dependencies = [ 664 | "imgui", 665 | "winit", 666 | ] 667 | 668 | [[package]] 669 | name = "implot" 670 | version = "0.6.0" 671 | dependencies = [ 672 | "bitflags", 673 | "imgui", 674 | "implot-sys", 675 | "parking_lot", 676 | "rustversion", 677 | ] 678 | 679 | [[package]] 680 | name = "implot-glium-demo" 681 | version = "0.0.0" 682 | dependencies = [ 683 | "clipboard", 684 | "examples-shared", 685 | "glium", 686 | "image", 687 | "imgui", 688 | "imgui-glium-renderer", 689 | "imgui-sys", 690 | "imgui-winit-support", 691 | "implot", 692 | "implot-sys", 693 | ] 694 | 695 | [[package]] 696 | name = "implot-sys" 697 | version = "0.6.0" 698 | dependencies = [ 699 | "cc", 700 | "imgui-sys", 701 | ] 702 | 703 | [[package]] 704 | name = "instant" 705 | version = "0.1.10" 706 | source = "registry+https://github.com/rust-lang/crates.io-index" 707 | checksum = "bee0328b1209d157ef001c94dd85b4f8f64139adb0eac2659f4b08382b2f474d" 708 | dependencies = [ 709 | "cfg-if 1.0.0", 710 | ] 711 | 712 | [[package]] 713 | name = "jni-sys" 714 | version = "0.3.0" 715 | source = "registry+https://github.com/rust-lang/crates.io-index" 716 | checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" 717 | 718 | [[package]] 719 | name = "jpeg-decoder" 720 | version = "0.1.22" 721 | source = "registry+https://github.com/rust-lang/crates.io-index" 722 | checksum = "229d53d58899083193af11e15917b5640cd40b29ff475a1fe4ef725deb02d0f2" 723 | dependencies = [ 724 | "rayon", 725 | ] 726 | 727 | [[package]] 728 | name = "khronos_api" 729 | version = "3.1.0" 730 | source = "registry+https://github.com/rust-lang/crates.io-index" 731 | checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" 732 | 733 | [[package]] 734 | name = "lazy_static" 735 | version = "1.4.0" 736 | source = "registry+https://github.com/rust-lang/crates.io-index" 737 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 738 | 739 | [[package]] 740 | name = "libc" 741 | version = "0.2.102" 742 | source = "registry+https://github.com/rust-lang/crates.io-index" 743 | checksum = "a2a5ac8f984bfcf3a823267e5fde638acc3325f6496633a5da6bb6eb2171e103" 744 | 745 | [[package]] 746 | name = "libloading" 747 | version = "0.6.7" 748 | source = "registry+https://github.com/rust-lang/crates.io-index" 749 | checksum = "351a32417a12d5f7e82c368a66781e307834dae04c6ce0cd4456d52989229883" 750 | dependencies = [ 751 | "cfg-if 1.0.0", 752 | "winapi", 753 | ] 754 | 755 | [[package]] 756 | name = "libloading" 757 | version = "0.7.0" 758 | source = "registry+https://github.com/rust-lang/crates.io-index" 759 | checksum = "6f84d96438c15fcd6c3f244c8fce01d1e2b9c6b5623e9c711dc9286d8fc92d6a" 760 | dependencies = [ 761 | "cfg-if 1.0.0", 762 | "winapi", 763 | ] 764 | 765 | [[package]] 766 | name = "lock_api" 767 | version = "0.4.5" 768 | source = "registry+https://github.com/rust-lang/crates.io-index" 769 | checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" 770 | dependencies = [ 771 | "scopeguard", 772 | ] 773 | 774 | [[package]] 775 | name = "log" 776 | version = "0.4.14" 777 | source = "registry+https://github.com/rust-lang/crates.io-index" 778 | checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" 779 | dependencies = [ 780 | "cfg-if 1.0.0", 781 | ] 782 | 783 | [[package]] 784 | name = "malloc_buf" 785 | version = "0.0.6" 786 | source = "registry+https://github.com/rust-lang/crates.io-index" 787 | checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" 788 | dependencies = [ 789 | "libc", 790 | ] 791 | 792 | [[package]] 793 | name = "maybe-uninit" 794 | version = "2.0.0" 795 | source = "registry+https://github.com/rust-lang/crates.io-index" 796 | checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" 797 | 798 | [[package]] 799 | name = "memchr" 800 | version = "2.4.1" 801 | source = "registry+https://github.com/rust-lang/crates.io-index" 802 | checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" 803 | 804 | [[package]] 805 | name = "memmap2" 806 | version = "0.1.0" 807 | source = "registry+https://github.com/rust-lang/crates.io-index" 808 | checksum = "d9b70ca2a6103ac8b665dc150b142ef0e4e89df640c9e6cf295d189c3caebe5a" 809 | dependencies = [ 810 | "libc", 811 | ] 812 | 813 | [[package]] 814 | name = "memoffset" 815 | version = "0.6.4" 816 | source = "registry+https://github.com/rust-lang/crates.io-index" 817 | checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" 818 | dependencies = [ 819 | "autocfg", 820 | ] 821 | 822 | [[package]] 823 | name = "minimal-lexical" 824 | version = "0.1.3" 825 | source = "registry+https://github.com/rust-lang/crates.io-index" 826 | checksum = "0c835948974f68e0bd58636fc6c5b1fbff7b297e3046f11b3b3c18bbac012c6d" 827 | 828 | [[package]] 829 | name = "miniz_oxide" 830 | version = "0.3.7" 831 | source = "registry+https://github.com/rust-lang/crates.io-index" 832 | checksum = "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435" 833 | dependencies = [ 834 | "adler32", 835 | ] 836 | 837 | [[package]] 838 | name = "miniz_oxide" 839 | version = "0.4.4" 840 | source = "registry+https://github.com/rust-lang/crates.io-index" 841 | checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" 842 | dependencies = [ 843 | "adler", 844 | "autocfg", 845 | ] 846 | 847 | [[package]] 848 | name = "mio" 849 | version = "0.7.13" 850 | source = "registry+https://github.com/rust-lang/crates.io-index" 851 | checksum = "8c2bdb6314ec10835cd3293dd268473a835c02b7b352e788be788b3c6ca6bb16" 852 | dependencies = [ 853 | "libc", 854 | "log", 855 | "miow", 856 | "ntapi", 857 | "winapi", 858 | ] 859 | 860 | [[package]] 861 | name = "mio-misc" 862 | version = "1.2.1" 863 | source = "registry+https://github.com/rust-lang/crates.io-index" 864 | checksum = "0ddf05411bb159cdb5801bb10002afb66cb4572be656044315e363460ce69dc2" 865 | dependencies = [ 866 | "crossbeam", 867 | "crossbeam-queue", 868 | "log", 869 | "mio", 870 | ] 871 | 872 | [[package]] 873 | name = "miow" 874 | version = "0.3.7" 875 | source = "registry+https://github.com/rust-lang/crates.io-index" 876 | checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" 877 | dependencies = [ 878 | "winapi", 879 | ] 880 | 881 | [[package]] 882 | name = "ndk" 883 | version = "0.3.0" 884 | source = "registry+https://github.com/rust-lang/crates.io-index" 885 | checksum = "8794322172319b972f528bf90c6b467be0079f1fa82780ffb431088e741a73ab" 886 | dependencies = [ 887 | "jni-sys", 888 | "ndk-sys", 889 | "num_enum", 890 | "thiserror", 891 | ] 892 | 893 | [[package]] 894 | name = "ndk-glue" 895 | version = "0.3.0" 896 | source = "registry+https://github.com/rust-lang/crates.io-index" 897 | checksum = "c5caf0c24d51ac1c905c27d4eda4fa0635bbe0de596b8f79235e0b17a4d29385" 898 | dependencies = [ 899 | "lazy_static", 900 | "libc", 901 | "log", 902 | "ndk", 903 | "ndk-macro", 904 | "ndk-sys", 905 | ] 906 | 907 | [[package]] 908 | name = "ndk-macro" 909 | version = "0.2.0" 910 | source = "registry+https://github.com/rust-lang/crates.io-index" 911 | checksum = "05d1c6307dc424d0f65b9b06e94f88248e6305726b14729fd67a5e47b2dc481d" 912 | dependencies = [ 913 | "darling", 914 | "proc-macro-crate 0.1.5", 915 | "proc-macro2", 916 | "quote", 917 | "syn", 918 | ] 919 | 920 | [[package]] 921 | name = "ndk-sys" 922 | version = "0.2.1" 923 | source = "registry+https://github.com/rust-lang/crates.io-index" 924 | checksum = "c44922cb3dbb1c70b5e5f443d63b64363a898564d739ba5198e3a9138442868d" 925 | 926 | [[package]] 927 | name = "nix" 928 | version = "0.18.0" 929 | source = "registry+https://github.com/rust-lang/crates.io-index" 930 | checksum = "83450fe6a6142ddd95fb064b746083fc4ef1705fe81f64a64e1d4b39f54a1055" 931 | dependencies = [ 932 | "bitflags", 933 | "cc", 934 | "cfg-if 0.1.10", 935 | "libc", 936 | ] 937 | 938 | [[package]] 939 | name = "nix" 940 | version = "0.20.0" 941 | source = "registry+https://github.com/rust-lang/crates.io-index" 942 | checksum = "fa9b4819da1bc61c0ea48b63b7bc8604064dd43013e7cc325df098d49cd7c18a" 943 | dependencies = [ 944 | "bitflags", 945 | "cc", 946 | "cfg-if 1.0.0", 947 | "libc", 948 | ] 949 | 950 | [[package]] 951 | name = "nom" 952 | version = "7.0.0" 953 | source = "registry+https://github.com/rust-lang/crates.io-index" 954 | checksum = "7ffd9d26838a953b4af82cbeb9f1592c6798916983959be223a7124e992742c1" 955 | dependencies = [ 956 | "memchr", 957 | "minimal-lexical", 958 | "version_check", 959 | ] 960 | 961 | [[package]] 962 | name = "ntapi" 963 | version = "0.3.6" 964 | source = "registry+https://github.com/rust-lang/crates.io-index" 965 | checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" 966 | dependencies = [ 967 | "winapi", 968 | ] 969 | 970 | [[package]] 971 | name = "num-integer" 972 | version = "0.1.44" 973 | source = "registry+https://github.com/rust-lang/crates.io-index" 974 | checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" 975 | dependencies = [ 976 | "autocfg", 977 | "num-traits", 978 | ] 979 | 980 | [[package]] 981 | name = "num-iter" 982 | version = "0.1.42" 983 | source = "registry+https://github.com/rust-lang/crates.io-index" 984 | checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59" 985 | dependencies = [ 986 | "autocfg", 987 | "num-integer", 988 | "num-traits", 989 | ] 990 | 991 | [[package]] 992 | name = "num-rational" 993 | version = "0.3.2" 994 | source = "registry+https://github.com/rust-lang/crates.io-index" 995 | checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" 996 | dependencies = [ 997 | "autocfg", 998 | "num-integer", 999 | "num-traits", 1000 | ] 1001 | 1002 | [[package]] 1003 | name = "num-traits" 1004 | version = "0.2.14" 1005 | source = "registry+https://github.com/rust-lang/crates.io-index" 1006 | checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" 1007 | dependencies = [ 1008 | "autocfg", 1009 | ] 1010 | 1011 | [[package]] 1012 | name = "num_cpus" 1013 | version = "1.13.0" 1014 | source = "registry+https://github.com/rust-lang/crates.io-index" 1015 | checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" 1016 | dependencies = [ 1017 | "hermit-abi", 1018 | "libc", 1019 | ] 1020 | 1021 | [[package]] 1022 | name = "num_enum" 1023 | version = "0.5.4" 1024 | source = "registry+https://github.com/rust-lang/crates.io-index" 1025 | checksum = "3f9bd055fb730c4f8f4f57d45d35cd6b3f0980535b056dc7ff119cee6a66ed6f" 1026 | dependencies = [ 1027 | "derivative", 1028 | "num_enum_derive", 1029 | ] 1030 | 1031 | [[package]] 1032 | name = "num_enum_derive" 1033 | version = "0.5.4" 1034 | source = "registry+https://github.com/rust-lang/crates.io-index" 1035 | checksum = "486ea01961c4a818096de679a8b740b26d9033146ac5291b1c98557658f8cdd9" 1036 | dependencies = [ 1037 | "proc-macro-crate 1.1.0", 1038 | "proc-macro2", 1039 | "quote", 1040 | "syn", 1041 | ] 1042 | 1043 | [[package]] 1044 | name = "objc" 1045 | version = "0.2.7" 1046 | source = "registry+https://github.com/rust-lang/crates.io-index" 1047 | checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" 1048 | dependencies = [ 1049 | "malloc_buf", 1050 | ] 1051 | 1052 | [[package]] 1053 | name = "objc-foundation" 1054 | version = "0.1.1" 1055 | source = "registry+https://github.com/rust-lang/crates.io-index" 1056 | checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" 1057 | dependencies = [ 1058 | "block", 1059 | "objc", 1060 | "objc_id", 1061 | ] 1062 | 1063 | [[package]] 1064 | name = "objc_id" 1065 | version = "0.1.1" 1066 | source = "registry+https://github.com/rust-lang/crates.io-index" 1067 | checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" 1068 | dependencies = [ 1069 | "objc", 1070 | ] 1071 | 1072 | [[package]] 1073 | name = "object" 1074 | version = "0.26.2" 1075 | source = "registry+https://github.com/rust-lang/crates.io-index" 1076 | checksum = "39f37e50073ccad23b6d09bcb5b263f4e76d3bb6038e4a3c08e52162ffa8abc2" 1077 | dependencies = [ 1078 | "memchr", 1079 | ] 1080 | 1081 | [[package]] 1082 | name = "once_cell" 1083 | version = "1.8.0" 1084 | source = "registry+https://github.com/rust-lang/crates.io-index" 1085 | checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" 1086 | 1087 | [[package]] 1088 | name = "osmesa-sys" 1089 | version = "0.1.2" 1090 | source = "registry+https://github.com/rust-lang/crates.io-index" 1091 | checksum = "88cfece6e95d2e717e0872a7f53a8684712ad13822a7979bc760b9c77ec0013b" 1092 | dependencies = [ 1093 | "shared_library", 1094 | ] 1095 | 1096 | [[package]] 1097 | name = "owned_ttf_parser" 1098 | version = "0.6.0" 1099 | source = "registry+https://github.com/rust-lang/crates.io-index" 1100 | checksum = "9f923fb806c46266c02ab4a5b239735c144bdeda724a50ed058e5226f594cde3" 1101 | dependencies = [ 1102 | "ttf-parser", 1103 | ] 1104 | 1105 | [[package]] 1106 | name = "parking_lot" 1107 | version = "0.11.2" 1108 | source = "registry+https://github.com/rust-lang/crates.io-index" 1109 | checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" 1110 | dependencies = [ 1111 | "instant", 1112 | "lock_api", 1113 | "parking_lot_core", 1114 | ] 1115 | 1116 | [[package]] 1117 | name = "parking_lot_core" 1118 | version = "0.8.5" 1119 | source = "registry+https://github.com/rust-lang/crates.io-index" 1120 | checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" 1121 | dependencies = [ 1122 | "cfg-if 1.0.0", 1123 | "instant", 1124 | "libc", 1125 | "redox_syscall", 1126 | "smallvec", 1127 | "winapi", 1128 | ] 1129 | 1130 | [[package]] 1131 | name = "percent-encoding" 1132 | version = "2.1.0" 1133 | source = "registry+https://github.com/rust-lang/crates.io-index" 1134 | checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" 1135 | 1136 | [[package]] 1137 | name = "pkg-config" 1138 | version = "0.3.19" 1139 | source = "registry+https://github.com/rust-lang/crates.io-index" 1140 | checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" 1141 | 1142 | [[package]] 1143 | name = "png" 1144 | version = "0.16.8" 1145 | source = "registry+https://github.com/rust-lang/crates.io-index" 1146 | checksum = "3c3287920cb847dee3de33d301c463fba14dda99db24214ddf93f83d3021f4c6" 1147 | dependencies = [ 1148 | "bitflags", 1149 | "crc32fast", 1150 | "deflate", 1151 | "miniz_oxide 0.3.7", 1152 | ] 1153 | 1154 | [[package]] 1155 | name = "proc-macro-crate" 1156 | version = "0.1.5" 1157 | source = "registry+https://github.com/rust-lang/crates.io-index" 1158 | checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" 1159 | dependencies = [ 1160 | "toml", 1161 | ] 1162 | 1163 | [[package]] 1164 | name = "proc-macro-crate" 1165 | version = "1.1.0" 1166 | source = "registry+https://github.com/rust-lang/crates.io-index" 1167 | checksum = "1ebace6889caf889b4d3f76becee12e90353f2b8c7d875534a71e5742f8f6f83" 1168 | dependencies = [ 1169 | "thiserror", 1170 | "toml", 1171 | ] 1172 | 1173 | [[package]] 1174 | name = "proc-macro2" 1175 | version = "1.0.29" 1176 | source = "registry+https://github.com/rust-lang/crates.io-index" 1177 | checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" 1178 | dependencies = [ 1179 | "unicode-xid", 1180 | ] 1181 | 1182 | [[package]] 1183 | name = "quote" 1184 | version = "1.0.9" 1185 | source = "registry+https://github.com/rust-lang/crates.io-index" 1186 | checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" 1187 | dependencies = [ 1188 | "proc-macro2", 1189 | ] 1190 | 1191 | [[package]] 1192 | name = "raw-window-handle" 1193 | version = "0.3.3" 1194 | source = "registry+https://github.com/rust-lang/crates.io-index" 1195 | checksum = "0a441a7a6c80ad6473bd4b74ec1c9a4c951794285bf941c2126f607c72e48211" 1196 | dependencies = [ 1197 | "libc", 1198 | ] 1199 | 1200 | [[package]] 1201 | name = "rayon" 1202 | version = "1.5.1" 1203 | source = "registry+https://github.com/rust-lang/crates.io-index" 1204 | checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90" 1205 | dependencies = [ 1206 | "autocfg", 1207 | "crossbeam-deque", 1208 | "either", 1209 | "rayon-core", 1210 | ] 1211 | 1212 | [[package]] 1213 | name = "rayon-core" 1214 | version = "1.9.1" 1215 | source = "registry+https://github.com/rust-lang/crates.io-index" 1216 | checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" 1217 | dependencies = [ 1218 | "crossbeam-channel", 1219 | "crossbeam-deque", 1220 | "crossbeam-utils", 1221 | "lazy_static", 1222 | "num_cpus", 1223 | ] 1224 | 1225 | [[package]] 1226 | name = "redox_syscall" 1227 | version = "0.2.10" 1228 | source = "registry+https://github.com/rust-lang/crates.io-index" 1229 | checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" 1230 | dependencies = [ 1231 | "bitflags", 1232 | ] 1233 | 1234 | [[package]] 1235 | name = "rustc-demangle" 1236 | version = "0.1.21" 1237 | source = "registry+https://github.com/rust-lang/crates.io-index" 1238 | checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" 1239 | 1240 | [[package]] 1241 | name = "rusttype" 1242 | version = "0.9.2" 1243 | source = "registry+https://github.com/rust-lang/crates.io-index" 1244 | checksum = "dc7c727aded0be18c5b80c1640eae0ac8e396abf6fa8477d96cb37d18ee5ec59" 1245 | dependencies = [ 1246 | "ab_glyph_rasterizer", 1247 | "owned_ttf_parser", 1248 | ] 1249 | 1250 | [[package]] 1251 | name = "rustversion" 1252 | version = "1.0.5" 1253 | source = "registry+https://github.com/rust-lang/crates.io-index" 1254 | checksum = "61b3909d758bb75c79f23d4736fac9433868679d3ad2ea7a61e3c25cfda9a088" 1255 | 1256 | [[package]] 1257 | name = "same-file" 1258 | version = "1.0.6" 1259 | source = "registry+https://github.com/rust-lang/crates.io-index" 1260 | checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" 1261 | dependencies = [ 1262 | "winapi-util", 1263 | ] 1264 | 1265 | [[package]] 1266 | name = "scoped-tls" 1267 | version = "1.0.0" 1268 | source = "registry+https://github.com/rust-lang/crates.io-index" 1269 | checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" 1270 | 1271 | [[package]] 1272 | name = "scoped_threadpool" 1273 | version = "0.1.9" 1274 | source = "registry+https://github.com/rust-lang/crates.io-index" 1275 | checksum = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8" 1276 | 1277 | [[package]] 1278 | name = "scopeguard" 1279 | version = "1.1.0" 1280 | source = "registry+https://github.com/rust-lang/crates.io-index" 1281 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 1282 | 1283 | [[package]] 1284 | name = "serde" 1285 | version = "1.0.130" 1286 | source = "registry+https://github.com/rust-lang/crates.io-index" 1287 | checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" 1288 | 1289 | [[package]] 1290 | name = "shared_library" 1291 | version = "0.1.9" 1292 | source = "registry+https://github.com/rust-lang/crates.io-index" 1293 | checksum = "5a9e7e0f2bfae24d8a5b5a66c5b257a83c7412304311512a0c054cd5e619da11" 1294 | dependencies = [ 1295 | "lazy_static", 1296 | "libc", 1297 | ] 1298 | 1299 | [[package]] 1300 | name = "smallvec" 1301 | version = "1.6.1" 1302 | source = "registry+https://github.com/rust-lang/crates.io-index" 1303 | checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" 1304 | 1305 | [[package]] 1306 | name = "smithay-client-toolkit" 1307 | version = "0.12.3" 1308 | source = "registry+https://github.com/rust-lang/crates.io-index" 1309 | checksum = "4750c76fd5d3ac95fa3ed80fe667d6a3d8590a960e5b575b98eea93339a80b80" 1310 | dependencies = [ 1311 | "andrew", 1312 | "bitflags", 1313 | "calloop", 1314 | "dlib 0.4.2", 1315 | "lazy_static", 1316 | "log", 1317 | "memmap2", 1318 | "nix 0.18.0", 1319 | "wayland-client", 1320 | "wayland-cursor", 1321 | "wayland-protocols", 1322 | ] 1323 | 1324 | [[package]] 1325 | name = "strsim" 1326 | version = "0.9.3" 1327 | source = "registry+https://github.com/rust-lang/crates.io-index" 1328 | checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" 1329 | 1330 | [[package]] 1331 | name = "syn" 1332 | version = "1.0.76" 1333 | source = "registry+https://github.com/rust-lang/crates.io-index" 1334 | checksum = "c6f107db402c2c2055242dbf4d2af0e69197202e9faacbef9571bbe47f5a1b84" 1335 | dependencies = [ 1336 | "proc-macro2", 1337 | "quote", 1338 | "unicode-xid", 1339 | ] 1340 | 1341 | [[package]] 1342 | name = "takeable-option" 1343 | version = "0.5.0" 1344 | source = "registry+https://github.com/rust-lang/crates.io-index" 1345 | checksum = "36ae8932fcfea38b7d3883ae2ab357b0d57a02caaa18ebb4f5ece08beaec4aa0" 1346 | 1347 | [[package]] 1348 | name = "thiserror" 1349 | version = "1.0.29" 1350 | source = "registry+https://github.com/rust-lang/crates.io-index" 1351 | checksum = "602eca064b2d83369e2b2f34b09c70b605402801927c65c11071ac911d299b88" 1352 | dependencies = [ 1353 | "thiserror-impl", 1354 | ] 1355 | 1356 | [[package]] 1357 | name = "thiserror-impl" 1358 | version = "1.0.29" 1359 | source = "registry+https://github.com/rust-lang/crates.io-index" 1360 | checksum = "bad553cc2c78e8de258400763a647e80e6d1b31ee237275d756f6836d204494c" 1361 | dependencies = [ 1362 | "proc-macro2", 1363 | "quote", 1364 | "syn", 1365 | ] 1366 | 1367 | [[package]] 1368 | name = "tiff" 1369 | version = "0.6.1" 1370 | source = "registry+https://github.com/rust-lang/crates.io-index" 1371 | checksum = "9a53f4706d65497df0c4349241deddf35f84cee19c87ed86ea8ca590f4464437" 1372 | dependencies = [ 1373 | "jpeg-decoder", 1374 | "miniz_oxide 0.4.4", 1375 | "weezl", 1376 | ] 1377 | 1378 | [[package]] 1379 | name = "toml" 1380 | version = "0.5.8" 1381 | source = "registry+https://github.com/rust-lang/crates.io-index" 1382 | checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" 1383 | dependencies = [ 1384 | "serde", 1385 | ] 1386 | 1387 | [[package]] 1388 | name = "ttf-parser" 1389 | version = "0.6.2" 1390 | source = "registry+https://github.com/rust-lang/crates.io-index" 1391 | checksum = "3e5d7cd7ab3e47dda6e56542f4bbf3824c15234958c6e1bd6aaa347e93499fdc" 1392 | 1393 | [[package]] 1394 | name = "unicode-xid" 1395 | version = "0.2.2" 1396 | source = "registry+https://github.com/rust-lang/crates.io-index" 1397 | checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" 1398 | 1399 | [[package]] 1400 | name = "version_check" 1401 | version = "0.9.3" 1402 | source = "registry+https://github.com/rust-lang/crates.io-index" 1403 | checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" 1404 | 1405 | [[package]] 1406 | name = "walkdir" 1407 | version = "2.3.2" 1408 | source = "registry+https://github.com/rust-lang/crates.io-index" 1409 | checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" 1410 | dependencies = [ 1411 | "same-file", 1412 | "winapi", 1413 | "winapi-util", 1414 | ] 1415 | 1416 | [[package]] 1417 | name = "wayland-client" 1418 | version = "0.28.6" 1419 | source = "registry+https://github.com/rust-lang/crates.io-index" 1420 | checksum = "e3ab332350e502f159382201394a78e3cc12d0f04db863429260164ea40e0355" 1421 | dependencies = [ 1422 | "bitflags", 1423 | "downcast-rs", 1424 | "libc", 1425 | "nix 0.20.0", 1426 | "scoped-tls", 1427 | "wayland-commons", 1428 | "wayland-scanner", 1429 | "wayland-sys", 1430 | ] 1431 | 1432 | [[package]] 1433 | name = "wayland-commons" 1434 | version = "0.28.6" 1435 | source = "registry+https://github.com/rust-lang/crates.io-index" 1436 | checksum = "a21817947c7011bbd0a27e11b17b337bfd022e8544b071a2641232047966fbda" 1437 | dependencies = [ 1438 | "nix 0.20.0", 1439 | "once_cell", 1440 | "smallvec", 1441 | "wayland-sys", 1442 | ] 1443 | 1444 | [[package]] 1445 | name = "wayland-cursor" 1446 | version = "0.28.6" 1447 | source = "registry+https://github.com/rust-lang/crates.io-index" 1448 | checksum = "be610084edd1586d45e7bdd275fe345c7c1873598caa464c4fb835dee70fa65a" 1449 | dependencies = [ 1450 | "nix 0.20.0", 1451 | "wayland-client", 1452 | "xcursor", 1453 | ] 1454 | 1455 | [[package]] 1456 | name = "wayland-egl" 1457 | version = "0.28.6" 1458 | source = "registry+https://github.com/rust-lang/crates.io-index" 1459 | checksum = "99ba1ab1e18756b23982d36f08856d521d7df45015f404a2d7c4f0b2d2f66956" 1460 | dependencies = [ 1461 | "wayland-client", 1462 | "wayland-sys", 1463 | ] 1464 | 1465 | [[package]] 1466 | name = "wayland-protocols" 1467 | version = "0.28.6" 1468 | source = "registry+https://github.com/rust-lang/crates.io-index" 1469 | checksum = "286620ea4d803bacf61fa087a4242ee316693099ee5a140796aaba02b29f861f" 1470 | dependencies = [ 1471 | "bitflags", 1472 | "wayland-client", 1473 | "wayland-commons", 1474 | "wayland-scanner", 1475 | ] 1476 | 1477 | [[package]] 1478 | name = "wayland-scanner" 1479 | version = "0.28.6" 1480 | source = "registry+https://github.com/rust-lang/crates.io-index" 1481 | checksum = "ce923eb2deb61de332d1f356ec7b6bf37094dc5573952e1c8936db03b54c03f1" 1482 | dependencies = [ 1483 | "proc-macro2", 1484 | "quote", 1485 | "xml-rs", 1486 | ] 1487 | 1488 | [[package]] 1489 | name = "wayland-sys" 1490 | version = "0.28.6" 1491 | source = "registry+https://github.com/rust-lang/crates.io-index" 1492 | checksum = "d841fca9aed7febf9bed2e9796c49bf58d4152ceda8ac949ebe00868d8f0feb8" 1493 | dependencies = [ 1494 | "dlib 0.5.0", 1495 | "lazy_static", 1496 | "pkg-config", 1497 | ] 1498 | 1499 | [[package]] 1500 | name = "weezl" 1501 | version = "0.1.5" 1502 | source = "registry+https://github.com/rust-lang/crates.io-index" 1503 | checksum = "d8b77fdfd5a253be4ab714e4ffa3c49caf146b4de743e97510c0656cf90f1e8e" 1504 | 1505 | [[package]] 1506 | name = "winapi" 1507 | version = "0.3.9" 1508 | source = "registry+https://github.com/rust-lang/crates.io-index" 1509 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1510 | dependencies = [ 1511 | "winapi-i686-pc-windows-gnu", 1512 | "winapi-x86_64-pc-windows-gnu", 1513 | ] 1514 | 1515 | [[package]] 1516 | name = "winapi-i686-pc-windows-gnu" 1517 | version = "0.4.0" 1518 | source = "registry+https://github.com/rust-lang/crates.io-index" 1519 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1520 | 1521 | [[package]] 1522 | name = "winapi-util" 1523 | version = "0.1.5" 1524 | source = "registry+https://github.com/rust-lang/crates.io-index" 1525 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 1526 | dependencies = [ 1527 | "winapi", 1528 | ] 1529 | 1530 | [[package]] 1531 | name = "winapi-x86_64-pc-windows-gnu" 1532 | version = "0.4.0" 1533 | source = "registry+https://github.com/rust-lang/crates.io-index" 1534 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1535 | 1536 | [[package]] 1537 | name = "winit" 1538 | version = "0.25.0" 1539 | source = "registry+https://github.com/rust-lang/crates.io-index" 1540 | checksum = "79610794594d5e86be473ef7763f604f2159cbac8c94debd00df8fb41e86c2f8" 1541 | dependencies = [ 1542 | "bitflags", 1543 | "cocoa", 1544 | "core-foundation 0.9.1", 1545 | "core-graphics 0.22.2", 1546 | "core-video-sys", 1547 | "dispatch", 1548 | "instant", 1549 | "lazy_static", 1550 | "libc", 1551 | "log", 1552 | "mio", 1553 | "mio-misc", 1554 | "ndk", 1555 | "ndk-glue", 1556 | "ndk-sys", 1557 | "objc", 1558 | "parking_lot", 1559 | "percent-encoding", 1560 | "raw-window-handle", 1561 | "scopeguard", 1562 | "smithay-client-toolkit", 1563 | "wayland-client", 1564 | "winapi", 1565 | "x11-dl", 1566 | ] 1567 | 1568 | [[package]] 1569 | name = "x11-clipboard" 1570 | version = "0.3.3" 1571 | source = "registry+https://github.com/rust-lang/crates.io-index" 1572 | checksum = "89bd49c06c9eb5d98e6ba6536cf64ac9f7ee3a009b2f53996d405b3944f6bcea" 1573 | dependencies = [ 1574 | "xcb", 1575 | ] 1576 | 1577 | [[package]] 1578 | name = "x11-dl" 1579 | version = "2.18.5" 1580 | source = "registry+https://github.com/rust-lang/crates.io-index" 1581 | checksum = "2bf981e3a5b3301209754218f962052d4d9ee97e478f4d26d4a6eced34c1fef8" 1582 | dependencies = [ 1583 | "lazy_static", 1584 | "libc", 1585 | "maybe-uninit", 1586 | "pkg-config", 1587 | ] 1588 | 1589 | [[package]] 1590 | name = "xcb" 1591 | version = "0.8.2" 1592 | source = "registry+https://github.com/rust-lang/crates.io-index" 1593 | checksum = "5e917a3f24142e9ff8be2414e36c649d47d6cc2ba81f16201cdef96e533e02de" 1594 | dependencies = [ 1595 | "libc", 1596 | "log", 1597 | ] 1598 | 1599 | [[package]] 1600 | name = "xcursor" 1601 | version = "0.3.4" 1602 | source = "registry+https://github.com/rust-lang/crates.io-index" 1603 | checksum = "463705a63313cd4301184381c5e8042f0a7e9b4bb63653f216311d4ae74690b7" 1604 | dependencies = [ 1605 | "nom", 1606 | ] 1607 | 1608 | [[package]] 1609 | name = "xdg" 1610 | version = "2.2.0" 1611 | source = "registry+https://github.com/rust-lang/crates.io-index" 1612 | checksum = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57" 1613 | 1614 | [[package]] 1615 | name = "xml-rs" 1616 | version = "0.8.4" 1617 | source = "registry+https://github.com/rust-lang/crates.io-index" 1618 | checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3" 1619 | -------------------------------------------------------------------------------- /implot-examples/implot-glium-demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "implot-glium-demo" 3 | version = "0.0.0" 4 | edition = "2018" 5 | authors = ["Sandro Merkli", "implot-rs contributors"] 6 | description = "implot examples, with backend code for using glium (originally from imgui-examples)" 7 | homepage = "https://github.com/4bb4/implot-rs" 8 | repository = "https://github.com/4bb4/implot-rs" 9 | license = "MIT/Apache-2.0" 10 | publish = false 11 | 12 | [dependencies] 13 | clipboard = "0.5" 14 | glium = { version = "0.30", default-features = true } 15 | image = "0.23" 16 | imgui-sys = "0.8.0" 17 | imgui = "0.8.0" 18 | imgui-glium-renderer = "0.8.0" 19 | imgui-winit-support = "0.8.0" 20 | 21 | implot-sys = { path = "../../implot-sys" } 22 | implot = { path = "../../" } 23 | examples-shared = { path = "../examples-shared" } 24 | -------------------------------------------------------------------------------- /implot-examples/implot-glium-demo/src/main.rs: -------------------------------------------------------------------------------- 1 | use imgui::{Condition, Window}; 2 | use implot::Context; 3 | 4 | // The actual backend-specific code is in this. 5 | mod support; 6 | 7 | fn main() { 8 | let system = support::init(file!()); 9 | let mut showing_demo = false; 10 | let mut showing_rust_demo = true; 11 | let mut demo_state = examples_shared::DemoState::new(); 12 | let plotcontext = Context::create(); 13 | system.main_loop(move |_, ui| { 14 | // The context is moved into the closure after creation so plot_ui is valid. 15 | let plot_ui = plotcontext.get_plot_ui(); 16 | 17 | if showing_demo { 18 | implot::show_demo_window(&mut showing_demo); 19 | } 20 | 21 | if showing_rust_demo { 22 | demo_state.show_demos(ui, &plot_ui); 23 | } 24 | 25 | Window::new("Welcome to the ImPlot-rs demo!") 26 | .size([430.0, 450.0], Condition::FirstUseEver) 27 | .build(ui, || { 28 | ui.checkbox("Show C++ ImPlot demo window", &mut showing_demo); 29 | ui.checkbox("Show Rust ImPlot demo windows", &mut showing_rust_demo); 30 | // TODO(4bb4) ... move windows by default so this is less confusing 31 | ui.text_wrapped( 32 | "Note that the windows are stacked, so move this one out of the way to see\ 33 | the ones beneath it. If you see something in the C++ demo window, but not\ 34 | in the Rust ImPlot demo window, that means the bindings are likely not \ 35 | implemented yet. Feel free to open an issue if you are missing something \ 36 | in particular. 37 | ", 38 | ); 39 | }); 40 | }); 41 | } 42 | -------------------------------------------------------------------------------- /implot-examples/implot-glium-demo/src/support/clipboard.rs: -------------------------------------------------------------------------------- 1 | // Taken directly from imgui-rs examples at 2 | // 3 | // https://github.com/Gekkio/imgui-rs/tree/master/imgui-examples/examples/support 4 | // 5 | // Not my code. Originally by Joonas Javanainen and the ImGUI-rs contributors 6 | use clipboard::{ClipboardContext, ClipboardProvider}; 7 | use imgui::ClipboardBackend; 8 | 9 | pub struct ClipboardSupport(ClipboardContext); 10 | 11 | pub fn init() -> Option { 12 | ClipboardContext::new().ok().map(ClipboardSupport) 13 | } 14 | 15 | impl ClipboardBackend for ClipboardSupport { 16 | fn get(&mut self) -> Option { 17 | self.0.get_contents().ok().map(|text| text.into()) 18 | } 19 | fn set(&mut self, text: &str) { 20 | let _ = self.0.set_contents(text.to_owned()); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /implot-examples/implot-glium-demo/src/support/mod.rs: -------------------------------------------------------------------------------- 1 | // Taken directly from imgui-rs examples at 2 | // 3 | // https://github.com/Gekkio/imgui-rs/tree/master/imgui-examples/examples/support 4 | // 5 | // Not my code. Originally by Joonas Javanainen and the ImGUI-rs contributors 6 | use glium::glutin; 7 | use glium::glutin::event::{Event, WindowEvent}; 8 | use glium::glutin::event_loop::{ControlFlow, EventLoop}; 9 | use glium::glutin::window::WindowBuilder; 10 | use glium::{Display, Surface}; 11 | use imgui::{Context, FontConfig, FontSource, Ui}; 12 | use imgui_glium_renderer::Renderer; 13 | use imgui_winit_support::{HiDpiMode, WinitPlatform}; 14 | use std::time::Instant; 15 | 16 | mod clipboard; 17 | 18 | pub struct System { 19 | pub event_loop: EventLoop<()>, 20 | pub display: glium::Display, 21 | pub imgui: Context, 22 | pub renderer: Renderer, 23 | pub platform: WinitPlatform, 24 | pub font_size: f32, 25 | } 26 | 27 | pub fn init(title: &str) -> System { 28 | let title = match title.rfind('/') { 29 | Some(idx) => title.split_at(idx + 1).1, 30 | None => title, 31 | }; 32 | let event_loop = EventLoop::new(); 33 | let context = glutin::ContextBuilder::new().with_vsync(true); 34 | let builder = WindowBuilder::new() 35 | .with_title(title.to_owned()) 36 | .with_inner_size(glutin::dpi::LogicalSize::new(1024f64, 768f64)); 37 | let display = 38 | Display::new(builder, context, &event_loop).expect("Failed to initialize display"); 39 | 40 | let mut imgui = Context::create(); 41 | imgui.set_ini_filename(None); 42 | 43 | if let Some(backend) = clipboard::init() { 44 | imgui.set_clipboard_backend(backend); 45 | } else { 46 | eprintln!("Failed to initialize clipboard"); 47 | } 48 | 49 | let mut platform = WinitPlatform::init(&mut imgui); 50 | { 51 | let gl_window = display.gl_window(); 52 | let window = gl_window.window(); 53 | platform.attach_window(imgui.io_mut(), window, HiDpiMode::Rounded); 54 | } 55 | 56 | let hidpi_factor = platform.hidpi_factor(); 57 | let font_size = (13.0 * hidpi_factor) as f32; 58 | imgui.fonts().add_font(&[FontSource::DefaultFontData { 59 | config: Some(FontConfig { 60 | size_pixels: font_size, 61 | ..FontConfig::default() 62 | }), 63 | }]); 64 | 65 | imgui.io_mut().font_global_scale = (1.0 / hidpi_factor) as f32; 66 | 67 | let renderer = Renderer::init(&mut imgui, &display).expect("Failed to initialize renderer"); 68 | 69 | System { 70 | event_loop, 71 | display, 72 | imgui, 73 | platform, 74 | renderer, 75 | font_size, 76 | } 77 | } 78 | 79 | impl System { 80 | pub fn main_loop(self, mut run_ui: F) { 81 | let System { 82 | event_loop, 83 | display, 84 | mut imgui, 85 | mut platform, 86 | mut renderer, 87 | .. 88 | } = self; 89 | let mut last_frame = Instant::now(); 90 | 91 | event_loop.run(move |event, _, control_flow| match event { 92 | Event::NewEvents(_) => { 93 | let now = Instant::now(); 94 | imgui.io_mut().update_delta_time(now - last_frame); 95 | last_frame = now; 96 | } 97 | Event::MainEventsCleared => { 98 | let gl_window = display.gl_window(); 99 | platform 100 | .prepare_frame(imgui.io_mut(), gl_window.window()) 101 | .expect("Failed to prepare frame"); 102 | gl_window.window().request_redraw(); 103 | } 104 | Event::RedrawRequested(_) => { 105 | let mut ui = imgui.frame(); 106 | 107 | let mut run = true; 108 | run_ui(&mut run, &mut ui); 109 | if !run { 110 | *control_flow = ControlFlow::Exit; 111 | } 112 | 113 | let gl_window = display.gl_window(); 114 | let mut target = display.draw(); 115 | target.clear_color_srgb(1.0, 1.0, 1.0, 1.0); 116 | platform.prepare_render(&ui, gl_window.window()); 117 | let draw_data = ui.render(); 118 | renderer 119 | .render(&mut target, draw_data) 120 | .expect("Rendering failed"); 121 | target.finish().expect("Failed to swap buffers"); 122 | } 123 | Event::WindowEvent { 124 | event: WindowEvent::CloseRequested, 125 | .. 126 | } => *control_flow = ControlFlow::Exit, 127 | event => { 128 | let gl_window = display.gl_window(); 129 | platform.handle_event(imgui.io_mut(), gl_window.window(), &event); 130 | } 131 | }) 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /implot-examples/implot-wgpu-demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "implot-wgpu-demo" 3 | version = "0.1.0" 4 | authors = ["Benedikt Mandelkow ", "imgui-wgpu contributors"] 5 | edition = "2018" 6 | resolver = "2" 7 | 8 | [dependencies] 9 | implot = { path = "../../" } 10 | 11 | wgpu = "0.10" 12 | winit = "0.25" # opening windows and handling input 13 | futures = "^0.3.5" # executing async functions using blocking executor 14 | imgui = "0.8.0" 15 | imgui-winit-support = "0.8.0" # connection of input (keys) to imgui 16 | imgui-wgpu = "0.17.1" 17 | examples-shared = { path = "../examples-shared" } 18 | -------------------------------------------------------------------------------- /implot-examples/implot-wgpu-demo/src/main.rs: -------------------------------------------------------------------------------- 1 | use imgui::{Condition, Window}; 2 | use implot::Context; 3 | 4 | // The actual backend-specific code is in this. 5 | mod support; 6 | 7 | fn main() { 8 | let system = support::init(file!()); 9 | let mut showing_demo = false; 10 | let mut showing_rust_demo = true; 11 | let mut demo_state = examples_shared::DemoState::new(); 12 | let plotcontext = Context::create(); 13 | system.main_loop(move |_, ui| { 14 | // The context is moved into the closure after creation so plot_ui is valid. 15 | let plot_ui = plotcontext.get_plot_ui(); 16 | 17 | if showing_demo { 18 | implot::show_demo_window(&mut showing_demo); 19 | } 20 | 21 | if showing_rust_demo { 22 | demo_state.show_demos(ui, &plot_ui); 23 | } 24 | 25 | Window::new("Welcome to the ImPlot-rs demo!") 26 | .size([430.0, 450.0], Condition::FirstUseEver) 27 | .build(ui, || { 28 | ui.checkbox("Show C++ ImPlot demo window", &mut showing_demo); 29 | ui.checkbox("Show Rust ImPlot demo windows", &mut showing_rust_demo); 30 | // TODO(4bb4) ... move windows by default so this is less confusing 31 | ui.text_wrapped( 32 | "Note that the windows are stacked, so move this one out of the way to see\ 33 | the ones beneath it. If you see something in the C++ demo window, but not\ 34 | in the Rust ImPlot demo window, that means the bindings are likely not \ 35 | implemented yet. Feel free to open an issue if you are missing something \ 36 | in particular. 37 | ", 38 | ); 39 | }); 40 | }); 41 | } 42 | -------------------------------------------------------------------------------- /implot-examples/implot-wgpu-demo/src/support/clipboard.rs: -------------------------------------------------------------------------------- 1 | // Taken directly from imgui-rs examples at 2 | // 3 | // https://github.com/Gekkio/imgui-rs/tree/master/imgui-examples/examples/support 4 | // 5 | // Not my code. Originally by Joonas Javanainen and the ImGUI-rs contributors 6 | use clipboard::{ClipboardContext, ClipboardProvider}; 7 | use imgui::{ClipboardBackend, ImStr, ImString}; 8 | 9 | pub struct ClipboardSupport(ClipboardContext); 10 | 11 | pub fn init() -> Option { 12 | ClipboardContext::new() 13 | .ok() 14 | .map(|ctx| ClipboardSupport(ctx)) 15 | } 16 | 17 | impl ClipboardBackend for ClipboardSupport { 18 | fn get(&mut self) -> Option { 19 | self.0.get_contents().ok().map(|text| text.into()) 20 | } 21 | fn set(&mut self, text: &ImStr) { 22 | let _ = self.0.set_contents(text.to_str().to_owned()); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /implot-examples/implot-wgpu-demo/src/support/mod.rs: -------------------------------------------------------------------------------- 1 | use futures::executor::block_on; 2 | use imgui::{Context, FontSource, Ui}; 3 | use imgui_wgpu::{Renderer, RendererConfig}; 4 | use imgui_winit_support::WinitPlatform; 5 | use std::time::Instant; 6 | use winit::{ 7 | dpi::LogicalSize, 8 | event::{Event, WindowEvent}, 9 | event_loop::{ControlFlow, EventLoop}, 10 | window::Window, 11 | }; 12 | 13 | pub struct System { 14 | pub event_loop: EventLoop<()>, 15 | pub imgui: Context, 16 | pub renderer: Renderer, 17 | pub platform: WinitPlatform, 18 | pub font_size: f32, 19 | pub hidpi_factor: f64, 20 | pub surface_conf: wgpu::SurfaceConfiguration, 21 | pub window: Window, 22 | pub device: wgpu::Device, 23 | pub queue: wgpu::Queue, 24 | pub surface: wgpu::Surface, 25 | } 26 | 27 | pub fn init(title: &str) -> System { 28 | // Set up window and GPU 29 | let event_loop = EventLoop::new(); 30 | let instance = wgpu::Instance::new(wgpu::Backends::PRIMARY); 31 | 32 | let (window, size, surface) = { 33 | let window = Window::new(&event_loop).unwrap(); 34 | window.set_inner_size(LogicalSize { 35 | width: 1280.0, 36 | height: 720.0, 37 | }); 38 | window.set_title(title); 39 | let size = window.inner_size(); 40 | 41 | let surface = unsafe { instance.create_surface(&window) }; 42 | 43 | (window, size, surface) 44 | }; 45 | 46 | let adapter = block_on(instance.request_adapter(&wgpu::RequestAdapterOptions { 47 | power_preference: wgpu::PowerPreference::HighPerformance, 48 | compatible_surface: Some(&surface), 49 | })) 50 | .unwrap(); 51 | 52 | let (device, queue) = 53 | block_on(adapter.request_device(&wgpu::DeviceDescriptor::default(), None)).unwrap(); 54 | 55 | // Set up swap chain 56 | let surface_conf = wgpu::SurfaceConfiguration { 57 | usage: wgpu::TextureUsages::RENDER_ATTACHMENT, 58 | format: wgpu::TextureFormat::Bgra8UnormSrgb, 59 | width: size.width as u32, 60 | height: size.height as u32, 61 | present_mode: wgpu::PresentMode::Mailbox, 62 | }; 63 | 64 | surface.configure(&device, &surface_conf); 65 | 66 | // Set up dear imgui 67 | let mut imgui = imgui::Context::create(); 68 | 69 | let mut platform = imgui_winit_support::WinitPlatform::init(&mut imgui); 70 | platform.attach_window( 71 | imgui.io_mut(), 72 | &window, 73 | imgui_winit_support::HiDpiMode::Default, 74 | ); 75 | imgui.set_ini_filename(None); 76 | 77 | let hidpi_factor = window.scale_factor(); 78 | 79 | let font_size = (13.0 * hidpi_factor) as f32; 80 | imgui.io_mut().font_global_scale = (1.0 / hidpi_factor) as f32; 81 | 82 | imgui.fonts().add_font(&[FontSource::DefaultFontData { 83 | config: Some(imgui::FontConfig { 84 | oversample_h: 1, 85 | pixel_snap_h: true, 86 | size_pixels: font_size, 87 | ..Default::default() 88 | }), 89 | }]); 90 | 91 | // 92 | // Set up dear imgui wgpu renderer 93 | // 94 | let renderer_config = RendererConfig { 95 | texture_format: surface_conf.format, 96 | ..Default::default() 97 | }; 98 | 99 | let renderer = Renderer::new(&mut imgui, &device, &queue, renderer_config); 100 | 101 | System { 102 | event_loop, 103 | imgui, 104 | renderer, 105 | platform, 106 | font_size, 107 | hidpi_factor, 108 | surface_conf, 109 | window, 110 | device, 111 | queue, 112 | surface, 113 | } 114 | } 115 | 116 | impl System { 117 | pub fn main_loop(self, mut run_ui: F) { 118 | let System { 119 | event_loop, 120 | mut imgui, 121 | mut renderer, 122 | // Currently not used, but was used pre-refactor 123 | // mut hidpi_factor, 124 | mut surface_conf, 125 | mut platform, 126 | window, 127 | device, 128 | queue, 129 | surface, 130 | .. 131 | } = self; 132 | let mut last_frame = Instant::now(); 133 | let mut last_cursor = None; 134 | 135 | event_loop.run(move |event, _, control_flow| { 136 | *control_flow = ControlFlow::Poll; 137 | 138 | match event { 139 | Event::WindowEvent { 140 | event: WindowEvent::ScaleFactorChanged { scale_factor, .. }, 141 | .. 142 | } => { 143 | // This 144 | let _hidpi_factor = scale_factor; 145 | } 146 | Event::WindowEvent { 147 | event: WindowEvent::Resized(_), 148 | .. 149 | } => { 150 | let size = window.inner_size(); 151 | 152 | // Recreate the swap chain with the new size 153 | surface_conf.width = size.width as u32; 154 | surface_conf.height = size.height as u32; 155 | surface.configure(&device, &surface_conf); 156 | } 157 | Event::WindowEvent { 158 | event: WindowEvent::CloseRequested, 159 | .. 160 | } => *control_flow = ControlFlow::Exit, 161 | Event::MainEventsCleared => window.request_redraw(), 162 | Event::RedrawEventsCleared => { 163 | let now = Instant::now(); 164 | imgui.io_mut().update_delta_time(now - last_frame); 165 | last_frame = now; 166 | 167 | let frame = match surface.get_current_frame() { 168 | Ok(frame) => frame.output, 169 | Err(e) => { 170 | eprintln!("dropped frame: {:?}", e); 171 | return; 172 | } 173 | }; 174 | let view = frame 175 | .texture 176 | .create_view(&wgpu::TextureViewDescriptor::default()); 177 | 178 | platform 179 | .prepare_frame(imgui.io_mut(), &window) 180 | .expect("Failed to prepare frame"); 181 | let mut ui = imgui.frame(); 182 | 183 | // --- Actual drawing code ---------------------------------------------- 184 | let mut run = true; 185 | run_ui(&mut run, &mut ui); 186 | if !run { 187 | *control_flow = ControlFlow::Exit; 188 | } 189 | 190 | // --- Post-drawing rendering code -------------------------------------- 191 | let mut encoder: wgpu::CommandEncoder = device 192 | .create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }); 193 | 194 | if last_cursor != Some(ui.mouse_cursor()) { 195 | last_cursor = Some(ui.mouse_cursor()); 196 | platform.prepare_render(&ui, &window); 197 | } 198 | 199 | let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { 200 | label: None, 201 | color_attachments: &[wgpu::RenderPassColorAttachment { 202 | view: &view, 203 | resolve_target: None, 204 | ops: wgpu::Operations { 205 | load: wgpu::LoadOp::Clear(wgpu::Color { 206 | // TODO(4bb4) remove hardcoded values here 207 | r: 0.1, 208 | g: 0.4, 209 | b: 0.3, 210 | a: 1.0, 211 | }), 212 | store: true, 213 | }, 214 | }], 215 | depth_stencil_attachment: None, 216 | }); 217 | 218 | renderer 219 | .render(ui.render(), &queue, &device, &mut rpass) 220 | .expect("Rendering failed"); 221 | 222 | drop(rpass); 223 | 224 | queue.submit(Some(encoder.finish())); 225 | } 226 | _ => (), 227 | } 228 | 229 | platform.handle_event(imgui.io_mut(), &window, &event); 230 | }) 231 | } 232 | } 233 | -------------------------------------------------------------------------------- /implot-sys-bindgen/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "implot-sys-bindgen" 3 | version = "0.3.0" 4 | authors = ["Sandro Merkli"] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | bindgen = "0.57" 9 | imgui-sys = { version = "0.8.0" } 10 | -------------------------------------------------------------------------------- /implot-sys-bindgen/build.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | 3 | fn main() { 4 | // We just forward the DEP_IMGUI_THIRD_PARTY variable here because the 5 | // main function outside the build script does not actually see it 6 | let cimgui_include_path = 7 | env::var_os("DEP_IMGUI_THIRD_PARTY").expect("DEP_IMGUI_THIRD_PARTY not defined"); 8 | println!( 9 | "cargo:rustc-env=DEP_IMGUI_THIRD_PARTY={}", 10 | cimgui_include_path 11 | .to_str() 12 | .expect("Could not turn cimgui include path to string") 13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /implot-sys-bindgen/src/main.rs: -------------------------------------------------------------------------------- 1 | use bindgen::{Builder, CargoCallbacks}; 2 | use std::{env, io::Write, path::PathBuf}; 3 | 4 | // All this crate does is run bindgen on cimplot and store the result 5 | // in the src folder of the implot-sys crate. We add those bindings 6 | // to git so people don't have to install clang just to use implot-rs. 7 | 8 | fn main() { 9 | let cwd = env::current_dir().expect("Could not read current directory"); 10 | let sys_crate_path = cwd 11 | .join("..") 12 | .join("implot-sys") 13 | .canonicalize() 14 | .expect("Could not find sys crate directory"); 15 | 16 | let cimgui_include_path = PathBuf::from( 17 | env::var_os("DEP_IMGUI_THIRD_PARTY").expect("DEP_IMGUI_THIRD_PARTY not defined"), 18 | ); 19 | 20 | let bindings = Builder::default() 21 | .header( 22 | cimgui_include_path 23 | .join("cimgui.h") 24 | .to_str() 25 | .expect("Could not convert cimgui.h path to string"), 26 | ) 27 | .header( 28 | sys_crate_path 29 | .join("third-party") 30 | .join("cimplot") 31 | .join("cimplot.h") 32 | .to_str() 33 | .expect("Could not turn cimplot.h path into string"), 34 | ) 35 | .parse_callbacks(Box::new(CargoCallbacks)) 36 | .clang_arg("-DCIMGUI_DEFINE_ENUMS_AND_STRUCTS=1") 37 | // Reuse the imgui types that implot requires from imgui_sys so we don't define 38 | // our own new types. 39 | .raw_line("pub use imgui_sys::{ImVec2, ImVec4, ImGuiCond, ImTextureID};") 40 | .raw_line("pub use imgui_sys::{ImGuiContext, ImGuiKeyModFlags, ImDrawList};") 41 | .raw_line("pub use imgui_sys::{ImGuiMouseButton, ImGuiDragDropFlags};") 42 | .whitelist_recursively(false) 43 | .whitelist_function("ImPlot.*") 44 | .whitelist_type("ImPlot.*") 45 | // We do want to create bindings for the scalar typedefs 46 | .whitelist_type("Im[U|S][0-9]{1,2}") 47 | // Remove some functions that would take a variable-argument list 48 | .blacklist_function("ImPlot_AnnotateVVec4") 49 | .blacklist_function("ImPlot_AnnotateVStr") 50 | .blacklist_function("ImPlot_AnnotateClampedVVec4") 51 | .blacklist_function("ImPlot_AnnotateClampedVStr") 52 | .generate() 53 | .expect("Unable to generate bindings"); 54 | 55 | // The above type re-export shenanigans make bindgen unable to derive Copy, Clone and Debug on 56 | // some types, but they would work - we hence manually re-add them here. 57 | let mut bindings_string = bindings.to_string(); 58 | ["ImPlotInputMap", "ImPlotStyle"].iter().for_each(|name| { 59 | bindings_string = bindings_string.replace( 60 | &format!("pub struct {}", name), 61 | &format!("#[derive(Clone, Copy, Debug)]\npub struct {}", name), 62 | ); 63 | }); 64 | 65 | // Finally we write the bindings to a file. 66 | let out_path = sys_crate_path.join("src"); 67 | let mut out_file = 68 | std::fs::File::create(&out_path.join("bindings.rs")).expect("Could not open bindings file"); 69 | out_file 70 | .write_all(&bindings_string.into_bytes()[..]) 71 | .expect("Couldn't write bindings"); 72 | } 73 | -------------------------------------------------------------------------------- /implot-sys/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "implot-sys" 3 | version = "0.6.0" 4 | edition = "2018" 5 | authors = ["Sandro Merkli", "implot-rs contributors"] 6 | description = "Raw FFI bindings to implot" 7 | homepage = "https://github.com/4bb4/implot-rs" 8 | repository = "https://github.com/4bb4/implot-rs" 9 | license = "MIT/Apache-2.0" 10 | categories = ["gui", "external-ffi-bindings"] 11 | build = "build.rs" 12 | links = "implot" 13 | 14 | [dependencies] 15 | imgui-sys = "0.8.0" 16 | 17 | [build-dependencies] 18 | cc = "1.0" 19 | -------------------------------------------------------------------------------- /implot-sys/build.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | // This is taken pretty vanilla from 4 | // https://github.com/Gekkio/imgui-rs/blob/master/imgui-sys/build.rs 5 | // for now, but expected to diverge from that over time. 6 | use std::{env, fs, io, path::Path}; 7 | 8 | const CPP_FILES: &[&str] = &[ 9 | "third-party/cimplot/cimplot.cpp", 10 | "third-party/cimplot/implot/implot.cpp", 11 | "third-party/cimplot/implot/implot_items.cpp", 12 | "third-party/cimplot/implot/implot_demo.cpp", // Could remove this if demo not used 13 | ]; 14 | 15 | const IMPLOT_INCLUDE_DIRECTORIES: &[&str] = &["third-party/cimplot/implot/"]; 16 | 17 | fn assert_file_exists(path: &str) -> io::Result<()> { 18 | match fs::metadata(path) { 19 | Ok(_) => Ok(()), 20 | Err(ref e) if e.kind() == io::ErrorKind::NotFound => { 21 | panic!( 22 | "Can't access {}. Did you forget to fetch git submodules?", 23 | path 24 | ); 25 | } 26 | Err(e) => Err(e), 27 | } 28 | } 29 | 30 | fn main() -> io::Result<()> { 31 | // --- Compile cimgui 32 | let mut build = cc::Build::new(); 33 | build.cpp(true); 34 | 35 | // Take over imgui preprocessor defines from the imgui-sys crate. 36 | // Taken from https://github.com/aloucks/imguizmo-rs/blob/master/imguizmo-sys/build.rs 37 | for (key, val) in env::vars().filter(|(key, _)| key.starts_with("DEP_IMGUI_DEFINE_")) { 38 | let key = key.trim_start_matches("DEP_IMGUI_DEFINE_"); 39 | let val = if !val.is_empty() { 40 | Some(val.as_str()) 41 | } else { 42 | None 43 | }; 44 | build.define(key, val); 45 | } 46 | 47 | let cimgui_include_path = 48 | env::var_os("DEP_IMGUI_THIRD_PARTY").expect("DEP_IMGUI_THIRD_PARTY not defined"); 49 | let imgui_include_path = Path::new(&cimgui_include_path).join("imgui"); 50 | build.include(&cimgui_include_path); 51 | build.include(&imgui_include_path); 52 | for path in IMPLOT_INCLUDE_DIRECTORIES { 53 | build.include(path); 54 | } 55 | 56 | // Taken from the imgui-sys build as well 57 | build.flag_if_supported("-Wno-return-type-c-linkage"); 58 | build.flag_if_supported("-Wno-unused-parameter"); 59 | build.flag_if_supported("-std=c++11"); 60 | for path in CPP_FILES { 61 | assert_file_exists(path)?; 62 | build.file(path); 63 | } 64 | build.compile("cimplot"); 65 | Ok(()) 66 | } 67 | -------------------------------------------------------------------------------- /implot-sys/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_upper_case_globals)] 2 | #![allow(non_camel_case_types)] 3 | #![allow(non_snake_case)] 4 | 5 | // just for linking for tests 6 | #[cfg(test)] 7 | use imgui_sys; 8 | 9 | use std::ops::Range; 10 | include!("bindings.rs"); 11 | 12 | impl From> for ImPlotRange { 13 | fn from(from: Range) -> Self { 14 | ImPlotRange { 15 | Min: from.start, 16 | Max: from.end, 17 | } 18 | } 19 | } 20 | 21 | impl From<[f64; 2]> for ImPlotRange { 22 | fn from(from: [f64; 2]) -> Self { 23 | ImPlotRange { 24 | Min: from[0], 25 | Max: from[1], 26 | } 27 | } 28 | } 29 | 30 | impl From<(f64, f64)> for ImPlotRange { 31 | fn from(from: (f64, f64)) -> Self { 32 | ImPlotRange { 33 | Min: from.0, 34 | Max: from.1, 35 | } 36 | } 37 | } 38 | 39 | impl From for ImPlotRange { 40 | fn from(from: ImVec2) -> Self { 41 | ImPlotRange { 42 | Min: from.x as f64, 43 | Max: from.y as f64, 44 | } 45 | } 46 | } 47 | 48 | #[cfg(test)] 49 | mod tests { 50 | use super::*; 51 | 52 | #[test] 53 | fn test_plot_range_from_range() { 54 | let r = 5.0..7.0; 55 | let im_range: ImPlotRange = r.clone().into(); 56 | assert_eq!(im_range.Min, r.start); 57 | assert_eq!(im_range.Max, r.end); 58 | 59 | let arr = [7.0, 8.0]; 60 | let im_range: ImPlotRange = arr.clone().into(); 61 | assert_eq!(im_range.Min, arr[0]); 62 | assert_eq!(im_range.Max, arr[1]); 63 | 64 | let tuple = (12.0, 19.0); 65 | let im_range: ImPlotRange = tuple.clone().into(); 66 | assert_eq!(im_range.Min, tuple.0); 67 | assert_eq!(im_range.Max, tuple.1); 68 | 69 | let imvec = imgui_sys::ImVec2::new(33.0, 55.0); 70 | let im_range: ImPlotRange = imvec.clone().into(); 71 | assert_eq!(im_range.Min, imvec.x as f64); 72 | assert_eq!(im_range.Max, imvec.y as f64); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/context.rs: -------------------------------------------------------------------------------- 1 | //! Module for handling the ImPlot context. This is modeled quite directly after how 2 | //! this is dealt with in imgui-rs, because it follows the same concepts and doing this 3 | //! also helps readability if one is already familiar with the imgui code. 4 | 5 | use parking_lot::ReentrantMutex; 6 | 7 | use crate::sys; 8 | use crate::PlotUi; 9 | /// An implot context. 10 | /// 11 | /// A context is required to do most of the things this library provides. While this was created 12 | /// implicitly in earlier versions of the library, it is now created explicitly. These contexts 13 | /// cannot currently be disabled through the high level API. This could be implemented though, 14 | /// if you need multiple contexts that you can switch around between, file an issue. 15 | #[rustversion::attr(since(1.48), doc(alias = "ImPlotContext"))] 16 | pub struct Context { 17 | raw: *mut sys::ImPlotContext, 18 | } 19 | 20 | // This mutex is used to guard any accesses to the context 21 | static CTX_MUTEX: ReentrantMutex<()> = parking_lot::const_reentrant_mutex(()); 22 | 23 | /// Check if there is no current context defined by calling into the C++ API 24 | fn no_current_context() -> bool { 25 | let ctx = unsafe { sys::ImPlot_GetCurrentContext() }; 26 | ctx.is_null() 27 | } 28 | 29 | impl Context { 30 | /// Create a context. This will also activate the context in ImPlot, and hence creating 31 | /// a second context when one already exists is an error and will panic. 32 | pub fn create() -> Self { 33 | let _guard = CTX_MUTEX.lock(); 34 | assert!( 35 | no_current_context(), 36 | "A new active context cannot be created, because another one already exists" 37 | ); 38 | 39 | let ctx = unsafe { sys::ImPlot_CreateContext() }; 40 | unsafe { 41 | sys::ImPlot_SetCurrentContext(ctx); 42 | } 43 | Self { raw: ctx } 44 | } 45 | 46 | /// Get a "plot ui" struct, this will be used to build actual plots and is quite 47 | /// analogous to imgui-rs' "Ui" struct. 48 | pub fn get_plot_ui(&self) -> PlotUi { 49 | PlotUi { context: self } 50 | } 51 | 52 | /// Use light colors for the implot style. 53 | /// 54 | /// This will eventually be exposed more thoroughly in the form of ImPlotStyle, 55 | /// but for now this allows one to at least easily set the color preset. 56 | pub fn use_light_colors(&self) { 57 | unsafe { 58 | let style = sys::ImPlot_GetStyle(); 59 | assert_ne!(style, std::ptr::null_mut()); 60 | sys::ImPlot_StyleColorsLight(style); 61 | } 62 | } 63 | 64 | /// Use dark colors for the implot style. 65 | /// 66 | /// This will eventually be exposed more thoroughly in the form of ImPlotStyle, 67 | /// but for now this allows one to at least easily set the color preset. 68 | pub fn use_dark_colors(&self) { 69 | unsafe { 70 | let style = sys::ImPlot_GetStyle(); 71 | assert_ne!(style, std::ptr::null_mut()); 72 | sys::ImPlot_StyleColorsDark(style); 73 | } 74 | } 75 | 76 | /// Use classic colors for the implot style. 77 | /// 78 | /// This will eventually be exposed more thoroughly in the form of ImPlotStyle, 79 | /// but for now this allows one to at least easily set the color preset. 80 | pub fn use_classic_colors(&self) { 81 | unsafe { 82 | let style = sys::ImPlot_GetStyle(); 83 | assert_ne!(style, std::ptr::null_mut()); 84 | sys::ImPlot_StyleColorsClassic(style); 85 | } 86 | } 87 | } 88 | 89 | impl Drop for Context { 90 | fn drop(&mut self) { 91 | let _guard = CTX_MUTEX.lock(); 92 | unsafe { 93 | sys::ImPlot_DestroyContext(self.raw); 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! # Rust bindings to ImPlot 2 | //! 3 | //! This crate contains idiomatic bindings to the C++ [implot library](https://github.com/epezent/implot), 4 | //! which use the bindings exposed by the `implot-sys` crate. An attempt is made to keep 5 | //! documentation here somewhat self-contained, but when in doubt, the documentation of implot 6 | //! itself (in particular also the demo code [here](https://github.com/epezent/implot/blob/master/implot_demo.cpp)) 7 | //! should help as well. 8 | //! 9 | //! For usage examples, see the `implot-examples` crate - it contains standalone runnable examples 10 | //! that showcase the API and features of this crate. The [Github readme](https://github.com/4bb4/implot-rs) 11 | //! lists the features that are already implemented as idiomatic bindings. For everything else, if 12 | //! you'd really like a particular feature, file an issue and it'll be given priority for wrapping, 13 | //! or directly contribute a PR, or use the low-level bindings directly for the time being. 14 | //! 15 | //! If you've seen a construct or feature in C++ implot and can't find it here, try searching for 16 | //! the C++ name - some doc aliases are defined to increase the chances of that working. If this 17 | //! does not yield any results, you can also try cloning the source and doing a full-text search to 18 | //! see if the feature is used somewhere internally the code. 19 | use implot_sys as sys; 20 | 21 | // TODO(4bb4) facade-wrap these? 22 | pub use self::{context::*, plot::*, plot_elements::*}; 23 | use std::os::raw::c_char; 24 | pub use sys::{ImPlotLimits, ImPlotPoint, ImPlotRange, ImVec2, ImVec4}; 25 | 26 | mod context; 27 | mod plot; 28 | mod plot_elements; 29 | 30 | // The bindings for some reason don't contain this - it has to match the IMPLOT_AUTO from 31 | // the original C++ header for things to work properly. 32 | const IMPLOT_AUTO: i32 = -1; 33 | 34 | // Number of Y axes, this is used in a bunch of places for storing things like settings. 35 | // If this changes, also change the YAxisChoice enum. 36 | const NUMBER_OF_Y_AXES: usize = 3; 37 | 38 | /// Choice of Y axis. This an enum instead of just an integer so as to make it impossible 39 | /// to select a Y axis that is not present - this makes it easier to avoid `Result`-type 40 | /// return values on functions that could otherwise not really fail. 41 | // Implementation note: This enum is converted straight to an usize index in a few places 42 | // so we can store data about individual axes in arrays, so this pretty much should stay 43 | // just a mapping of words to numbers. 44 | #[rustversion::attr(since(1.48), doc(alias = "ImPlotYAxis"))] 45 | #[derive(Clone)] 46 | #[repr(u32)] 47 | pub enum YAxisChoice { 48 | First = sys::ImPlotYAxis__ImPlotYAxis_1, 49 | Second = sys::ImPlotYAxis__ImPlotYAxis_2, 50 | Third = sys::ImPlotYAxis__ImPlotYAxis_3, 51 | } 52 | 53 | /// Turn an Option into an i32. Picks IMPLOT_AUTO for None. 54 | #[rustversion::attr(since(1.48), doc(alias = "IMPLOT_AUTO"))] 55 | fn y_axis_choice_option_to_i32(y_axis_choice: Option) -> i32 { 56 | match y_axis_choice { 57 | Some(choice) => choice as i32, 58 | None => IMPLOT_AUTO, 59 | } 60 | } 61 | 62 | /// A temporary reference for building plots. This does not really do anything on its own at 63 | /// this point, but it is used to enforce that a context is created and active for other features, 64 | /// such as creating plots. 65 | pub struct PlotUi<'ui> { 66 | context: &'ui Context, 67 | } 68 | 69 | // --- Markers, color maps, style variables, legend location ---------------------------------- 70 | /// Markers, documentation copied from implot.h for convenience. 71 | #[rustversion::attr(since(1.48), doc(alias = "ImPlotMarker"))] 72 | #[repr(i32)] 73 | #[derive(Copy, Clone, Debug)] 74 | pub enum Marker { 75 | /// no marker 76 | None = sys::ImPlotMarker__ImPlotMarker_None, 77 | /// a circle marker will be rendered at each point 78 | Circle = sys::ImPlotMarker__ImPlotMarker_Circle, 79 | /// a square maker will be rendered at each point 80 | Square = sys::ImPlotMarker__ImPlotMarker_Square, 81 | /// a diamond marker will be rendered at each point 82 | Diamond = sys::ImPlotMarker__ImPlotMarker_Diamond, 83 | /// an upward-pointing triangle marker will up rendered at each point 84 | Up = sys::ImPlotMarker__ImPlotMarker_Up, 85 | /// an downward-pointing triangle marker will up rendered at each point 86 | Down = sys::ImPlotMarker__ImPlotMarker_Down, 87 | /// an leftward-pointing triangle marker will up rendered at each point 88 | Left = sys::ImPlotMarker__ImPlotMarker_Left, 89 | /// an rightward-pointing triangle marker will up rendered at each point 90 | Right = sys::ImPlotMarker__ImPlotMarker_Right, 91 | /// a cross marker will be rendered at each point (not filled) 92 | Cross = sys::ImPlotMarker__ImPlotMarker_Cross, 93 | /// a plus marker will be rendered at each point (not filled) 94 | Plus = sys::ImPlotMarker__ImPlotMarker_Plus, 95 | /// a asterisk marker will be rendered at each point (not filled) 96 | Asterisk = sys::ImPlotMarker__ImPlotMarker_Asterisk, 97 | } 98 | 99 | /// Colorable plot elements. These are called "ImPlotCol" in ImPlot itself, but I found that 100 | /// name somewhat confusing because we are not referring to colors, but _which_ thing can 101 | /// be colored - hence I added the "Element". 102 | #[rustversion::attr(since(1.48), doc(alias = "ImPlotCol"))] 103 | #[repr(u32)] 104 | #[derive(Copy, Clone, Debug)] 105 | pub enum PlotColorElement { 106 | /// Plot line/outline color (defaults to next unused color in current colormap) 107 | Line = sys::ImPlotCol__ImPlotCol_Line, 108 | /// Plot fill color for bars (defaults to the current line color) 109 | Fill = sys::ImPlotCol__ImPlotCol_Fill, 110 | /// Marker outline color (defaults to the current line color) 111 | MarkerOutline = sys::ImPlotCol__ImPlotCol_MarkerOutline, 112 | /// Marker fill color (defaults to the current line color) 113 | MarkerFill = sys::ImPlotCol__ImPlotCol_MarkerFill, 114 | /// Error bar color (defaults to text color) 115 | ErrorBar = sys::ImPlotCol__ImPlotCol_ErrorBar, 116 | /// Plot frame background color (defaults to FRAME_BG) 117 | FrameBg = sys::ImPlotCol__ImPlotCol_FrameBg, 118 | /// Plot area background color (defaults to WINDOW_BG) 119 | PlotBg = sys::ImPlotCol__ImPlotCol_PlotBg, 120 | /// Plot area border color (defaults to text color) 121 | PlotBorder = sys::ImPlotCol__ImPlotCol_PlotBorder, 122 | /// Legend background color (defaults to ImGuiCol_PopupBg) 123 | LegendBackground = sys::ImPlotCol__ImPlotCol_LegendBg, 124 | /// Legend border color (defaults to ImPlotCol_PlotBorder) 125 | LegendBorder = sys::ImPlotCol__ImPlotCol_LegendBorder, 126 | /// Legend text color (defaults to ImPlotCol_InlayText) 127 | LegendText = sys::ImPlotCol__ImPlotCol_LegendText, 128 | /// Plot title text color (defaults to ImGuiCol_Text) 129 | TitleText = sys::ImPlotCol__ImPlotCol_TitleText, 130 | /// Color of text appearing inside of plots (defaults to ImGuiCol_Text) 131 | InlayText = sys::ImPlotCol__ImPlotCol_InlayText, 132 | /// X-axis label and tick lables color (defaults to ImGuiCol_Text) 133 | XAxis = sys::ImPlotCol__ImPlotCol_XAxis, 134 | /// X-axis grid color (defaults to 25% ImPlotCol_XAxis) 135 | XAxisGrid = sys::ImPlotCol__ImPlotCol_XAxisGrid, 136 | /// Y-axis label and tick labels color (defaults to ImGuiCol_Text) 137 | YAxis = sys::ImPlotCol__ImPlotCol_YAxis, 138 | /// Y-axis grid color (defaults to 25% ImPlotCol_YAxis) 139 | YAxisGrid = sys::ImPlotCol__ImPlotCol_YAxisGrid, 140 | /// 2nd y-axis label and tick labels color (defaults to ImGuiCol_Text) 141 | YAxis2 = sys::ImPlotCol__ImPlotCol_YAxis2, 142 | /// 2nd y-axis grid/label color (defaults to 25% ImPlotCol_YAxis2) 143 | YAxisGrid2 = sys::ImPlotCol__ImPlotCol_YAxisGrid2, 144 | /// 3rd y-axis label and tick labels color (defaults to ImGuiCol_Text) 145 | YAxis3 = sys::ImPlotCol__ImPlotCol_YAxis3, 146 | /// 3rd y-axis grid/label color (defaults to 25% ImPlotCol_YAxis3) 147 | YAxisGrid3 = sys::ImPlotCol__ImPlotCol_YAxisGrid3, 148 | /// Box-selection color (defaults to yellow) 149 | Selection = sys::ImPlotCol__ImPlotCol_Selection, 150 | /// crosshairs color (defaults to ImPlotCol_PlotBorder) 151 | Crosshairs = sys::ImPlotCol__ImPlotCol_Crosshairs, 152 | /// Box-query color (defaults to green) 153 | Query = sys::ImPlotCol__ImPlotCol_Query, 154 | } 155 | 156 | /// Colormap choice. Documentation copied from implot.h for convenience. 157 | #[rustversion::attr(since(1.48), doc(alias = "ImPlotColormap"))] 158 | #[repr(u32)] 159 | #[derive(Copy, Clone, Debug)] 160 | pub enum Colormap { 161 | /// ImPlot default colormap (n=10). Called "Standard" here because Default is reserved. 162 | Standard = sys::ImPlotColormap__ImPlotColormap_Default, 163 | /// a.k.a. seaborn deep (n=10) 164 | Deep = sys::ImPlotColormap__ImPlotColormap_Deep, 165 | /// a.k.a. matplotlib "Set1" (n=9) 166 | Dark = sys::ImPlotColormap__ImPlotColormap_Dark, 167 | /// a.k.a. matplotlib "Pastel1" (n=9) 168 | Pastel = sys::ImPlotColormap__ImPlotColormap_Pastel, 169 | /// a.k.a. matplotlib "Paired" (n=12) 170 | Paired = sys::ImPlotColormap__ImPlotColormap_Paired, 171 | /// a.k.a. matplotlib "viridis" (n=11) 172 | Viridis = sys::ImPlotColormap__ImPlotColormap_Viridis, 173 | /// a.k.a. matplotlib "plasma" (n=11) 174 | Plasma = sys::ImPlotColormap__ImPlotColormap_Plasma, 175 | /// a.k.a. matplotlib/MATLAB "hot" (n=11) 176 | Hot = sys::ImPlotColormap__ImPlotColormap_Hot, 177 | /// a.k.a. matplotlib/MATLAB "cool" (n=11) 178 | Cool = sys::ImPlotColormap__ImPlotColormap_Cool, 179 | /// a.k.a. matplotlib/MATLAB "pink" (n=11) 180 | Pink = sys::ImPlotColormap__ImPlotColormap_Pink, 181 | /// a.k.a. MATLAB "jet" (n=11) 182 | Jet = sys::ImPlotColormap__ImPlotColormap_Jet, 183 | } 184 | 185 | /// Style variable choice, as in "which thing will be affected by a style setting". 186 | #[rustversion::attr(since(1.48), doc(alias = "ImPlotStyleVar"))] 187 | #[repr(u32)] 188 | #[derive(Copy, Clone, Debug)] 189 | pub enum StyleVar { 190 | /// f32, line weight in pixels 191 | LineWeight = sys::ImPlotStyleVar__ImPlotStyleVar_LineWeight, 192 | /// u32, marker specification 193 | Marker = sys::ImPlotStyleVar__ImPlotStyleVar_Marker, 194 | /// f32, marker size in pixels (roughly the marker's "radius") 195 | MarkerSize = sys::ImPlotStyleVar__ImPlotStyleVar_MarkerSize, 196 | /// f32, outline weight of markers in pixels 197 | MarkerWeight = sys::ImPlotStyleVar__ImPlotStyleVar_MarkerWeight, 198 | /// f32, alpha modifier applied to all plot item fills 199 | FillAlpha = sys::ImPlotStyleVar__ImPlotStyleVar_FillAlpha, 200 | /// f32, error bar whisker width in pixels 201 | ErrorBarSize = sys::ImPlotStyleVar__ImPlotStyleVar_ErrorBarSize, 202 | /// f32, error bar whisker weight in pixels 203 | ErrorBarWeight = sys::ImPlotStyleVar__ImPlotStyleVar_ErrorBarWeight, 204 | /// f32, digital channels bit height (at 1) in pixels 205 | DigitalBitHeight = sys::ImPlotStyleVar__ImPlotStyleVar_DigitalBitHeight, 206 | /// f32, digital channels bit padding gap in pixels 207 | DigitalBitGap = sys::ImPlotStyleVar__ImPlotStyleVar_DigitalBitGap, 208 | /// f32, thickness of border around plot area 209 | PlotBorderSize = sys::ImPlotStyleVar__ImPlotStyleVar_PlotBorderSize, 210 | /// f32, alpha multiplier applied to minor axis grid lines 211 | MinorAlpha = sys::ImPlotStyleVar__ImPlotStyleVar_MinorAlpha, 212 | /// ImVec2, major tick lengths for X and Y axes 213 | MajorTickLen = sys::ImPlotStyleVar__ImPlotStyleVar_MajorTickLen, 214 | /// ImVec2, minor tick lengths for X and Y axes 215 | MinorTickLen = sys::ImPlotStyleVar__ImPlotStyleVar_MinorTickLen, 216 | /// ImVec2, line thickness of major ticks 217 | MajorTickSize = sys::ImPlotStyleVar__ImPlotStyleVar_MajorTickSize, 218 | /// ImVec2, line thickness of minor ticks 219 | MinorTickSize = sys::ImPlotStyleVar__ImPlotStyleVar_MinorTickSize, 220 | /// ImVec2, line thickness of major grid lines 221 | MajorGridSize = sys::ImPlotStyleVar__ImPlotStyleVar_MajorGridSize, 222 | /// ImVec2, line thickness of minor grid lines 223 | MinorGridSize = sys::ImPlotStyleVar__ImPlotStyleVar_MinorGridSize, 224 | /// ImVec2, padding between widget frame and plot area and/or labels 225 | PlotPadding = sys::ImPlotStyleVar__ImPlotStyleVar_PlotPadding, 226 | /// ImVec2, padding between axes labels, tick labels, and plot edge 227 | LabelPadding = sys::ImPlotStyleVar__ImPlotStyleVar_LabelPadding, 228 | /// ImVec2, legend padding from top-left of plot 229 | LegendPadding = sys::ImPlotStyleVar__ImPlotStyleVar_LegendPadding, 230 | /// ImVec2, legend inner padding from legend edges 231 | LegendInnerPadding = sys::ImPlotStyleVar__ImPlotStyleVar_LegendInnerPadding, 232 | /// ImVec2, spacing between legend entries 233 | LegendSpacing = sys::ImPlotStyleVar__ImPlotStyleVar_LegendSpacing, 234 | /// ImVec2, padding between plot edge and interior info text 235 | MousePosPadding = sys::ImPlotStyleVar__ImPlotStyleVar_MousePosPadding, 236 | /// ImVec2, text padding around annotation labels 237 | AnnotationPadding = sys::ImPlotStyleVar__ImPlotStyleVar_AnnotationPadding, 238 | /// ImVec2, additional fit padding as a percentage of the fit extents 239 | /// (e.g. ImVec2(0.1f,0.1f) adds 10% to the fit extents of X and Y) 240 | FitPadding = sys::ImPlotStyleVar__ImPlotStyleVar_FitPadding, 241 | /// ImVec2, default size used when ImVec2(0,0) is passed to BeginPlot 242 | PlotDefaultSize = sys::ImPlotStyleVar__ImPlotStyleVar_PlotDefaultSize, 243 | /// ImVec2, minimum size plot frame can be when shrunk 244 | PlotMinSize = sys::ImPlotStyleVar__ImPlotStyleVar_PlotMinSize, 245 | } 246 | 247 | /// Used to position items on a plot (e.g. legends, labels, etc.) 248 | #[rustversion::attr(since(1.48), doc(alias = "ImPlotLocation"))] 249 | #[repr(u32)] 250 | #[derive(Copy, Clone, Debug)] 251 | pub enum PlotLocation { 252 | /// Center-center 253 | Center = sys::ImPlotLocation__ImPlotLocation_Center, 254 | /// Top-center 255 | North = sys::ImPlotLocation__ImPlotLocation_North, 256 | /// Bottom-center 257 | South = sys::ImPlotLocation__ImPlotLocation_South, 258 | /// Center-left 259 | West = sys::ImPlotLocation__ImPlotLocation_West, 260 | /// Center-right 261 | East = sys::ImPlotLocation__ImPlotLocation_East, 262 | /// Top-left 263 | NorthWest = sys::ImPlotLocation__ImPlotLocation_NorthWest, 264 | /// Top-right 265 | NorthEast = sys::ImPlotLocation__ImPlotLocation_NorthEast, 266 | /// Bottom-left 267 | SouthWest = sys::ImPlotLocation__ImPlotLocation_SouthWest, 268 | /// Bottom-right 269 | SouthEast = sys::ImPlotLocation__ImPlotLocation_SouthEast, 270 | } 271 | 272 | #[rustversion::attr(since(1.48), doc(alias = "ImPlotOrientation"))] 273 | /// Used to orient items on a plot (e.g. legends, labels, etc.) 274 | #[repr(u32)] 275 | #[derive(Copy, Clone, Debug)] 276 | pub enum PlotOrientation { 277 | Horizontal = sys::ImPlotOrientation__ImPlotOrientation_Horizontal, 278 | Vertical = sys::ImPlotOrientation__ImPlotOrientation_Vertical, 279 | } 280 | 281 | /// Switch to one of the built-in preset colormaps. If samples is greater than 1, the map will be 282 | /// linearly resampled. 283 | #[rustversion::attr(since(1.48), doc(alias = "SetColormap"))] 284 | pub fn set_colormap_from_preset(preset: Colormap, samples: u32) { 285 | unsafe { 286 | // "as" casts saturate as of Rust 1.45. This is safe here, and at least the enum 287 | // values are not expected to go outside the range of an i32 anyway, so there is no 288 | // risk of changed values. 289 | sys::ImPlot_SetColormapPlotColormap(preset as i32, samples as i32); 290 | } 291 | } 292 | 293 | /// Set a custom colormap in the form of a vector of colors. 294 | #[rustversion::attr(since(1.48), doc(alias = "SetColormap"))] 295 | pub fn set_colormap_from_vec(colors: Vec) { 296 | unsafe { 297 | sys::ImPlot_SetColormapVec4Ptr(colors.as_ptr(), colors.len() as i32); 298 | } 299 | } 300 | 301 | // --- Push/pop utils ------------------------------------------------------------------------- 302 | // Currently not in a struct yet. imgui-rs has some smarts about dealing with stacks, in particular 303 | // leak detection, which I'd like to replicate here at some point. 304 | /// Push a style color to the stack, giving an element and the four components of the color. 305 | /// The components should be between 0.0 (no intensity) and 1.0 (full intensity). 306 | /// The return value is a token that gets used for removing the style color from the stack again: 307 | /// ```no_run 308 | /// # use implot::{push_style_color, PlotColorElement}; 309 | /// let pushed_var = push_style_color(&PlotColorElement::Line, 1.0, 1.0, 1.0, 0.2); 310 | /// // Plot some things 311 | /// pushed_var.pop(); 312 | /// ``` 313 | #[rustversion::attr(since(1.48), doc(alias = "PushStyleColor"))] 314 | pub fn push_style_color( 315 | element: &PlotColorElement, 316 | red: f32, 317 | green: f32, 318 | blue: f32, 319 | alpha: f32, 320 | ) -> StyleColorToken { 321 | unsafe { 322 | sys::ImPlot_PushStyleColorVec4( 323 | *element as sys::ImPlotCol, 324 | sys::ImVec4 { 325 | x: red, 326 | y: green, 327 | z: blue, 328 | w: alpha, 329 | }, 330 | ); 331 | } 332 | StyleColorToken { was_popped: false } 333 | } 334 | 335 | /// Tracks a change pushed to the style color stack 336 | pub struct StyleColorToken { 337 | /// Whether this token has been popped or not. 338 | was_popped: bool, 339 | } 340 | 341 | impl StyleColorToken { 342 | #[rustversion::attr(since(1.48), doc(alias = "PopStyleColor"))] 343 | pub fn pop(mut self) { 344 | if self.was_popped { 345 | panic!("Attempted to pop a style color token twice.") 346 | } 347 | self.was_popped = true; 348 | unsafe { 349 | sys::ImPlot_PopStyleColor(1); 350 | } 351 | } 352 | } 353 | 354 | /// Push a f32 style variable to the stack. The returned token is used for removing 355 | /// the variable from the stack again: 356 | /// ```no_run 357 | /// # use implot::{push_style_var_f32, StyleVar}; 358 | /// let pushed_var = push_style_var_f32(&StyleVar::LineWeight, 11.0); 359 | /// // Plot some things 360 | /// pushed_var.pop(); 361 | /// ``` 362 | #[rustversion::attr(since(1.48), doc(alias = "PushStyleVar"))] 363 | pub fn push_style_var_f32(element: &StyleVar, value: f32) -> StyleVarToken { 364 | unsafe { 365 | sys::ImPlot_PushStyleVarFloat(*element as sys::ImPlotStyleVar, value); 366 | } 367 | StyleVarToken { was_popped: false } 368 | } 369 | 370 | /// Push an u32 style variable to the stack. The only i32 style variable is Marker 371 | /// at the moment, for that, use something like 372 | /// ```no_run 373 | /// # use implot::{push_style_var_i32, StyleVar, Marker}; 374 | /// let markerchoice = push_style_var_i32(&StyleVar::Marker, Marker::Cross as i32); 375 | /// // plot things 376 | /// markerchoice.pop() 377 | /// ``` 378 | #[rustversion::attr(since(1.48), doc(alias = "PushStyleVar"))] 379 | pub fn push_style_var_i32(element: &StyleVar, value: i32) -> StyleVarToken { 380 | unsafe { 381 | sys::ImPlot_PushStyleVarInt(*element as sys::ImPlotStyleVar, value); 382 | } 383 | StyleVarToken { was_popped: false } 384 | } 385 | 386 | /// Push an ImVec2 style variable to the stack. The returned token is used for removing 387 | /// the variable from the stack again. 388 | pub fn push_style_var_imvec2(element: &StyleVar, value: ImVec2) -> StyleVarToken { 389 | unsafe { 390 | sys::ImPlot_PushStyleVarVec2(*element as sys::ImPlotStyleVar, value); 391 | } 392 | StyleVarToken { was_popped: false } 393 | } 394 | 395 | /// Tracks a change pushed to the style variable stack 396 | pub struct StyleVarToken { 397 | /// Whether this token has been popped or not. 398 | was_popped: bool, 399 | } 400 | 401 | impl StyleVarToken { 402 | /// Pop this token from the stack. 403 | #[rustversion::attr(since(1.48), doc(alias = "PopStyleVar"))] 404 | pub fn pop(mut self) { 405 | if self.was_popped { 406 | panic!("Attempted to pop a style var token twice.") 407 | } 408 | self.was_popped = true; 409 | unsafe { 410 | sys::ImPlot_PopStyleVar(1); 411 | } 412 | } 413 | } 414 | 415 | // --- Miscellaneous ----------------------------------------------------------------------------- 416 | /// Returns true if the plot area in the current or most recent plot is hovered. 417 | #[rustversion::attr(since(1.48), doc(alias = "IsPlotHovered"))] 418 | pub fn is_plot_hovered() -> bool { 419 | unsafe { sys::ImPlot_IsPlotHovered() } 420 | } 421 | 422 | /// Returns true if the current or most recent plot is queried 423 | #[rustversion::attr(since(1.48), doc(alias = "IsPlotQueried"))] 424 | pub fn is_plot_queried() -> bool { 425 | unsafe { sys::ImPlot_IsPlotQueried() } 426 | } 427 | 428 | /// Returns the mouse position in x,y coordinates of the current or most recent plot, 429 | /// for the specified choice of Y axis. If `None` is the Y axis choice, that means the 430 | /// most recently selected Y axis is chosen. 431 | #[rustversion::attr(since(1.48), doc(alias = "GetPlotMousePos"))] 432 | pub fn get_plot_mouse_position(y_axis_choice: Option) -> ImPlotPoint { 433 | let y_axis_choice_i32 = y_axis_choice_option_to_i32(y_axis_choice); 434 | let mut point = ImPlotPoint { x: 0.0, y: 0.0 }; // doesn't seem to have default() 435 | unsafe { 436 | sys::ImPlot_GetPlotMousePos(&mut point as *mut ImPlotPoint, y_axis_choice_i32); 437 | } 438 | point 439 | } 440 | 441 | /// Convert pixels, given as an `ImVec2`, to a position in the current plot's coordinate system. 442 | /// Uses the specified Y axis, if any, otherwise whatever was previously chosen. 443 | #[rustversion::attr(since(1.48), doc(alias = "PixelsToPlot"))] 444 | pub fn pixels_to_plot_vec2( 445 | pixel_position: &ImVec2, 446 | y_axis_choice: Option, 447 | ) -> ImPlotPoint { 448 | let y_axis_choice_i32 = y_axis_choice_option_to_i32(y_axis_choice); 449 | let mut point = ImPlotPoint { x: 0.0, y: 0.0 }; // doesn't seem to have default() 450 | unsafe { 451 | sys::ImPlot_PixelsToPlotVec2( 452 | &mut point as *mut ImPlotPoint, 453 | *pixel_position, 454 | y_axis_choice_i32, 455 | ); 456 | } 457 | point 458 | } 459 | 460 | /// Convert pixels, given as floats `x` and `y`, to a position in the current plot's coordinate 461 | /// system. Uses the specified Y axis, if any, otherwise whatever was previously chosen. 462 | #[rustversion::attr(since(1.48), doc(alias = "PixelsToPlot"))] 463 | pub fn pixels_to_plot_f32( 464 | pixel_position_x: f32, 465 | pixel_position_y: f32, 466 | y_axis_choice: Option, 467 | ) -> ImPlotPoint { 468 | let y_axis_choice_i32 = y_axis_choice_option_to_i32(y_axis_choice); 469 | let mut point = ImPlotPoint { x: 0.0, y: 0.0 }; // doesn't seem to have default() 470 | unsafe { 471 | sys::ImPlot_PixelsToPlotFloat( 472 | &mut point as *mut ImPlotPoint, 473 | pixel_position_x, 474 | pixel_position_y, 475 | y_axis_choice_i32, 476 | ); 477 | } 478 | point 479 | } 480 | 481 | /// Convert a position in the current plot's coordinate system to pixels. Uses the specified Y 482 | /// axis, if any, otherwise whatever was previously chosen. 483 | /// 484 | #[rustversion::attr(since(1.48), doc(alias = "PlotToPixels"))] 485 | pub fn plot_to_pixels_vec2( 486 | plot_position: &ImPlotPoint, 487 | y_axis_choice: Option, 488 | ) -> ImVec2 { 489 | let y_axis_choice_i32 = y_axis_choice_option_to_i32(y_axis_choice); 490 | let mut pixel_position = ImVec2 { x: 0.0, y: 0.0 }; // doesn't seem to have default() 491 | unsafe { 492 | sys::ImPlot_PlotToPixelsPlotPoInt( 493 | &mut pixel_position as *mut ImVec2, 494 | *plot_position, 495 | y_axis_choice_i32, 496 | ); 497 | } 498 | pixel_position 499 | } 500 | 501 | /// Convert a position in the current plot's coordinate system to pixels. Uses the specified Y 502 | /// axis, if any, otherwise whatever was previously chosen. 503 | #[rustversion::attr(since(1.48), doc(alias = "PlotToPixels"))] 504 | pub fn plot_to_pixels_f32( 505 | plot_position_x: f64, 506 | plot_position_y: f64, 507 | y_axis_choice: Option, 508 | ) -> ImVec2 { 509 | let y_axis_choice_i32 = y_axis_choice_option_to_i32(y_axis_choice); 510 | let mut pixel_position = ImVec2 { x: 0.0, y: 0.0 }; // doesn't seem to have default() 511 | unsafe { 512 | sys::ImPlot_PlotToPixelsdouble( 513 | &mut pixel_position as *mut ImVec2, 514 | plot_position_x, 515 | plot_position_y, 516 | y_axis_choice_i32, 517 | ); 518 | } 519 | pixel_position 520 | } 521 | 522 | /// Returns the current or most recent plot axis range for the specified choice of Y axis. If 523 | /// `None` is the Y axis choice, that means the most recently selected Y axis is chosen. 524 | #[rustversion::attr(since(1.48), doc(alias = "GetPlotLimits"))] 525 | pub fn get_plot_limits(y_axis_choice: Option) -> ImPlotLimits { 526 | let y_axis_choice_i32 = y_axis_choice_option_to_i32(y_axis_choice); 527 | // ImPlotLimits doesn't seem to have default() 528 | let mut limits = ImPlotLimits { 529 | X: ImPlotRange { Min: 0.0, Max: 0.0 }, 530 | Y: ImPlotRange { Min: 0.0, Max: 0.0 }, 531 | }; 532 | unsafe { 533 | sys::ImPlot_GetPlotLimits(&mut limits as *mut ImPlotLimits, y_axis_choice_i32); 534 | } 535 | limits 536 | } 537 | 538 | /// Returns the query limits of the current or most recent plot, for the specified choice of Y 539 | /// axis. If `None` is the Y axis choice, that means the most recently selected Y axis is chosen. 540 | #[rustversion::attr(since(1.48), doc(alias = "GetPlotQuery"))] 541 | pub fn get_plot_query(y_axis_choice: Option) -> ImPlotLimits { 542 | let y_axis_choice_i32 = y_axis_choice_option_to_i32(y_axis_choice); 543 | // ImPlotLimits doesn't seem to have default() 544 | let mut limits = ImPlotLimits { 545 | X: ImPlotRange { Min: 0.0, Max: 0.0 }, 546 | Y: ImPlotRange { Min: 0.0, Max: 0.0 }, 547 | }; 548 | unsafe { 549 | sys::ImPlot_GetPlotQuery(&mut limits as *mut ImPlotLimits, y_axis_choice_i32); 550 | } 551 | limits 552 | } 553 | 554 | /// Set the Y axis to be used for any upcoming plot elements 555 | #[rustversion::attr(since(1.48), doc(alias = "SetPlotYAxis"))] 556 | pub fn set_plot_y_axis(y_axis_choice: YAxisChoice) { 557 | unsafe { 558 | sys::ImPlot_SetPlotYAxis(y_axis_choice as i32); 559 | } 560 | } 561 | 562 | /// Returns true if the XAxis plot area in the current plot is hovered. 563 | #[rustversion::attr(since(1.48), doc(alias = "IsPlotXAxisHovered"))] 564 | pub fn is_plot_x_axis_hovered() -> bool { 565 | unsafe { sys::ImPlot_IsPlotXAxisHovered() } 566 | } 567 | 568 | /// Returns true if the Y axis area of the given Y axis choice in the current plot is hovered. If 569 | /// `None` is the Y axis choice, that means the most recently selected Y axis is chosen. 570 | #[rustversion::attr(since(1.48), doc(alias = "IsPlotYAxisHovered"))] 571 | pub fn is_plot_y_axis_hovered(y_axis_choice: Option) -> bool { 572 | let y_axis_choice_i32 = y_axis_choice_option_to_i32(y_axis_choice); 573 | unsafe { sys::ImPlot_IsPlotYAxisHovered(y_axis_choice_i32) } 574 | } 575 | 576 | /// Returns true if the given item in the legend of the current plot is hovered. 577 | pub fn is_legend_entry_hovered(legend_entry: &str) -> bool { 578 | unsafe { sys::ImPlot_IsLegendEntryHovered(legend_entry.as_ptr() as *const c_char) } 579 | } 580 | 581 | // --- Demo window ------------------------------------------------------------------------------- 582 | /// Show the demo window for poking around what functionality implot has to 583 | /// offer. Note that not all of this is necessarily implemented in implot-rs 584 | /// already - if you find something missing you'd really like, raise an issue. 585 | // This requires implot_demo.cpp to be in the list of sources in implot-sys. 586 | #[rustversion::attr(since(1.48), doc(alias = "ShowDemoWindow"))] 587 | pub fn show_demo_window(show: &mut bool) { 588 | unsafe { 589 | implot_sys::ImPlot_ShowDemoWindow(show); 590 | } 591 | } 592 | -------------------------------------------------------------------------------- /src/plot.rs: -------------------------------------------------------------------------------- 1 | //! # Plot module 2 | //! 3 | //! This module defines the `Plot` struct, which is used to create a 2D plot that will 4 | //! contain all other objects that can be created using this library. 5 | use crate::{Context, PlotLocation, PlotOrientation, PlotUi, YAxisChoice, NUMBER_OF_Y_AXES}; 6 | use bitflags::bitflags; 7 | pub use imgui::Condition; 8 | use implot_sys as sys; 9 | use std::ffi::CString; 10 | use std::os::raw::c_char; 11 | use std::{cell::RefCell, rc::Rc}; 12 | pub use sys::{ImPlotLimits, ImPlotPoint, ImPlotRange, ImVec2, ImVec4}; 13 | 14 | const DEFAULT_PLOT_SIZE_X: f32 = 400.0; 15 | const DEFAULT_PLOT_SIZE_Y: f32 = 400.0; 16 | 17 | #[rustversion::attr(since(1.48), doc(alias = "ImPlotFlags"))] 18 | bitflags! { 19 | /// Flags for customizing plot behavior and interaction. Documentation copied from implot.h for 20 | /// convenience. ImPlot itself also has a "CanvasOnly" flag, which can be emulated here with 21 | /// the combination of `NO_LEGEND`, `NO_MENUS`, `NO_BOX_SELECT` and `NO_MOUSE_POSITION`. 22 | #[repr(transparent)] 23 | pub struct PlotFlags: u32 { 24 | /// "Default" according to original docs 25 | const NONE = sys::ImPlotFlags__ImPlotFlags_None; 26 | /// Plot items will not be highlighted when their legend entry is hovered 27 | const NO_LEGEND = sys::ImPlotFlags__ImPlotFlags_NoLegend; 28 | /// The user will not be able to open context menus with double-right click 29 | const NO_MENUS = sys::ImPlotFlags__ImPlotFlags_NoMenus; 30 | /// The user will not be able to box-select with right-mouse 31 | const NO_BOX_SELECT = sys::ImPlotFlags__ImPlotFlags_NoBoxSelect; 32 | /// The mouse position, in plot coordinates, will not be displayed 33 | const NO_MOUSE_POSITION = sys::ImPlotFlags__ImPlotFlags_NoMousePos; 34 | /// Plot items will not be highlighted when their legend entry is hovered 35 | const NO_HIGHLIGHT = sys::ImPlotFlags__ImPlotFlags_NoHighlight; 36 | /// A child window region will not be used to capture mouse scroll (can boost performance 37 | /// for single ImGui window applications) 38 | const NO_CHILD = sys::ImPlotFlags__ImPlotFlags_NoChild; 39 | /// Use an aspect ratio of 1:1 for the plot 40 | const AXIS_EQUAL = sys::ImPlotFlags__ImPlotFlags_Equal; 41 | /// Enable a 2nd y axis 42 | const Y_AXIS_2 = sys::ImPlotFlags__ImPlotFlags_YAxis2; 43 | /// Enable a 3nd y axis 44 | const Y_AXIS_3 = sys::ImPlotFlags__ImPlotFlags_YAxis3; 45 | /// The user will be able to draw query rects with middle-mouse 46 | const QUERY = sys::ImPlotFlags__ImPlotFlags_Query; 47 | /// The default mouse cursor will be replaced with a crosshair when hovered 48 | const CROSSHAIRS = sys::ImPlotFlags__ImPlotFlags_Crosshairs; 49 | /// Plot data outside the plot area will be culled from rendering 50 | const ANTIALIASED = sys::ImPlotFlags__ImPlotFlags_AntiAliased; 51 | } 52 | } 53 | 54 | #[rustversion::attr(since(1.48), doc(alias = "ImPlotAxisFlags"))] 55 | bitflags! { 56 | /// Axis flags. Documentation copied from implot.h for convenience. ImPlot itself also 57 | /// has `Lock`, which combines `LOCK_MIN` and `LOCK_MAX`, and `NoDecorations`, which combines 58 | /// `NO_GRID_LINES`, `NO_TICK_MARKS` and `NO_TICK_LABELS`. 59 | #[repr(transparent)] 60 | pub struct AxisFlags: u32 { 61 | /// "Default" according to original docs 62 | const NONE = sys::ImPlotAxisFlags__ImPlotAxisFlags_None; 63 | /// Grid lines will not be displayed 64 | const NO_GRID_LINES = sys::ImPlotAxisFlags__ImPlotAxisFlags_NoGridLines; 65 | /// Tick marks will not be displayed 66 | const NO_TICK_MARKS = sys::ImPlotAxisFlags__ImPlotAxisFlags_NoTickMarks; 67 | /// Text labels will not be displayed 68 | const NO_TICK_LABELS = sys::ImPlotAxisFlags__ImPlotAxisFlags_NoTickLabels; 69 | /// A logartithmic (base 10) axis scale will be used (mutually exclusive with AxisFlags::TIME) 70 | const LOG_SCALE = sys::ImPlotAxisFlags__ImPlotAxisFlags_LogScale; 71 | /// Axis will display date/time formatted labels (mutually exclusive with AxisFlags::LOG_SCALE) 72 | const TIME = sys::ImPlotAxisFlags__ImPlotAxisFlags_Time; 73 | /// The axis will be inverted 74 | const INVERT = sys::ImPlotAxisFlags__ImPlotAxisFlags_Invert; 75 | /// The axis minimum value will be locked when panning/zooming 76 | const LOCK_MIN = sys::ImPlotAxisFlags__ImPlotAxisFlags_LockMin; 77 | /// The axis maximum value will be locked when panning/zooming 78 | const LOCK_MAX = sys::ImPlotAxisFlags__ImPlotAxisFlags_LockMax; 79 | } 80 | } 81 | 82 | /// Internally-used struct for storing axis limits 83 | #[derive(Clone)] 84 | enum AxisLimitSpecification { 85 | /// Direct limits, specified as values 86 | Single(ImPlotRange, Condition), 87 | /// Limits that are linked to limits of other plots (via clones of the same Rc) 88 | Linked(Rc>), 89 | } 90 | 91 | /// Struct to represent an ImPlot. This is the main construct used to contain all kinds of plots in ImPlot. 92 | /// 93 | /// `Plot` is to be used (within an imgui window) with the following pattern: 94 | /// ```no_run 95 | /// # use implot; 96 | /// let plotting_context = implot::Context::create(); 97 | /// let plot_ui = plotting_context.get_plot_ui(); 98 | /// implot::Plot::new("my title") 99 | /// .size([300.0, 200.0]) // other things such as .x_label("some_label") can be added too 100 | /// .build(&plot_ui, || { 101 | /// // Do things such as plotting lines 102 | /// }); 103 | /// 104 | /// ``` 105 | /// (If you are coming from the C++ implementation or the C bindings: build() calls both 106 | /// begin() and end() internally) 107 | pub struct Plot { 108 | /// Title of the plot, shown on top. Stored as CString because that's what we'll use 109 | /// afterwards, and this ensures the CString itself will stay alive long enough for the plot. 110 | title: CString, 111 | /// Size of the plot in [x, y] direction, in the same units imgui uses. 112 | size: [f32; 2], 113 | /// Label of the x axis, shown on the bottom. Stored as CString because that's what we'll use 114 | /// afterwards, and this ensures the CString itself will stay alive long enough for the plot. 115 | x_label: CString, 116 | /// Label of the y axis, shown on the left. Stored as CString because that's what we'll use 117 | /// afterwards, and this ensures the CString itself will stay alive long enough for the plot. 118 | y_label: CString, 119 | /// X axis limits, if present 120 | x_limits: Option, 121 | /// Y axis limits, if present 122 | y_limits: [Option; NUMBER_OF_Y_AXES], 123 | /// Positions for custom X axis ticks, if any 124 | x_tick_positions: Option>, 125 | /// Labels for custom X axis ticks, if any. I'd prefer to store these together 126 | /// with the positions in one vector of an algebraic data type, but this would mean extra 127 | /// copies when it comes time to draw the plot because the C++ library expects separate lists. 128 | /// The data is stored as CStrings because those are null-terminated, and since we have to 129 | /// convert to null-terminated data anyway, we may as well do that directly instead of cloning 130 | /// Strings and converting them afterwards. 131 | x_tick_labels: Option>, 132 | /// Whether to also show the default X ticks when showing custom ticks or not 133 | show_x_default_ticks: bool, 134 | /// Positions for custom Y axis ticks, if any 135 | y_tick_positions: [Option>; NUMBER_OF_Y_AXES], 136 | /// Labels for custom Y axis ticks, if any. I'd prefer to store these together 137 | /// with the positions in one vector of an algebraic data type, but this would mean extra 138 | /// copies when it comes time to draw the plot because the C++ library expects separate lists. 139 | /// The data is stored as CStrings because those are null-terminated, and since we have to 140 | /// convert to null-terminated data anyway, we may as well do that directly instead of cloning 141 | /// Strings and converting them afterwards. 142 | y_tick_labels: [Option>; NUMBER_OF_Y_AXES], 143 | /// Whether to also show the default Y ticks when showing custom ticks or not 144 | show_y_default_ticks: [bool; NUMBER_OF_Y_AXES], 145 | /// Configuration for the legend, if specified. The tuple contains location, orientation 146 | /// and a boolean (true means legend is outside of plot, false means within). If nothing 147 | /// is set, implot's defaults are used. Note also that if these are set, then implot's 148 | /// interactive legend configuration does not work because it is overridden by the settings 149 | /// here. 150 | legend_configuration: Option<(PlotLocation, PlotOrientation, bool)>, 151 | /// Flags relating to the plot TODO(4bb4) make those into bitflags 152 | plot_flags: sys::ImPlotFlags, 153 | /// Flags relating to the X axis of the plot TODO(4bb4) make those into bitflags 154 | x_flags: sys::ImPlotAxisFlags, 155 | /// Flags relating to the each of the Y axes of the plot TODO(4bb4) make those into bitflags 156 | y_flags: [sys::ImPlotAxisFlags; NUMBER_OF_Y_AXES], 157 | } 158 | 159 | impl Plot { 160 | /// Create a new plot with some defaults set. Does not draw anything yet. 161 | /// Note that this uses antialiasing by default, unlike the C++ API. If you are seeing 162 | /// artifacts or weird rendering, try disabling it. 163 | /// 164 | /// # Panics 165 | /// Will panic if the title string contains internal null bytes. 166 | pub fn new(title: &str) -> Self { 167 | // Needed for initialization, see https://github.com/rust-lang/rust/issues/49147 168 | const POS_NONE: Option> = None; 169 | const TICK_NONE: Option> = None; 170 | 171 | // TODO(4bb4) question these defaults, maybe remove some of them 172 | Self { 173 | title: CString::new(title) 174 | .unwrap_or_else(|_| panic!("String contains internal null bytes: {}", title)), 175 | size: [DEFAULT_PLOT_SIZE_X, DEFAULT_PLOT_SIZE_Y], 176 | x_label: CString::new("").unwrap(), 177 | y_label: CString::new("").unwrap(), 178 | x_limits: None, 179 | y_limits: Default::default(), 180 | x_tick_positions: None, 181 | x_tick_labels: None, 182 | show_x_default_ticks: false, 183 | y_tick_positions: [POS_NONE; NUMBER_OF_Y_AXES], 184 | y_tick_labels: [TICK_NONE; NUMBER_OF_Y_AXES], 185 | show_y_default_ticks: [false; NUMBER_OF_Y_AXES], 186 | legend_configuration: None, 187 | plot_flags: PlotFlags::ANTIALIASED.bits() as sys::ImPlotFlags, 188 | x_flags: AxisFlags::NONE.bits() as sys::ImPlotAxisFlags, 189 | y_flags: [AxisFlags::NONE.bits() as sys::ImPlotAxisFlags; NUMBER_OF_Y_AXES], 190 | } 191 | } 192 | 193 | /// Sets the plot size, given as [size_x, size_y]. Units are the same as 194 | /// what imgui uses. TODO(4bb4) ... which is? I'm not sure it's pixels 195 | #[inline] 196 | pub fn size(mut self, size: [f32; 2]) -> Self { 197 | self.size = size; 198 | self 199 | } 200 | 201 | /// Set the x label of the plot 202 | /// 203 | /// # Panics 204 | /// Will panic if the label string contains internal null bytes. 205 | #[inline] 206 | pub fn x_label(mut self, label: &str) -> Self { 207 | self.x_label = CString::new(label) 208 | .unwrap_or_else(|_| panic!("String contains internal null bytes: {}", label)); 209 | self 210 | } 211 | 212 | /// Set the y label of the plot 213 | /// 214 | /// # Panics 215 | /// Will panic if the label string contains internal null bytes. 216 | #[inline] 217 | pub fn y_label(mut self, label: &str) -> Self { 218 | self.y_label = CString::new(label) 219 | .unwrap_or_else(|_| panic!("String contains internal null bytes: {}", label)); 220 | self 221 | } 222 | 223 | /// Set the x limits of the plot. 224 | /// 225 | /// Note: This conflicts with `linked_x_limits`, whichever is called last on plot construction 226 | /// takes effect. 227 | #[inline] 228 | pub fn x_limits>(mut self, limits: L, condition: Condition) -> Self { 229 | self.x_limits = Some(AxisLimitSpecification::Single(limits.into(), condition)); 230 | self 231 | } 232 | 233 | /// Set linked x limits for this plot. Pass clones of the same `Rc` into other plots 234 | /// to link their limits with the same values. 235 | /// 236 | /// Note: This conflicts with `x_limits`, whichever is called last on plot construction takes 237 | /// effect. 238 | #[inline] 239 | pub fn linked_x_limits(mut self, limits: Rc>) -> Self { 240 | self.x_limits = Some(AxisLimitSpecification::Linked(limits)); 241 | self 242 | } 243 | 244 | /// Set the Y limits of the plot for the given Y axis. Call multiple times with different 245 | /// `y_axis_choice` values to set for multiple axes, or use the convenience methods such as 246 | /// [`Plot::y1_limits`]. 247 | /// 248 | /// Note: This conflicts with `linked_y_limits`, whichever is called last on plot construction 249 | /// takes effect for a given axis. 250 | #[inline] 251 | pub fn y_limits>( 252 | mut self, 253 | limits: L, 254 | y_axis_choice: YAxisChoice, 255 | condition: Condition, 256 | ) -> Self { 257 | let axis_index = y_axis_choice as usize; 258 | self.y_limits[axis_index] = Some(AxisLimitSpecification::Single(limits.into(), condition)); 259 | self 260 | } 261 | 262 | /// Convenience function to directly set the Y limits for the first Y axis. To programmatically 263 | /// (or on demand) decide which axis to set limits for, use [`Plot::y_limits`] 264 | #[inline] 265 | pub fn y1_limits>(self, limits: L, condition: Condition) -> Self { 266 | self.y_limits(limits, YAxisChoice::First, condition) 267 | } 268 | 269 | /// Convenience function to directly set the Y limits for the second Y axis. To 270 | /// programmatically (or on demand) decide which axis to set limits for, use [`Plot::y_limits`] 271 | #[inline] 272 | pub fn y2_limits>(self, limits: L, condition: Condition) -> Self { 273 | self.y_limits(limits, YAxisChoice::Second, condition) 274 | } 275 | 276 | /// Convenience function to directly set the Y limits for the third Y axis. To programmatically 277 | /// (or on demand) decide which axis to set limits for, use [`Plot::y_limits`] 278 | #[inline] 279 | pub fn y3_limits>(self, limits: L, condition: Condition) -> Self { 280 | self.y_limits(limits, YAxisChoice::Third, condition) 281 | } 282 | 283 | /// Set linked Y limits of the plot for the given Y axis. Pass clones of the same `Rc` into 284 | /// other plots to link their limits with the same values. Call multiple times with different 285 | /// `y_axis_choice` values to set for multiple axes, or use the convenience methods such as 286 | /// [`Plot::y1_limits`]. 287 | /// 288 | /// Note: This conflicts with `y_limits`, whichever is called last on plot construction takes 289 | /// effect for a given axis. 290 | #[inline] 291 | pub fn linked_y_limits( 292 | mut self, 293 | limits: Rc>, 294 | y_axis_choice: YAxisChoice, 295 | ) -> Self { 296 | let axis_index = y_axis_choice as usize; 297 | self.y_limits[axis_index] = Some(AxisLimitSpecification::Linked(limits)); 298 | self 299 | } 300 | 301 | /// Convenience function to directly set linked Y limits for the first Y axis. To 302 | /// programmatically (or on demand) decide which axis to set limits for, use 303 | /// [`Plot::linked_y_limits`]. 304 | #[inline] 305 | pub fn linked_y1_limits(self, limits: Rc>) -> Self { 306 | self.linked_y_limits(limits, YAxisChoice::First) 307 | } 308 | 309 | /// Convenience function to directly set linked Y limits for the second Y axis. To 310 | /// programmatically (or on demand) decide which axis to set limits for, use 311 | /// [`Plot::linked_y_limits`]. 312 | #[inline] 313 | pub fn linked_y2_limits(self, limits: Rc>) -> Self { 314 | self.linked_y_limits(limits, YAxisChoice::Second) 315 | } 316 | 317 | /// Convenience function to directly set linked Y limits for the third Y axis. To 318 | /// programmatically (or on demand) decide which axis to set limits for, use 319 | /// [`Plot::linked_y_limits`]. 320 | #[inline] 321 | pub fn linked_y3_limits(self, limits: Rc>) -> Self { 322 | self.linked_y_limits(limits, YAxisChoice::Third) 323 | } 324 | 325 | /// Set X ticks without labels for the plot. The vector contains one label each in 326 | /// the form of a tuple `(label_position, label_string)`. The `show_default` setting 327 | /// determines whether the default ticks are also shown. 328 | #[inline] 329 | pub fn x_ticks(mut self, ticks: &[f64], show_default: bool) -> Self { 330 | self.x_tick_positions = Some(ticks.into()); 331 | self.show_x_default_ticks = show_default; 332 | self 333 | } 334 | 335 | /// Set X ticks without labels for the plot. The vector contains one label each in 336 | /// the form of a tuple `(label_position, label_string)`. The `show_default` setting 337 | /// determines whether the default ticks are also shown. 338 | #[inline] 339 | pub fn y_ticks( 340 | mut self, 341 | y_axis_choice: YAxisChoice, 342 | ticks: &[f64], 343 | show_default: bool, 344 | ) -> Self { 345 | let axis_index = y_axis_choice as usize; 346 | self.y_tick_positions[axis_index] = Some(ticks.into()); 347 | self.show_y_default_ticks[axis_index] = show_default; 348 | self 349 | } 350 | 351 | /// Set X ticks with labels for the plot. The vector contains one position and label 352 | /// each in the form of a tuple `(label_position, label_string)`. The `show_default` 353 | /// setting determines whether the default ticks are also shown. 354 | /// 355 | /// # Panics 356 | /// Will panic if any of the tick label strings contain internal null bytes. 357 | #[inline] 358 | pub fn x_ticks_with_labels( 359 | mut self, 360 | tick_labels: &[(f64, String)], 361 | show_default: bool, 362 | ) -> Self { 363 | self.x_tick_positions = Some(tick_labels.iter().map(|x| x.0).collect()); 364 | self.x_tick_labels = Some( 365 | tick_labels 366 | .iter() 367 | .map(|x| { 368 | CString::new(x.1.as_str()) 369 | .unwrap_or_else(|_| panic!("String contains internal null bytes: {}", x.1)) 370 | }) 371 | .collect(), 372 | ); 373 | self.show_x_default_ticks = show_default; 374 | self 375 | } 376 | 377 | /// Set Y ticks with labels for the plot. The vector contains one position and label 378 | /// each in the form of a tuple `(label_position, label_string)`. The `show_default` 379 | /// setting determines whether the default ticks are also shown. 380 | /// 381 | /// # Panics 382 | /// Will panic if any of the tick label strings contain internal null bytes. 383 | #[inline] 384 | pub fn y_ticks_with_labels( 385 | mut self, 386 | y_axis_choice: YAxisChoice, 387 | tick_labels: &[(f64, String)], 388 | show_default: bool, 389 | ) -> Self { 390 | let axis_index = y_axis_choice as usize; 391 | self.y_tick_positions[axis_index] = Some(tick_labels.iter().map(|x| x.0).collect()); 392 | self.y_tick_labels[axis_index] = Some( 393 | tick_labels 394 | .iter() 395 | .map(|x| { 396 | CString::new(x.1.as_str()) 397 | .unwrap_or_else(|_| panic!("String contains internal null bytes: {}", x.1)) 398 | }) 399 | .collect(), 400 | ); 401 | self.show_y_default_ticks[axis_index] = show_default; 402 | self 403 | } 404 | 405 | /// Set the plot flags, see the help for `PlotFlags` for what the available flags are 406 | #[inline] 407 | pub fn with_plot_flags(mut self, flags: &PlotFlags) -> Self { 408 | self.plot_flags = flags.bits() as sys::ImPlotFlags; 409 | self 410 | } 411 | 412 | /// Set the axis flags for the X axis in this plot 413 | #[inline] 414 | pub fn with_x_axis_flags(mut self, flags: &AxisFlags) -> Self { 415 | self.x_flags = flags.bits() as sys::ImPlotAxisFlags; 416 | self 417 | } 418 | 419 | /// Set the axis flags for the selected Y axis in this plot 420 | #[inline] 421 | pub fn with_y_axis_flags(mut self, y_axis_choice: YAxisChoice, flags: &AxisFlags) -> Self { 422 | let axis_index = y_axis_choice as usize; 423 | self.y_flags[axis_index] = flags.bits() as sys::ImPlotAxisFlags; 424 | self 425 | } 426 | 427 | /// Set the legend location, orientation and whether it is to be drawn outside the plot 428 | #[rustversion::attr(since(1.48), doc(alias = "SetLegendLocation"))] 429 | #[inline] 430 | pub fn with_legend_location( 431 | mut self, 432 | location: &PlotLocation, 433 | orientation: &PlotOrientation, 434 | outside: bool, 435 | ) -> Self { 436 | self.legend_configuration = Some((*location, *orientation, outside)); 437 | self 438 | } 439 | 440 | /// Internal helper function to set axis limits in case they are specified. 441 | fn maybe_set_axis_limits(&self) { 442 | // Limit-setting can either happen via direct limits or through linked limits. The version 443 | // of implot we link to here has different APIs for the two (separate per-axis calls for 444 | // direct, and one call for everything together for linked), hence the code here is a bit 445 | // clunky and takes the two approaches separately instead of a unified "match". 446 | 447 | // --- Direct limit-setting --- 448 | if let Some(AxisLimitSpecification::Single(limits, condition)) = &self.x_limits { 449 | unsafe { 450 | sys::ImPlot_SetNextPlotLimitsX( 451 | limits.Min, 452 | limits.Max, 453 | *condition as sys::ImGuiCond, 454 | ); 455 | } 456 | } 457 | 458 | self.y_limits 459 | .iter() 460 | .enumerate() 461 | .for_each(|(k, limit_spec)| { 462 | if let Some(AxisLimitSpecification::Single(limits, condition)) = limit_spec { 463 | unsafe { 464 | sys::ImPlot_SetNextPlotLimitsY( 465 | limits.Min, 466 | limits.Max, 467 | *condition as sys::ImGuiCond, 468 | k as i32, 469 | ); 470 | } 471 | } 472 | }); 473 | 474 | // --- Linked limit-setting --- 475 | let (xmin_pointer, xmax_pointer) = 476 | if let Some(AxisLimitSpecification::Linked(value)) = &self.x_limits { 477 | let mut borrowed = value.borrow_mut(); 478 | ( 479 | &mut (*borrowed).Min as *mut _, 480 | &mut (*borrowed).Max as *mut _, 481 | ) 482 | } else { 483 | (std::ptr::null_mut(), std::ptr::null_mut()) 484 | }; 485 | 486 | let y_limit_pointers: Vec<(*mut f64, *mut f64)> = self 487 | .y_limits 488 | .iter() 489 | .map(|limit_spec| { 490 | if let Some(AxisLimitSpecification::Linked(value)) = limit_spec { 491 | let mut borrowed = value.borrow_mut(); 492 | ( 493 | &mut (*borrowed).Min as *mut _, 494 | &mut (*borrowed).Max as *mut _, 495 | ) 496 | } else { 497 | (std::ptr::null_mut(), std::ptr::null_mut()) 498 | } 499 | }) 500 | .collect(); 501 | 502 | unsafe { 503 | // Calling this unconditionally here as calling it with all NULL pointers should not 504 | // affect anything. In terms of unsafety, the pointers should be OK as long as any plot 505 | // struct that has an Rc to the same data is alive. 506 | sys::ImPlot_LinkNextPlotLimits( 507 | xmin_pointer, 508 | xmax_pointer, 509 | y_limit_pointers[0].0, 510 | y_limit_pointers[0].1, 511 | y_limit_pointers[1].0, 512 | y_limit_pointers[1].1, 513 | y_limit_pointers[2].0, 514 | y_limit_pointers[2].1, 515 | ) 516 | } 517 | } 518 | 519 | /// Internal helper function to set tick labels in case they are specified. This does the 520 | /// preparation work that is the same for both the X and Y axis plots, then calls the 521 | /// "set next plot ticks" wrapper functions for both X and Y. 522 | fn maybe_set_tick_labels(&self) { 523 | // Show x ticks if they are available 524 | if self.x_tick_positions.is_some() && !self.x_tick_positions.as_ref().unwrap().is_empty() { 525 | let mut pointer_vec; // The vector of pointers we create has to have a longer lifetime 526 | let labels_pointer = if let Some(labels_value) = &self.x_tick_labels { 527 | pointer_vec = labels_value 528 | .iter() 529 | .map(|x| x.as_ptr() as *const c_char) 530 | .collect::>(); 531 | pointer_vec.as_mut_ptr() 532 | } else { 533 | std::ptr::null_mut() 534 | }; 535 | 536 | unsafe { 537 | sys::ImPlot_SetNextPlotTicksXdoublePtr( 538 | self.x_tick_positions.as_ref().unwrap().as_ptr(), 539 | self.x_tick_positions.as_ref().unwrap().len() as i32, 540 | labels_pointer, 541 | self.show_x_default_ticks, 542 | ) 543 | } 544 | } 545 | 546 | self.y_tick_positions 547 | .iter() 548 | .zip(self.y_tick_labels.iter()) 549 | .zip(self.show_y_default_ticks.iter()) 550 | .enumerate() 551 | .for_each(|(k, ((positions, labels), show_defaults))| { 552 | if positions.is_some() && !positions.as_ref().unwrap().is_empty() { 553 | // The vector of pointers we create has to have a longer lifetime 554 | let mut pointer_vec; 555 | let labels_pointer = if let Some(labels_value) = &labels { 556 | pointer_vec = labels_value 557 | .iter() 558 | .map(|x| x.as_ptr() as *const c_char) 559 | .collect::>(); 560 | pointer_vec.as_mut_ptr() 561 | } else { 562 | std::ptr::null_mut() 563 | }; 564 | 565 | unsafe { 566 | sys::ImPlot_SetNextPlotTicksYdoublePtr( 567 | positions.as_ref().unwrap().as_ptr(), 568 | positions.as_ref().unwrap().len() as i32, 569 | labels_pointer, 570 | *show_defaults, 571 | k as i32, 572 | ) 573 | } 574 | } 575 | }); 576 | } 577 | 578 | /// Attempt to show the plot. If this returns a token, the plot will actually 579 | /// be drawn. In this case, use the drawing functionality to draw things on the 580 | /// plot, and then call `end()` on the token when done with the plot. 581 | /// If none was returned, that means the plot is not rendered. 582 | /// 583 | /// For a convenient implementation of all this, use [`build()`](struct.Plot.html#method.build) 584 | /// instead. 585 | #[rustversion::attr(since(1.48), doc(alias = "BeginPlot"))] 586 | pub fn begin(&self, plot_ui: &PlotUi) -> Option { 587 | self.maybe_set_axis_limits(); 588 | self.maybe_set_tick_labels(); 589 | 590 | let should_render = unsafe { 591 | let size_vec: ImVec2 = ImVec2 { 592 | x: self.size[0], 593 | y: self.size[1], 594 | }; 595 | sys::ImPlot_BeginPlot( 596 | self.title.as_ptr(), 597 | self.x_label.as_ptr(), 598 | self.y_label.as_ptr(), 599 | size_vec, 600 | self.plot_flags, 601 | self.x_flags, 602 | self.y_flags[0], 603 | self.y_flags[1], 604 | self.y_flags[2], 605 | ) 606 | }; 607 | 608 | if should_render { 609 | // Configure legend location, if one was set. This has to be called between begin() and 610 | // end(), but since only the last call to it actually affects the outcome, I'm adding 611 | // it here instead of as a freestanding function. If this is too restrictive (for 612 | // example, if you want to set the location based on code running _during_ the plotting 613 | // for some reason), file an issue and we'll move it. 614 | if let Some(legend_config) = &self.legend_configuration { 615 | // We introduce variables with typechecks here to safeguard against accidental 616 | // changes in order in the config tuple 617 | let location: PlotLocation = legend_config.0; 618 | let orientation: PlotOrientation = legend_config.1; 619 | let outside_plot: bool = legend_config.2; 620 | unsafe { 621 | sys::ImPlot_SetLegendLocation(location as i32, orientation as i32, outside_plot) 622 | } 623 | } 624 | 625 | Some(PlotToken { 626 | context: plot_ui.context, 627 | plot_title: self.title.clone(), 628 | }) 629 | } else { 630 | // In contrast with imgui windows, end() does not have to be 631 | // called if we don't render. This is more like an imgui popup modal. 632 | None 633 | } 634 | } 635 | 636 | /// Creates a window and runs a closure to construct the contents. This internally 637 | /// calls `begin` and `end`. 638 | /// 639 | /// Note: the closure is not called if ImPlot::BeginPlot() returned 640 | /// false - TODO(4bb4) figure out if this is if things are not rendered 641 | #[rustversion::attr(since(1.48), doc(alias = "BeginPlot"))] 642 | #[rustversion::attr(since(1.48), doc(alias = "EndPlot"))] 643 | pub fn build(self, plot_ui: &PlotUi, f: F) { 644 | if let Some(token) = self.begin(plot_ui) { 645 | f(); 646 | token.end() 647 | } 648 | } 649 | } 650 | 651 | /// Tracks a plot that must be ended by calling `.end()` 652 | pub struct PlotToken { 653 | context: *const Context, 654 | /// For better error messages 655 | plot_title: CString, 656 | } 657 | 658 | impl PlotToken { 659 | /// End a previously begin()'ed plot. 660 | #[rustversion::attr(since(1.48), doc(alias = "EndPlot"))] 661 | pub fn end(mut self) { 662 | self.context = std::ptr::null(); 663 | unsafe { sys::ImPlot_EndPlot() }; 664 | } 665 | } 666 | 667 | impl Drop for PlotToken { 668 | fn drop(&mut self) { 669 | if !self.context.is_null() && !std::thread::panicking() { 670 | panic!( 671 | "Warning: A PlotToken for plot \"{:?}\" was not called end() on", 672 | self.plot_title 673 | ); 674 | } 675 | } 676 | } 677 | -------------------------------------------------------------------------------- /src/plot_elements.rs: -------------------------------------------------------------------------------- 1 | //! # Plot elements module 2 | //! 3 | //! This module defines the various structs that can be used for drawing different things such 4 | //! as lines, bars, scatter plots and text in a plot. For the module to create plots themselves, 5 | //! see `plot`. 6 | use crate::sys; 7 | use std::ffi::CString; 8 | use std::os::raw::c_char; 9 | 10 | pub use crate::sys::ImPlotPoint; 11 | 12 | // --- Actual plotting functionality ------------------------------------------------------------- 13 | /// Struct to provide functionality for plotting a line in a plot. 14 | pub struct PlotLine { 15 | /// Label to show in the legend for this line 16 | label: CString, 17 | } 18 | 19 | impl PlotLine { 20 | /// Create a new line to be plotted. Does not draw anything yet. 21 | /// 22 | /// # Panics 23 | /// Will panic if the label string contains internal null bytes. 24 | pub fn new(label: &str) -> Self { 25 | Self { 26 | label: CString::new(label) 27 | .unwrap_or_else(|_| panic!("Label string has internal null bytes: {}", label)), 28 | } 29 | } 30 | 31 | /// Plot a line. Use this in closures passed to [`Plot::build()`](struct.Plot.html#method.build) 32 | pub fn plot(&self, x: &[f64], y: &[f64]) { 33 | // If there is no data to plot, we stop here 34 | if x.len().min(y.len()) == 0 { 35 | return; 36 | } 37 | unsafe { 38 | sys::ImPlot_PlotLinedoublePtrdoublePtr( 39 | self.label.as_ptr() as *const c_char, 40 | x.as_ptr(), 41 | y.as_ptr(), 42 | x.len().min(y.len()) as i32, // "as" casts saturate as of Rust 1.45. This is safe here. 43 | 0, // No offset 44 | std::mem::size_of::() as i32, // Stride, set to one f64 for the standard use case 45 | ); 46 | } 47 | } 48 | } 49 | 50 | /// Struct to provide functionality for plotting a line in a plot with stairs style. 51 | pub struct PlotStairs { 52 | /// Label to show in the legend for this line 53 | label: CString, 54 | } 55 | 56 | impl PlotStairs { 57 | /// Create a new line to be plotted. Does not draw anything yet. 58 | /// 59 | /// # Panics 60 | /// Will panic if the label string contains internal null bytes. 61 | pub fn new(label: &str) -> Self { 62 | Self { 63 | label: CString::new(label) 64 | .unwrap_or_else(|_| panic!("Label string has internal null bytes: {}", label)), 65 | } 66 | } 67 | 68 | /// Plot a stairs style line. Use this in closures passed to 69 | /// [`Plot::build()`](struct.Plot.html#method.build) 70 | pub fn plot(&self, x: &[f64], y: &[f64]) { 71 | // If there is no data to plot, we stop here 72 | if x.len().min(y.len()) == 0 { 73 | return; 74 | } 75 | unsafe { 76 | sys::ImPlot_PlotStairsdoublePtrdoublePtr( 77 | self.label.as_ptr() as *const c_char, 78 | x.as_ptr(), 79 | y.as_ptr(), 80 | x.len().min(y.len()) as i32, // "as" casts saturate as of Rust 1.45. This is safe here. 81 | 0, // No offset 82 | std::mem::size_of::() as i32, // Stride, set to one f64 for the standard use case 83 | ); 84 | } 85 | } 86 | } 87 | 88 | /// Struct to provide functionality for creating a scatter plot 89 | pub struct PlotScatter { 90 | /// Label to show in the legend for this scatter plot 91 | /// 92 | /// # Panics 93 | /// Will panic if the label string contains internal null bytes. 94 | label: CString, 95 | } 96 | 97 | impl PlotScatter { 98 | /// Create a new scatter plot to be shown. Does not draw anything yet. 99 | pub fn new(label: &str) -> Self { 100 | Self { 101 | label: CString::new(label) 102 | .unwrap_or_else(|_| panic!("Label string has internal null bytes: {}", label)), 103 | } 104 | } 105 | 106 | /// Draw a previously-created scatter plot. Use this in closures passed to 107 | /// [`Plot::build()`](struct.Plot.html#method.build) 108 | pub fn plot(&self, x: &[f64], y: &[f64]) { 109 | // If there is no data to plot, we stop here 110 | if x.len().min(y.len()) == 0 { 111 | return; 112 | } 113 | unsafe { 114 | sys::ImPlot_PlotScatterdoublePtrdoublePtr( 115 | self.label.as_ptr() as *const c_char, 116 | x.as_ptr(), 117 | y.as_ptr(), 118 | x.len().min(y.len()) as i32, // "as" casts saturate as of Rust 1.45. This is safe here. 119 | 0, // No offset 120 | std::mem::size_of::() as i32, // Stride, set to one f64 for the standard use case 121 | ); 122 | } 123 | } 124 | } 125 | 126 | /// Struct to provide bar plotting functionality. 127 | pub struct PlotBars { 128 | /// Label to show in the legend for this line 129 | label: CString, 130 | 131 | /// Width of the bars, in plot coordinate terms 132 | bar_width: f64, 133 | 134 | /// Horizontal bar mode 135 | horizontal_bars: bool, 136 | } 137 | 138 | impl PlotBars { 139 | /// Create a new bar plot to be shown. Defaults to drawing vertical bars. 140 | /// Does not draw anything yet. 141 | /// 142 | /// # Panics 143 | /// Will panic if the label string contains internal null bytes. 144 | pub fn new(label: &str) -> Self { 145 | Self { 146 | label: CString::new(label) 147 | .unwrap_or_else(|_| panic!("Label string has internal null bytes: {}", label)), 148 | bar_width: 0.67, // Default value taken from C++ implot 149 | horizontal_bars: false, 150 | } 151 | } 152 | 153 | /// Set the width of the bars 154 | pub fn with_bar_width(mut self, bar_width: f64) -> Self { 155 | self.bar_width = bar_width; 156 | self 157 | } 158 | 159 | /// Set the bars to be horizontal (default is vertical) 160 | pub fn with_horizontal_bars(mut self) -> Self { 161 | self.horizontal_bars = true; 162 | self 163 | } 164 | 165 | /// Draw a previously-created bar plot. Use this in closures passed to 166 | /// [`Plot::build()`](struct.Plot.html#method.build). The `axis_positions` 167 | /// specify where on the corresponding axis (X for vertical mode, Y for horizontal mode) the 168 | /// bar is drawn, and the `bar_values` specify what values the bars have. 169 | pub fn plot(&self, axis_positions: &[f64], bar_values: &[f64]) { 170 | let number_of_points = axis_positions.len().min(bar_values.len()); 171 | // If there is no data to plot, we stop here 172 | if number_of_points == 0 { 173 | return; 174 | } 175 | unsafe { 176 | // C++ implot has separate functions for the two variants, but the interfaces 177 | // are the same, so they are unified here. The x and y values have different 178 | // meanings though, hence the swapping around before they are passed to the 179 | // plotting function. 180 | let (plot_function, x, y); 181 | if self.horizontal_bars { 182 | plot_function = sys::ImPlot_PlotBarsHdoublePtrdoublePtr 183 | as unsafe extern "C" fn( 184 | *const c_char, 185 | *const f64, 186 | *const f64, 187 | i32, 188 | f64, 189 | i32, 190 | i32, 191 | ); 192 | x = bar_values; 193 | y = axis_positions; 194 | } else { 195 | plot_function = sys::ImPlot_PlotBarsdoublePtrdoublePtr 196 | as unsafe extern "C" fn( 197 | *const c_char, 198 | *const f64, 199 | *const f64, 200 | i32, 201 | f64, 202 | i32, 203 | i32, 204 | ); 205 | x = axis_positions; 206 | y = bar_values; 207 | }; 208 | 209 | plot_function( 210 | self.label.as_ptr() as *const c_char, 211 | x.as_ptr(), 212 | y.as_ptr(), 213 | number_of_points as i32, // "as" casts saturate as of Rust 1.45. This is safe here. 214 | self.bar_width, 215 | 0, // No offset 216 | std::mem::size_of::() as i32, // Stride, set to one f64 for the standard use case 217 | ); 218 | } 219 | } 220 | } 221 | 222 | /// Struct to provide functionality for adding text within a plot 223 | pub struct PlotText { 224 | /// Label to show in plot 225 | label: CString, 226 | 227 | /// X component of the pixel offset to be used. Will be used independently of the actual plot 228 | /// scaling. Defaults to 0. 229 | pixel_offset_x: f32, 230 | 231 | /// Y component of the pixel offset to be used. Will be used independently of the actual plot 232 | /// scaling. Defaults to 0. 233 | pixel_offset_y: f32, 234 | } 235 | 236 | impl PlotText { 237 | /// Create a new text label to be shown. Does not draw anything yet. 238 | /// 239 | /// # Panics 240 | /// Will panic if the label string contains internal null bytes. 241 | pub fn new(label: &str) -> Self { 242 | Self { 243 | label: CString::new(label) 244 | .unwrap_or_else(|_| panic!("Label string has internal null bytes: {}", label)), 245 | pixel_offset_x: 0.0, 246 | pixel_offset_y: 0.0, 247 | } 248 | } 249 | 250 | /// Add a pixel offset to the text to be plotted. This offset will be independent of the 251 | /// scaling of the plot itself. 252 | pub fn with_pixel_offset(mut self, offset_x: f32, offset_y: f32) -> Self { 253 | self.pixel_offset_x = offset_x; 254 | self.pixel_offset_y = offset_y; 255 | self 256 | } 257 | 258 | /// Draw the text label in the plot at the given position, optionally vertically. Use this in 259 | /// closures passed to [`Plot::build()`](struct.Plot.html#method.build) 260 | pub fn plot(&self, x: f64, y: f64, vertical: bool) { 261 | // If there is nothing to show, don't do anything 262 | if self.label.as_bytes().is_empty() { 263 | return; 264 | } 265 | 266 | unsafe { 267 | sys::ImPlot_PlotText( 268 | self.label.as_ptr() as *const c_char, 269 | x, 270 | y, 271 | vertical, 272 | sys::ImVec2 { 273 | x: self.pixel_offset_x, 274 | y: self.pixel_offset_y, 275 | }, 276 | ); 277 | } 278 | } 279 | } 280 | 281 | /// Struct to provide functionality for creating headmaps. 282 | pub struct PlotHeatmap { 283 | /// Label to show in plot 284 | label: CString, 285 | 286 | /// Scale range of the values shown. If this is set to `None`, the scale 287 | /// is computed based on the values given to the `plot` function. If there 288 | /// is a value, the tuple is interpreted as `(minimum, maximum)`. 289 | scale_range: Option<(f64, f64)>, 290 | 291 | /// Label C style format string, this is shown when a a value point is hovered. 292 | /// None means don't show a label. The label is stored directly as an ImString because 293 | /// that is what's needed for the plot call anyway. Conversion is done in the setter. 294 | label_format: Option, 295 | 296 | /// Lower left point for the bounding rectangle. This is called `bounds_min` in the C++ code. 297 | drawarea_lower_left: ImPlotPoint, 298 | 299 | /// Upper right point for the bounding rectangle. This is called `bounds_max` in the C++ code. 300 | drawarea_upper_right: ImPlotPoint, 301 | } 302 | 303 | impl PlotHeatmap { 304 | /// Create a new heatmap to be shown. Uses the same defaults as the C++ version (see code for 305 | /// what those are), aside from the `scale_min` and `scale_max` values, which default to 306 | /// `None`, which is interpreted as "automatically make the scale fit the data". Does not draw 307 | /// anything yet. 308 | pub fn new(label: &str) -> Self { 309 | Self { 310 | label: CString::new(label) 311 | .unwrap_or_else(|_| panic!("Label string has internal null bytes: {}", label)), 312 | scale_range: None, 313 | label_format: Some(CString::new("%.1f").unwrap()), 314 | drawarea_lower_left: ImPlotPoint { x: 0.0, y: 0.0 }, 315 | drawarea_upper_right: ImPlotPoint { x: 1.0, y: 1.0 }, 316 | } 317 | } 318 | 319 | /// Specify the scale for the shown colors by minimum and maximum value. 320 | pub fn with_scale(mut self, scale_min: f64, scale_max: f64) -> Self { 321 | self.scale_range = Some((scale_min, scale_max)); 322 | self 323 | } 324 | 325 | /// Specify the label format for hovered data points. `None` means no label is shown. 326 | /// 327 | /// # Panics 328 | /// Will panic if the label format string contains internal null bytes. 329 | /// 330 | /// # Safety 331 | /// This function directly sets the format string of a C formatting function (`sprintf`). As 332 | /// such, one has to check oneself that the formatted numbers do not yield strings exceeding 333 | /// the length of the buffer used in the C++ code (32 bytes right now, this might change in the 334 | /// future, make sure to check in the vendored-in C++ code to be sure). While the string is 335 | /// not used until later and hence the function here is strictly speaking safe, the effect 336 | /// of this function can lead to unsoundness later, hence it is marked as unsafe. 337 | pub unsafe fn with_label_format(mut self, label_format: Option<&str>) -> Self { 338 | self.label_format = label_format.map(|x| { 339 | CString::new(x) 340 | .unwrap_or_else(|_| panic!("Format label string has internal null bytes: {}", x)) 341 | }); 342 | self 343 | } 344 | 345 | /// Specify the drawing area as the lower left and upper right point 346 | pub fn with_drawing_area(mut self, lower_left: ImPlotPoint, upper_right: ImPlotPoint) -> Self { 347 | self.drawarea_lower_left = lower_left; 348 | self.drawarea_upper_right = upper_right; 349 | self 350 | } 351 | 352 | /// Plot the heatmap, with the given values (assumed to be in row-major order), 353 | /// number of rows and number of columns. 354 | pub fn plot(&self, values: &[f64], number_of_rows: u32, number_of_cols: u32) { 355 | // If no range was given, determine that range 356 | let scale_range = self.scale_range.unwrap_or_else(|| { 357 | let mut min_seen = values[0]; 358 | let mut max_seen = values[0]; 359 | values.iter().for_each(|value| { 360 | min_seen = min_seen.min(*value); 361 | max_seen = max_seen.max(*value); 362 | }); 363 | (min_seen, max_seen) 364 | }); 365 | 366 | unsafe { 367 | sys::ImPlot_PlotHeatmapdoublePtr( 368 | self.label.as_ptr() as *const c_char, 369 | values.as_ptr(), 370 | number_of_rows as i32, // Not sure why C++ code uses a signed value here 371 | number_of_cols as i32, // Not sure why C++ code uses a signed value here 372 | scale_range.0, 373 | scale_range.1, 374 | // "no label" is taken as null pointer in the C++ code, but we're using 375 | // option types in the Rust bindings because they are more idiomatic. 376 | if self.label_format.is_some() { 377 | self.label_format.as_ref().unwrap().as_ptr() as *const c_char 378 | } else { 379 | std::ptr::null() 380 | }, 381 | self.drawarea_lower_left, 382 | self.drawarea_upper_right, 383 | ); 384 | } 385 | } 386 | } 387 | 388 | /// Struct to provide stem plotting functionality. 389 | pub struct PlotStems { 390 | /// Label to show in the legend for this line 391 | label: CString, 392 | 393 | /// Reference value for the y value, which the stems are "with respect to" 394 | reference_y: f64, 395 | } 396 | 397 | impl PlotStems { 398 | /// Create a new stem plot to be shown. Does not draw anything by itself, call 399 | /// [`PlotStems::plot`] on the struct for that. 400 | pub fn new(label: &str) -> Self { 401 | Self { 402 | label: CString::new(label) 403 | .unwrap_or_else(|_| panic!("Label string has internal null bytes: {}", label)), 404 | reference_y: 0.0, // Default value taken from C++ implot 405 | } 406 | } 407 | 408 | /// Set the reference y value for the stems 409 | pub fn with_reference_y(mut self, reference_y: f64) -> Self { 410 | self.reference_y = reference_y; 411 | self 412 | } 413 | 414 | /// Draw a previously-created stem plot. Use this in closures passed to 415 | /// [`Plot::build()`](struct.Plot.html#method.build). The `axis_positions` specify where on the 416 | /// X axis the stems are drawn, and the `stem_values` specify what values the stems have. 417 | pub fn plot(&self, axis_positions: &[f64], stem_values: &[f64]) { 418 | let number_of_points = axis_positions.len().min(stem_values.len()); 419 | // If there is no data to plot, we stop here 420 | if number_of_points == 0 { 421 | return; 422 | } 423 | unsafe { 424 | sys::ImPlot_PlotStemsdoublePtrdoublePtr( 425 | self.label.as_ptr() as *const c_char, 426 | axis_positions.as_ptr(), 427 | stem_values.as_ptr(), 428 | number_of_points as i32, // "as" casts saturate as of Rust 1.45. This is safe here. 429 | self.reference_y, 430 | 0, // No offset 431 | std::mem::size_of::() as i32, // Stride, set to one f64 for the standard use case 432 | ); 433 | } 434 | } 435 | } 436 | --------------------------------------------------------------------------------