Update to imgui-rs 0.11.0.

Remove a lot of code 'temporarily' while we do some restructuring.
This commit is contained in:
silvana 2023-09-22 13:09:38 +02:00
parent cdd3888446
commit e6a6f67b4d
13 changed files with 13520 additions and 4963 deletions

275
Cargo.lock generated Normal file
View file

@ -0,0 +1,275 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "cc"
version = "1.0.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
dependencies = [
"libc",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chlorine"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75476fe966a8af7c0ceae2a3e514afa87d4451741fcdfab8bfaa07ad301842ec"
[[package]]
name = "imgui"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "122d677d0efcd64ca15f12907beaf46b26bbd2cdc855ee5b227f29cf50f75bb5"
dependencies = [
"bitflags",
"cfg-if",
"imgui-sys",
"mint",
"parking_lot 0.12.1",
]
[[package]]
name = "imgui-sys"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d785272a57cb8058a53a1e6f376f48e2ec4f40fbc6a9bb197dabf7b6b59c03bf"
dependencies = [
"cc",
"cfg-if",
"chlorine",
"mint",
]
[[package]]
name = "implot"
version = "0.11.0"
dependencies = [
"bitflags",
"imgui",
"implot-sys",
"parking_lot 0.11.2",
"rustversion",
]
[[package]]
name = "implot-sys"
version = "0.11.0"
dependencies = [
"cc",
"imgui-sys",
"libc",
]
[[package]]
name = "instant"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
dependencies = [
"cfg-if",
]
[[package]]
name = "libc"
version = "0.2.148"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b"
[[package]]
name = "lock_api"
version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16"
dependencies = [
"autocfg",
"scopeguard",
]
[[package]]
name = "mint"
version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e53debba6bda7a793e5f99b8dacf19e626084f525f7829104ba9898f367d85ff"
[[package]]
name = "parking_lot"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
dependencies = [
"instant",
"lock_api",
"parking_lot_core 0.8.6",
]
[[package]]
name = "parking_lot"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
dependencies = [
"lock_api",
"parking_lot_core 0.9.8",
]
[[package]]
name = "parking_lot_core"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc"
dependencies = [
"cfg-if",
"instant",
"libc",
"redox_syscall 0.2.16",
"smallvec",
"winapi",
]
[[package]]
name = "parking_lot_core"
version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447"
dependencies = [
"cfg-if",
"libc",
"redox_syscall 0.3.5",
"smallvec",
"windows-targets",
]
[[package]]
name = "redox_syscall"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
dependencies = [
"bitflags",
]
[[package]]
name = "redox_syscall"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
dependencies = [
"bitflags",
]
[[package]]
name = "rustversion"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4"
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "smallvec"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-targets"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"

View file

@ -1,6 +1,6 @@
[package]
name = "implot"
version = "0.6.0"
version = "0.11.0"
edition = "2018"
authors = ["Sandro Merkli", "implot-rs contributors"]
description = "Rust bindings to https://github.com/epezent/implot"
@ -11,8 +11,8 @@ categories = ["gui", "api-bindings"]
readme = "README.md"
[dependencies]
implot-sys = { version = "0.6.0", path = "implot-sys" }
imgui = { version = "0.8.0" }
implot-sys = { version = "0.11.0", path = "implot-sys" }
imgui = { version = "0.11.0", features = ["docking"] }
bitflags = "1.0"
parking_lot = "0.11"
rustversion = "1.0.4"

380
implot-sys-bindgen/Cargo.lock generated Normal file
View file

@ -0,0 +1,380 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "aho-corasick"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea5d730647d4fadd988536d06fecce94b7b4f2a7efdae548f1cf4b63205518ab"
dependencies = [
"memchr",
]
[[package]]
name = "ansi_term"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
dependencies = [
"winapi",
]
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi",
]
[[package]]
name = "bindgen"
version = "0.57.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd4865004a46a0aafb2a0a5eb19d3c9fc46ee5f063a6cfc605c69ac9ecf5263d"
dependencies = [
"bitflags",
"cexpr",
"clang-sys",
"clap",
"env_logger",
"lazy_static",
"lazycell",
"log",
"peeking_take_while",
"proc-macro2",
"quote",
"regex",
"rustc-hash",
"shlex",
"which",
]
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "cc"
version = "1.0.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
dependencies = [
"libc",
]
[[package]]
name = "cexpr"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4aedb84272dbe89af497cf81375129abda4fc0a9e7c5d317498c15cc30c0d27"
dependencies = [
"nom",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chlorine"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75476fe966a8af7c0ceae2a3e514afa87d4451741fcdfab8bfaa07ad301842ec"
[[package]]
name = "clang-sys"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f"
dependencies = [
"glob",
"libc",
"libloading",
]
[[package]]
name = "clap"
version = "2.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
dependencies = [
"ansi_term",
"atty",
"bitflags",
"strsim",
"textwrap",
"unicode-width",
"vec_map",
]
[[package]]
name = "env_logger"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3"
dependencies = [
"atty",
"humantime",
"log",
"regex",
"termcolor",
]
[[package]]
name = "glob"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]]
name = "humantime"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "imgui-sys"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d785272a57cb8058a53a1e6f376f48e2ec4f40fbc6a9bb197dabf7b6b59c03bf"
dependencies = [
"cc",
"cfg-if",
"chlorine",
"mint",
]
[[package]]
name = "implot-sys-bindgen"
version = "0.3.0"
dependencies = [
"bindgen",
"imgui-sys",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "lazycell"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]]
name = "libc"
version = "0.2.148"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b"
[[package]]
name = "libloading"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
dependencies = [
"cfg-if",
"winapi",
]
[[package]]
name = "log"
version = "0.4.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
[[package]]
name = "memchr"
version = "2.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c"
[[package]]
name = "mint"
version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e53debba6bda7a793e5f99b8dacf19e626084f525f7829104ba9898f367d85ff"
[[package]]
name = "nom"
version = "5.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08959a387a676302eebf4ddbcbc611da04285579f76f88ee0506c63b1a61dd4b"
dependencies = [
"memchr",
"version_check",
]
[[package]]
name = "peeking_take_while"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
[[package]]
name = "proc-macro2"
version = "1.0.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
dependencies = [
"proc-macro2",
]
[[package]]
name = "regex"
version = "1.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "697061221ea1b4a94a624f67d0ae2bfe4e22b8a17b6a192afb11046542cc8c47"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2f401f4955220693b56f8ec66ee9c78abffd8d1c4f23dc41a23839eb88f0795"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da"
[[package]]
name = "rustc-hash"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "shlex"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2"
[[package]]
name = "strsim"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
[[package]]
name = "termcolor"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64"
dependencies = [
"winapi-util",
]
[[package]]
name = "textwrap"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
dependencies = [
"unicode-width",
]
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "unicode-width"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
[[package]]
name = "vec_map"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "which"
version = "3.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d011071ae14a2f6671d0b74080ae0cd8ebf3a6f8c9589a2cd45f23126fe29724"
dependencies = [
"libc",
]
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
dependencies = [
"winapi",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

View file

@ -6,4 +6,4 @@ edition = "2018"
[dependencies]
bindgen = "0.57"
imgui-sys = { version = "0.8.0" }
imgui-sys = { version = "0.11.0", features = ["docking"] }

View file

@ -17,6 +17,8 @@ fn main() {
env::var_os("DEP_IMGUI_THIRD_PARTY").expect("DEP_IMGUI_THIRD_PARTY not defined"),
);
println!("{}", cimgui_include_path.display());
let bindings = Builder::default()
.header(
cimgui_include_path
@ -34,21 +36,40 @@ fn main() {
)
.parse_callbacks(Box::new(CargoCallbacks))
.clang_arg("-DCIMGUI_DEFINE_ENUMS_AND_STRUCTS=1")
.clang_arg(format!("-I{}", cimgui_include_path.display()))
// Reuse the imgui types that implot requires from imgui_sys so we don't define
// our own new types.
.raw_line("pub use imgui_sys::{ImVec2, ImVec4, ImGuiCond, ImTextureID};")
.raw_line("pub use imgui_sys::{ImGuiContext, ImGuiKeyModFlags, ImDrawList};")
.raw_line("pub use imgui_sys::{ImVec2, ImVector_ImU32, ImVec4, ImGuiCond, ImTextureID};")
.raw_line("pub use imgui_sys::{ImGuiTextBuffer, ImGuiStorage, ImWchar, ImGuiTextRange};")
.raw_line("pub use imgui_sys::{ImGuiStoragePair, ImDrawCmd, *};")
.raw_line("pub use imgui_sys::{ImGuiContext, ImGuiKey, ImDrawList};")
.raw_line("pub use imgui_sys::{ImGuiMouseButton, ImGuiDragDropFlags};")
.raw_line("use libc::time_t;")
.whitelist_recursively(false)
.whitelist_function("ImPlot.*")
.whitelist_type("ImPlot.*")
// We do want to create bindings for the scalar typedefs
.whitelist_type("Im[U|S][0-9]{1,2}")
.whitelist_type("ImAxis")
.whitelist_var("ImAxis_")
.whitelist_type("ImPool_.+")
.whitelist_type("ImVector_.+")
.whitelist_type("tm")
// Remove some functions that would take a variable-argument list
.blacklist_function("ImPlot_AnnotateVVec4")
.blacklist_function("ImPlot_AnnotateVStr")
.blacklist_function("ImPlot_AnnotateClampedVVec4")
.blacklist_function("ImPlot_AnnotateClampedVStr")
.blacklist_type("ImVector_ImU32")
.blacklist_function("ImPlot_MkGmtTime")
.blacklist_function("ImPlot_GetGmtTime")
.blacklist_function("ImPlot_MkLocTime")
.blacklist_function("ImPlot_GetLocTime")
.blacklist_function("ImPlot_AnnotationV")
.blacklist_function("ImPlot_TagXV")
.blacklist_function("ImPlot_TagYV")
.blacklist_function("ImPlotAnnotationCollection_AppendV")
.blacklist_function("ImPlotTagCollection_AppendV")
.generate()
.expect("Unable to generate bindings");

View file

@ -1,6 +1,6 @@
[package]
name = "implot-sys"
version = "0.6.0"
version = "0.11.0"
edition = "2018"
authors = ["Sandro Merkli", "implot-rs contributors"]
description = "Raw FFI bindings to implot"
@ -12,7 +12,8 @@ build = "build.rs"
links = "implot"
[dependencies]
imgui-sys = "0.8.0"
imgui-sys = { version = "0.11.0", features = ["docking"] }
libc = "0.2.148"
[build-dependencies]
cc = "1.0"

11093
implot-sys/src/bindings.rs generated

File diff suppressed because it is too large Load diff

@ -1 +1 @@
Subproject commit 374317a84121a01868aa5274dbcf1c5a5df96e8c
Subproject commit 82d498a5bf0d945b1db21c80ba3ce69350930022

View file

@ -16,16 +16,18 @@
//! the C++ name - some doc aliases are defined to increase the chances of that working. If this
//! does not yield any results, you can also try cloning the source and doing a full-text search to
//! see if the feature is used somewhere internally the code.
use implot_sys as sys;
pub use implot_sys as sys;
// TODO(4bb4) facade-wrap these?
pub use self::{context::*, plot::*, plot_elements::*};
use std::os::raw::c_char;
pub use sys::{ImPlotLimits, ImPlotPoint, ImPlotRange, ImVec2, ImVec4};
pub use sys::{ImAxis, ImPlotPoint, ImPlotRange, ImPlotRect, ImVec2, ImVec4};
mod context;
pub mod lines;
mod plot;
mod plot_elements;
pub mod rect;
// The bindings for some reason don't contain this - it has to match the IMPLOT_AUTO from
// the original C++ header for things to work properly.
@ -41,23 +43,6 @@ const NUMBER_OF_Y_AXES: usize = 3;
// Implementation note: This enum is converted straight to an usize index in a few places
// so we can store data about individual axes in arrays, so this pretty much should stay
// just a mapping of words to numbers.
#[rustversion::attr(since(1.48), doc(alias = "ImPlotYAxis"))]
#[derive(Clone)]
#[repr(u32)]
pub enum YAxisChoice {
First = sys::ImPlotYAxis__ImPlotYAxis_1,
Second = sys::ImPlotYAxis__ImPlotYAxis_2,
Third = sys::ImPlotYAxis__ImPlotYAxis_3,
}
/// Turn an Option<YAxisChoice> into an i32. Picks IMPLOT_AUTO for None.
#[rustversion::attr(since(1.48), doc(alias = "IMPLOT_AUTO"))]
fn y_axis_choice_option_to_i32(y_axis_choice: Option<YAxisChoice>) -> i32 {
match y_axis_choice {
Some(choice) => choice as i32,
None => IMPLOT_AUTO,
}
}
/// A temporary reference for building plots. This does not really do anything on its own at
/// this point, but it is used to enforce that a context is created and active for other features,
@ -130,27 +115,12 @@ pub enum PlotColorElement {
/// Color of text appearing inside of plots (defaults to ImGuiCol_Text)
InlayText = sys::ImPlotCol__ImPlotCol_InlayText,
/// X-axis label and tick lables color (defaults to ImGuiCol_Text)
XAxis = sys::ImPlotCol__ImPlotCol_XAxis,
AxisBg = sys::ImPlotCol__ImPlotCol_AxisBg,
/// X-axis grid color (defaults to 25% ImPlotCol_XAxis)
XAxisGrid = sys::ImPlotCol__ImPlotCol_XAxisGrid,
/// Y-axis label and tick labels color (defaults to ImGuiCol_Text)
YAxis = sys::ImPlotCol__ImPlotCol_YAxis,
/// Y-axis grid color (defaults to 25% ImPlotCol_YAxis)
YAxisGrid = sys::ImPlotCol__ImPlotCol_YAxisGrid,
/// 2nd y-axis label and tick labels color (defaults to ImGuiCol_Text)
YAxis2 = sys::ImPlotCol__ImPlotCol_YAxis2,
/// 2nd y-axis grid/label color (defaults to 25% ImPlotCol_YAxis2)
YAxisGrid2 = sys::ImPlotCol__ImPlotCol_YAxisGrid2,
/// 3rd y-axis label and tick labels color (defaults to ImGuiCol_Text)
YAxis3 = sys::ImPlotCol__ImPlotCol_YAxis3,
/// 3rd y-axis grid/label color (defaults to 25% ImPlotCol_YAxis3)
YAxisGrid3 = sys::ImPlotCol__ImPlotCol_YAxisGrid3,
/// Box-selection color (defaults to yellow)
AxisBgHovered = sys::ImPlotCol__ImPlotCol_AxisBgHovered,
AxisBgActive = sys::ImPlotCol__ImPlotCol_AxisBgActive,
Selection = sys::ImPlotCol__ImPlotCol_Selection,
/// crosshairs color (defaults to ImPlotCol_PlotBorder)
Crosshairs = sys::ImPlotCol__ImPlotCol_Crosshairs,
/// Box-query color (defaults to green)
Query = sys::ImPlotCol__ImPlotCol_Query,
}
/// Colormap choice. Documentation copied from implot.h for convenience.
@ -158,8 +128,6 @@ pub enum PlotColorElement {
#[repr(u32)]
#[derive(Copy, Clone, Debug)]
pub enum Colormap {
/// ImPlot default colormap (n=10). Called "Standard" here because Default is reserved.
Standard = sys::ImPlotColormap__ImPlotColormap_Default,
/// a.k.a. seaborn deep (n=10)
Deep = sys::ImPlotColormap__ImPlotColormap_Deep,
/// a.k.a. matplotlib "Set1" (n=9)
@ -269,35 +237,6 @@ pub enum PlotLocation {
SouthEast = sys::ImPlotLocation__ImPlotLocation_SouthEast,
}
#[rustversion::attr(since(1.48), doc(alias = "ImPlotOrientation"))]
/// Used to orient items on a plot (e.g. legends, labels, etc.)
#[repr(u32)]
#[derive(Copy, Clone, Debug)]
pub enum PlotOrientation {
Horizontal = sys::ImPlotOrientation__ImPlotOrientation_Horizontal,
Vertical = sys::ImPlotOrientation__ImPlotOrientation_Vertical,
}
/// Switch to one of the built-in preset colormaps. If samples is greater than 1, the map will be
/// linearly resampled.
#[rustversion::attr(since(1.48), doc(alias = "SetColormap"))]
pub fn set_colormap_from_preset(preset: Colormap, samples: u32) {
unsafe {
// "as" casts saturate as of Rust 1.45. This is safe here, and at least the enum
// values are not expected to go outside the range of an i32 anyway, so there is no
// risk of changed values.
sys::ImPlot_SetColormapPlotColormap(preset as i32, samples as i32);
}
}
/// Set a custom colormap in the form of a vector of colors.
#[rustversion::attr(since(1.48), doc(alias = "SetColormap"))]
pub fn set_colormap_from_vec(colors: Vec<ImVec4>) {
unsafe {
sys::ImPlot_SetColormapVec4Ptr(colors.as_ptr(), colors.len() as i32);
}
}
// --- Push/pop utils -------------------------------------------------------------------------
// Currently not in a struct yet. imgui-rs has some smarts about dealing with stacks, in particular
// leak detection, which I'd like to replicate here at some point.
@ -319,7 +258,7 @@ pub fn push_style_color(
alpha: f32,
) -> StyleColorToken {
unsafe {
sys::ImPlot_PushStyleColorVec4(
sys::ImPlot_PushStyleColor_Vec4(
*element as sys::ImPlotCol,
sys::ImVec4 {
x: red,
@ -362,7 +301,7 @@ impl StyleColorToken {
#[rustversion::attr(since(1.48), doc(alias = "PushStyleVar"))]
pub fn push_style_var_f32(element: &StyleVar, value: f32) -> StyleVarToken {
unsafe {
sys::ImPlot_PushStyleVarFloat(*element as sys::ImPlotStyleVar, value);
sys::ImPlot_PushStyleVar_Float(*element as sys::ImPlotStyleVar, value);
}
StyleVarToken { was_popped: false }
}
@ -378,7 +317,7 @@ pub fn push_style_var_f32(element: &StyleVar, value: f32) -> StyleVarToken {
#[rustversion::attr(since(1.48), doc(alias = "PushStyleVar"))]
pub fn push_style_var_i32(element: &StyleVar, value: i32) -> StyleVarToken {
unsafe {
sys::ImPlot_PushStyleVarInt(*element as sys::ImPlotStyleVar, value);
sys::ImPlot_PushStyleVar_Int(*element as sys::ImPlotStyleVar, value);
}
StyleVarToken { was_popped: false }
}
@ -387,7 +326,7 @@ pub fn push_style_var_i32(element: &StyleVar, value: i32) -> StyleVarToken {
/// the variable from the stack again.
pub fn push_style_var_imvec2(element: &StyleVar, value: ImVec2) -> StyleVarToken {
unsafe {
sys::ImPlot_PushStyleVarVec2(*element as sys::ImPlotStyleVar, value);
sys::ImPlot_PushStyleVar_Vec2(*element as sys::ImPlotStyleVar, value);
}
StyleVarToken { was_popped: false }
}
@ -419,21 +358,14 @@ pub fn is_plot_hovered() -> bool {
unsafe { sys::ImPlot_IsPlotHovered() }
}
/// Returns true if the current or most recent plot is queried
#[rustversion::attr(since(1.48), doc(alias = "IsPlotQueried"))]
pub fn is_plot_queried() -> bool {
unsafe { sys::ImPlot_IsPlotQueried() }
}
/// Returns the mouse position in x,y coordinates of the current or most recent plot,
/// for the specified choice of Y axis. If `None` is the Y axis choice, that means the
/// most recently selected Y axis is chosen.
#[rustversion::attr(since(1.48), doc(alias = "GetPlotMousePos"))]
pub fn get_plot_mouse_position(y_axis_choice: Option<YAxisChoice>) -> ImPlotPoint {
let y_axis_choice_i32 = y_axis_choice_option_to_i32(y_axis_choice);
pub fn get_plot_mouse_position(x: ImAxis, y: ImAxis) -> ImPlotPoint {
let mut point = ImPlotPoint { x: 0.0, y: 0.0 }; // doesn't seem to have default()
unsafe {
sys::ImPlot_GetPlotMousePos(&mut point as *mut ImPlotPoint, y_axis_choice_i32);
sys::ImPlot_GetPlotMousePos(&mut point as *mut ImPlotPoint, x, y);
}
point
}
@ -441,18 +373,10 @@ pub fn get_plot_mouse_position(y_axis_choice: Option<YAxisChoice>) -> ImPlotPoin
/// Convert pixels, given as an `ImVec2`, to a position in the current plot's coordinate system.
/// Uses the specified Y axis, if any, otherwise whatever was previously chosen.
#[rustversion::attr(since(1.48), doc(alias = "PixelsToPlot"))]
pub fn pixels_to_plot_vec2(
pixel_position: &ImVec2,
y_axis_choice: Option<YAxisChoice>,
) -> ImPlotPoint {
let y_axis_choice_i32 = y_axis_choice_option_to_i32(y_axis_choice);
pub fn pixels_to_plot_vec2(pixel_position: &ImVec2, x: ImAxis, y: ImAxis) -> ImPlotPoint {
let mut point = ImPlotPoint { x: 0.0, y: 0.0 }; // doesn't seem to have default()
unsafe {
sys::ImPlot_PixelsToPlotVec2(
&mut point as *mut ImPlotPoint,
*pixel_position,
y_axis_choice_i32,
);
sys::ImPlot_PixelsToPlot_Vec2(&mut point as *mut ImPlotPoint, *pixel_position, x, y);
}
point
}
@ -463,16 +387,17 @@ pub fn pixels_to_plot_vec2(
pub fn pixels_to_plot_f32(
pixel_position_x: f32,
pixel_position_y: f32,
y_axis_choice: Option<YAxisChoice>,
x: ImAxis,
y: ImAxis,
) -> ImPlotPoint {
let y_axis_choice_i32 = y_axis_choice_option_to_i32(y_axis_choice);
let mut point = ImPlotPoint { x: 0.0, y: 0.0 }; // doesn't seem to have default()
unsafe {
sys::ImPlot_PixelsToPlotFloat(
sys::ImPlot_PixelsToPlot_Float(
&mut point as *mut ImPlotPoint,
pixel_position_x,
pixel_position_y,
y_axis_choice_i32,
x,
y,
);
}
point
@ -482,17 +407,14 @@ pub fn pixels_to_plot_f32(
/// axis, if any, otherwise whatever was previously chosen.
///
#[rustversion::attr(since(1.48), doc(alias = "PlotToPixels"))]
pub fn plot_to_pixels_vec2(
plot_position: &ImPlotPoint,
y_axis_choice: Option<YAxisChoice>,
) -> ImVec2 {
let y_axis_choice_i32 = y_axis_choice_option_to_i32(y_axis_choice);
pub fn plot_to_pixels_vec2(plot_position: &ImPlotPoint, x_axis: ImAxis, y_axis: ImAxis) -> ImVec2 {
let mut pixel_position = ImVec2 { x: 0.0, y: 0.0 }; // doesn't seem to have default()
unsafe {
sys::ImPlot_PlotToPixelsPlotPoInt(
sys::ImPlot_PlotToPixels_PlotPoInt(
&mut pixel_position as *mut ImVec2,
*plot_position,
y_axis_choice_i32,
x_axis,
y_axis,
);
}
pixel_position
@ -504,16 +426,17 @@ pub fn plot_to_pixels_vec2(
pub fn plot_to_pixels_f32(
plot_position_x: f64,
plot_position_y: f64,
y_axis_choice: Option<YAxisChoice>,
x_axis: ImAxis,
y_axis: ImAxis,
) -> ImVec2 {
let y_axis_choice_i32 = y_axis_choice_option_to_i32(y_axis_choice);
let mut pixel_position = ImVec2 { x: 0.0, y: 0.0 }; // doesn't seem to have default()
unsafe {
sys::ImPlot_PlotToPixelsdouble(
sys::ImPlot_PlotToPixels_double(
&mut pixel_position as *mut ImVec2,
plot_position_x,
plot_position_y,
y_axis_choice_i32,
x_axis,
y_axis,
);
}
pixel_position
@ -522,57 +445,18 @@ pub fn plot_to_pixels_f32(
/// Returns the current or most recent plot axis range for the specified choice of Y axis. If
/// `None` is the Y axis choice, that means the most recently selected Y axis is chosen.
#[rustversion::attr(since(1.48), doc(alias = "GetPlotLimits"))]
pub fn get_plot_limits(y_axis_choice: Option<YAxisChoice>) -> ImPlotLimits {
let y_axis_choice_i32 = y_axis_choice_option_to_i32(y_axis_choice);
// ImPlotLimits doesn't seem to have default()
let mut limits = ImPlotLimits {
pub fn get_plot_limits(x: ImAxis, y: ImAxis) -> ImPlotRect {
// ImPlotRect doesn't seem to have default()
let mut limits = ImPlotRect {
X: ImPlotRange { Min: 0.0, Max: 0.0 },
Y: ImPlotRange { Min: 0.0, Max: 0.0 },
};
unsafe {
sys::ImPlot_GetPlotLimits(&mut limits as *mut ImPlotLimits, y_axis_choice_i32);
sys::ImPlot_GetPlotLimits(&mut limits as *mut ImPlotRect, x, y);
}
limits
}
/// Returns the query limits of the current or most recent plot, for the specified choice of Y
/// axis. If `None` is the Y axis choice, that means the most recently selected Y axis is chosen.
#[rustversion::attr(since(1.48), doc(alias = "GetPlotQuery"))]
pub fn get_plot_query(y_axis_choice: Option<YAxisChoice>) -> ImPlotLimits {
let y_axis_choice_i32 = y_axis_choice_option_to_i32(y_axis_choice);
// ImPlotLimits doesn't seem to have default()
let mut limits = ImPlotLimits {
X: ImPlotRange { Min: 0.0, Max: 0.0 },
Y: ImPlotRange { Min: 0.0, Max: 0.0 },
};
unsafe {
sys::ImPlot_GetPlotQuery(&mut limits as *mut ImPlotLimits, y_axis_choice_i32);
}
limits
}
/// Set the Y axis to be used for any upcoming plot elements
#[rustversion::attr(since(1.48), doc(alias = "SetPlotYAxis"))]
pub fn set_plot_y_axis(y_axis_choice: YAxisChoice) {
unsafe {
sys::ImPlot_SetPlotYAxis(y_axis_choice as i32);
}
}
/// Returns true if the XAxis plot area in the current plot is hovered.
#[rustversion::attr(since(1.48), doc(alias = "IsPlotXAxisHovered"))]
pub fn is_plot_x_axis_hovered() -> bool {
unsafe { sys::ImPlot_IsPlotXAxisHovered() }
}
/// Returns true if the Y axis area of the given Y axis choice in the current plot is hovered. If
/// `None` is the Y axis choice, that means the most recently selected Y axis is chosen.
#[rustversion::attr(since(1.48), doc(alias = "IsPlotYAxisHovered"))]
pub fn is_plot_y_axis_hovered(y_axis_choice: Option<YAxisChoice>) -> bool {
let y_axis_choice_i32 = y_axis_choice_option_to_i32(y_axis_choice);
unsafe { sys::ImPlot_IsPlotYAxisHovered(y_axis_choice_i32) }
}
/// Returns true if the given item in the legend of the current plot is hovered.
pub fn is_legend_entry_hovered(legend_entry: &str) -> bool {
unsafe { sys::ImPlot_IsLegendEntryHovered(legend_entry.as_ptr() as *const c_char) }

36
src/lines.rs Normal file
View file

@ -0,0 +1,36 @@
use crate::sys;
use std::ffi::CString;
use std::os::raw::c_char;
pub use crate::sys::ImPlotPoint;
pub struct PlotLine {
label: CString,
}
impl PlotLine {
pub fn new(label: &str) -> Self {
Self {
label: CString::new(label)
.unwrap_or_else(|_| panic!("label string has internal null bytes: {}", label)),
}
}
pub fn plot(&self, x: &[f64], y: &[f64]) {
if x.len().min(y.len()) == 0 {
return;
}
unsafe {
sys::ImPlot_PlotLine_doublePtrdoublePtr(
self.label.as_ptr() as *const c_char,
x.as_ptr(),
y.as_ptr(),
x.len().min(y.len()) as i32,
0,
0,
std::mem::size_of::<f64>() as i32,
);
}
}
}

View file

@ -1,625 +1,141 @@
//! # Plot module
//!
//! This module defines the `Plot` struct, which is used to create a 2D plot that will
//! contain all other objects that can be created using this library.
use crate::{Context, PlotLocation, PlotOrientation, PlotUi, YAxisChoice, NUMBER_OF_Y_AXES};
use bitflags::bitflags;
pub use imgui::Condition;
use implot_sys as sys;
use std::ffi::CString;
use std::os::raw::c_char;
use std::{cell::RefCell, rc::Rc};
pub use sys::{ImPlotLimits, ImPlotPoint, ImPlotRange, ImVec2, ImVec4};
use bitflags::bitflags;
use implot_sys as sys;
use sys::{ImAxis, ImVec2, *};
use crate::{Context, PlotUi};
const DEFAULT_PLOT_SIZE_X: f32 = 400.0;
const DEFAULT_PLOT_SIZE_Y: f32 = 400.0;
#[rustversion::attr(since(1.48), doc(alias = "ImPlotFlags"))]
pub enum Axis {
X1 = 0,
X2 = 1,
X3 = 2,
Y1 = 3,
Y2 = 4,
Y3 = 5,
}
bitflags! {
/// Flags for customizing plot behavior and interaction. Documentation copied from implot.h for
/// convenience. ImPlot itself also has a "CanvasOnly" flag, which can be emulated here with
/// the combination of `NO_LEGEND`, `NO_MENUS`, `NO_BOX_SELECT` and `NO_MOUSE_POSITION`.
#[repr(transparent)]
pub struct PlotFlags: u32 {
/// "Default" according to original docs
const NONE = sys::ImPlotFlags__ImPlotFlags_None;
/// Plot items will not be highlighted when their legend entry is hovered
const NO_LEGEND = sys::ImPlotFlags__ImPlotFlags_NoLegend;
/// The user will not be able to open context menus with double-right click
const NO_MENUS = sys::ImPlotFlags__ImPlotFlags_NoMenus;
/// The user will not be able to box-select with right-mouse
const NO_BOX_SELECT = sys::ImPlotFlags__ImPlotFlags_NoBoxSelect;
/// The mouse position, in plot coordinates, will not be displayed
const NO_MOUSE_POSITION = sys::ImPlotFlags__ImPlotFlags_NoMousePos;
/// Plot items will not be highlighted when their legend entry is hovered
const NO_HIGHLIGHT = sys::ImPlotFlags__ImPlotFlags_NoHighlight;
/// A child window region will not be used to capture mouse scroll (can boost performance
/// for single ImGui window applications)
const NO_CHILD = sys::ImPlotFlags__ImPlotFlags_NoChild;
/// Use an aspect ratio of 1:1 for the plot
const AXIS_EQUAL = sys::ImPlotFlags__ImPlotFlags_Equal;
/// Enable a 2nd y axis
const Y_AXIS_2 = sys::ImPlotFlags__ImPlotFlags_YAxis2;
/// Enable a 3nd y axis
const Y_AXIS_3 = sys::ImPlotFlags__ImPlotFlags_YAxis3;
/// The user will be able to draw query rects with middle-mouse
const QUERY = sys::ImPlotFlags__ImPlotFlags_Query;
/// The default mouse cursor will be replaced with a crosshair when hovered
const CROSSHAIRS = sys::ImPlotFlags__ImPlotFlags_Crosshairs;
/// Plot data outside the plot area will be culled from rendering
const ANTIALIASED = sys::ImPlotFlags__ImPlotFlags_AntiAliased;
const NONE = ImPlotFlags__ImPlotFlags_None;
const NOTITLE = ImPlotFlags__ImPlotFlags_NoTitle;
const NOLEGEND = ImPlotFlags__ImPlotFlags_NoLegend;
const NOMOUSETEXT = ImPlotFlags__ImPlotFlags_NoMouseText;
const NOINPUTS = ImPlotFlags__ImPlotFlags_NoInputs;
const NOMENUS = ImPlotFlags__ImPlotFlags_NoMenus;
const NOBOXSELECT = ImPlotFlags__ImPlotFlags_NoBoxSelect;
const NOCHILD = ImPlotFlags__ImPlotFlags_NoChild;
const NOFRAME = ImPlotFlags__ImPlotFlags_NoFrame;
const EQUAL = ImPlotFlags__ImPlotFlags_Equal;
const CROSSHAIRS = ImPlotFlags__ImPlotFlags_Crosshairs;
const CANVASONLY = ImPlotFlags__ImPlotFlags_CanvasOnly;
}
}
#[rustversion::attr(since(1.48), doc(alias = "ImPlotAxisFlags"))]
bitflags! {
/// Axis flags. Documentation copied from implot.h for convenience. ImPlot itself also
/// has `Lock`, which combines `LOCK_MIN` and `LOCK_MAX`, and `NoDecorations`, which combines
/// `NO_GRID_LINES`, `NO_TICK_MARKS` and `NO_TICK_LABELS`.
#[repr(transparent)]
pub struct AxisFlags: u32 {
/// "Default" according to original docs
const NONE = sys::ImPlotAxisFlags__ImPlotAxisFlags_None;
/// Grid lines will not be displayed
const NO_GRID_LINES = sys::ImPlotAxisFlags__ImPlotAxisFlags_NoGridLines;
/// Tick marks will not be displayed
const NO_TICK_MARKS = sys::ImPlotAxisFlags__ImPlotAxisFlags_NoTickMarks;
/// Text labels will not be displayed
const NO_TICK_LABELS = sys::ImPlotAxisFlags__ImPlotAxisFlags_NoTickLabels;
/// A logartithmic (base 10) axis scale will be used (mutually exclusive with AxisFlags::TIME)
const LOG_SCALE = sys::ImPlotAxisFlags__ImPlotAxisFlags_LogScale;
/// Axis will display date/time formatted labels (mutually exclusive with AxisFlags::LOG_SCALE)
const TIME = sys::ImPlotAxisFlags__ImPlotAxisFlags_Time;
/// The axis will be inverted
const INVERT = sys::ImPlotAxisFlags__ImPlotAxisFlags_Invert;
/// The axis minimum value will be locked when panning/zooming
const LOCK_MIN = sys::ImPlotAxisFlags__ImPlotAxisFlags_LockMin;
/// The axis maximum value will be locked when panning/zooming
const LOCK_MAX = sys::ImPlotAxisFlags__ImPlotAxisFlags_LockMax;
pub struct PlotAxisFlags: u32 {
const NONE = ImPlotAxisFlags__ImPlotAxisFlags_None;
const NO_LABEL = ImPlotAxisFlags__ImPlotAxisFlags_NoLabel;
const NO_GRID_LINES = ImPlotAxisFlags__ImPlotAxisFlags_NoGridLines;
const NO_TICK_MARKS = ImPlotAxisFlags__ImPlotAxisFlags_NoTickMarks;
const NO_TICK_LABELS = ImPlotAxisFlags__ImPlotAxisFlags_NoTickLabels;
const NO_INITIAL_FIT = ImPlotAxisFlags__ImPlotAxisFlags_NoInitialFit;
const NO_MENUS = ImPlotAxisFlags__ImPlotAxisFlags_NoMenus;
const NO_SIDESWITCH = ImPlotAxisFlags__ImPlotAxisFlags_NoSideSwitch;
const NO_HIGHLIGHT = ImPlotAxisFlags__ImPlotAxisFlags_NoHighlight;
const OPPOSITE = ImPlotAxisFlags__ImPlotAxisFlags_Opposite;
const FOREGROUND = ImPlotAxisFlags__ImPlotAxisFlags_Foreground;
const INVERT = ImPlotAxisFlags__ImPlotAxisFlags_Invert;
const AUTO_FIT = ImPlotAxisFlags__ImPlotAxisFlags_AutoFit;
const RANGE_FIT = ImPlotAxisFlags__ImPlotAxisFlags_RangeFit;
const PAN_STRETCH = ImPlotAxisFlags__ImPlotAxisFlags_PanStretch;
const LOCK_MIN = ImPlotAxisFlags__ImPlotAxisFlags_LockMin;
const LOCK_MAX = ImPlotAxisFlags__ImPlotAxisFlags_LockMax;
const LOCK = ImPlotAxisFlags__ImPlotAxisFlags_Lock;
const NO_DECORATIONS = ImPlotAxisFlags__ImPlotAxisFlags_NoDecorations;
const AUX_DEFAULT = ImPlotAxisFlags__ImPlotAxisFlags_AuxDefault;
}
}
/// Internally-used struct for storing axis limits
#[derive(Clone)]
enum AxisLimitSpecification {
/// Direct limits, specified as values
Single(ImPlotRange, Condition),
/// Limits that are linked to limits of other plots (via clones of the same Rc)
Linked(Rc<RefCell<ImPlotRange>>),
}
/// Struct to represent an ImPlot. This is the main construct used to contain all kinds of plots in ImPlot.
///
/// `Plot` is to be used (within an imgui window) with the following pattern:
/// ```no_run
/// # use implot;
/// let plotting_context = implot::Context::create();
/// let plot_ui = plotting_context.get_plot_ui();
/// implot::Plot::new("my title")
/// .size([300.0, 200.0]) // other things such as .x_label("some_label") can be added too
/// .build(&plot_ui, || {
/// // Do things such as plotting lines
/// });
///
/// ```
/// (If you are coming from the C++ implementation or the C bindings: build() calls both
/// begin() and end() internally)
pub struct Plot {
/// Title of the plot, shown on top. Stored as CString because that's what we'll use
/// afterwards, and this ensures the CString itself will stay alive long enough for the plot.
title: CString,
/// Size of the plot in [x, y] direction, in the same units imgui uses.
size: [f32; 2],
/// Label of the x axis, shown on the bottom. Stored as CString because that's what we'll use
/// afterwards, and this ensures the CString itself will stay alive long enough for the plot.
x_label: CString,
/// Label of the y axis, shown on the left. Stored as CString because that's what we'll use
/// afterwards, and this ensures the CString itself will stay alive long enough for the plot.
y_label: CString,
/// X axis limits, if present
x_limits: Option<AxisLimitSpecification>,
/// Y axis limits, if present
y_limits: [Option<AxisLimitSpecification>; NUMBER_OF_Y_AXES],
/// Positions for custom X axis ticks, if any
x_tick_positions: Option<Vec<f64>>,
/// Labels for custom X axis ticks, if any. I'd prefer to store these together
/// with the positions in one vector of an algebraic data type, but this would mean extra
/// copies when it comes time to draw the plot because the C++ library expects separate lists.
/// The data is stored as CStrings because those are null-terminated, and since we have to
/// convert to null-terminated data anyway, we may as well do that directly instead of cloning
/// Strings and converting them afterwards.
x_tick_labels: Option<Vec<CString>>,
/// Whether to also show the default X ticks when showing custom ticks or not
show_x_default_ticks: bool,
/// Positions for custom Y axis ticks, if any
y_tick_positions: [Option<Vec<f64>>; NUMBER_OF_Y_AXES],
/// Labels for custom Y axis ticks, if any. I'd prefer to store these together
/// with the positions in one vector of an algebraic data type, but this would mean extra
/// copies when it comes time to draw the plot because the C++ library expects separate lists.
/// The data is stored as CStrings because those are null-terminated, and since we have to
/// convert to null-terminated data anyway, we may as well do that directly instead of cloning
/// Strings and converting them afterwards.
y_tick_labels: [Option<Vec<CString>>; NUMBER_OF_Y_AXES],
/// Whether to also show the default Y ticks when showing custom ticks or not
show_y_default_ticks: [bool; NUMBER_OF_Y_AXES],
/// Configuration for the legend, if specified. The tuple contains location, orientation
/// and a boolean (true means legend is outside of plot, false means within). If nothing
/// is set, implot's defaults are used. Note also that if these are set, then implot's
/// interactive legend configuration does not work because it is overridden by the settings
/// here.
legend_configuration: Option<(PlotLocation, PlotOrientation, bool)>,
/// Flags relating to the plot TODO(4bb4) make those into bitflags
plot_flags: sys::ImPlotFlags,
/// Flags relating to the X axis of the plot TODO(4bb4) make those into bitflags
x_flags: sys::ImPlotAxisFlags,
/// Flags relating to the each of the Y axes of the plot TODO(4bb4) make those into bitflags
y_flags: [sys::ImPlotAxisFlags; NUMBER_OF_Y_AXES],
flags: ImPlotFlags,
x_flags: ImPlotAxisFlags,
y_flags: ImPlotAxisFlags,
}
impl Plot {
/// Create a new plot with some defaults set. Does not draw anything yet.
/// Note that this uses antialiasing by default, unlike the C++ API. If you are seeing
/// artifacts or weird rendering, try disabling it.
///
/// # Panics
/// Will panic if the title string contains internal null bytes.
pub fn new(title: &str) -> Self {
// Needed for initialization, see https://github.com/rust-lang/rust/issues/49147
const POS_NONE: Option<Vec<f64>> = None;
const TICK_NONE: Option<Vec<CString>> = None;
// TODO(4bb4) question these defaults, maybe remove some of them
Self {
title: CString::new(title)
.unwrap_or_else(|_| panic!("String contains internal null bytes: {}", title)),
.unwrap_or_else(|_| panic!("string contains internal null bytes: {}", title)),
size: [DEFAULT_PLOT_SIZE_X, DEFAULT_PLOT_SIZE_Y],
x_label: CString::new("").unwrap(),
y_label: CString::new("").unwrap(),
x_limits: None,
y_limits: Default::default(),
x_tick_positions: None,
x_tick_labels: None,
show_x_default_ticks: false,
y_tick_positions: [POS_NONE; NUMBER_OF_Y_AXES],
y_tick_labels: [TICK_NONE; NUMBER_OF_Y_AXES],
show_y_default_ticks: [false; NUMBER_OF_Y_AXES],
legend_configuration: None,
plot_flags: PlotFlags::ANTIALIASED.bits() as sys::ImPlotFlags,
x_flags: AxisFlags::NONE.bits() as sys::ImPlotAxisFlags,
y_flags: [AxisFlags::NONE.bits() as sys::ImPlotAxisFlags; NUMBER_OF_Y_AXES],
flags: PlotFlags::NONE.bits() as ImPlotFlags,
x_flags: PlotAxisFlags::NONE.bits() as ImPlotAxisFlags,
y_flags: PlotAxisFlags::NONE.bits() as ImPlotAxisFlags,
}
}
/// Sets the plot size, given as [size_x, size_y]. Units are the same as
/// what imgui uses. TODO(4bb4) ... which is? I'm not sure it's pixels
#[inline]
pub fn size(mut self, size: [f32; 2]) -> Self {
self.size = size;
self
}
/// Set the x label of the plot
///
/// # Panics
/// Will panic if the label string contains internal null bytes.
#[inline]
pub fn with_flags(mut self, flags: &PlotFlags) -> Self {
self.flags = flags.bits() as ImPlotFlags;
self
}
pub fn with_x_flags(mut self, flags: &PlotAxisFlags) -> Self {
self.x_flags = flags.bits() as ImPlotAxisFlags;
self
}
pub fn with_y_flags(mut self, flags: &PlotAxisFlags) -> Self {
self.y_flags = flags.bits() as ImPlotAxisFlags;
self
}
pub fn x_label(mut self, label: &str) -> Self {
self.x_label = CString::new(label)
.unwrap_or_else(|_| panic!("String contains internal null bytes: {}", label));
.unwrap_or_else(|_| panic!("string contains internal null bytes: {}", label));
self
}
/// Set the y label of the plot
///
/// # Panics
/// Will panic if the label string contains internal null bytes.
#[inline]
pub fn y_label(mut self, label: &str) -> Self {
self.y_label = CString::new(label)
.unwrap_or_else(|_| panic!("String contains internal null bytes: {}", label));
.unwrap_or_else(|_| panic!("string contains internal null bytes: {}", label));
self
}
/// Set the x limits of the plot.
///
/// Note: This conflicts with `linked_x_limits`, whichever is called last on plot construction
/// takes effect.
#[inline]
pub fn x_limits<L: Into<ImPlotRange>>(mut self, limits: L, condition: Condition) -> Self {
self.x_limits = Some(AxisLimitSpecification::Single(limits.into(), condition));
self
}
/// Set linked x limits for this plot. Pass clones of the same `Rc` into other plots
/// to link their limits with the same values.
///
/// Note: This conflicts with `x_limits`, whichever is called last on plot construction takes
/// effect.
#[inline]
pub fn linked_x_limits(mut self, limits: Rc<RefCell<ImPlotRange>>) -> Self {
self.x_limits = Some(AxisLimitSpecification::Linked(limits));
self
}
/// Set the Y limits of the plot for the given Y axis. Call multiple times with different
/// `y_axis_choice` values to set for multiple axes, or use the convenience methods such as
/// [`Plot::y1_limits`].
///
/// Note: This conflicts with `linked_y_limits`, whichever is called last on plot construction
/// takes effect for a given axis.
#[inline]
pub fn y_limits<L: Into<ImPlotRange>>(
mut self,
limits: L,
y_axis_choice: YAxisChoice,
condition: Condition,
) -> Self {
let axis_index = y_axis_choice as usize;
self.y_limits[axis_index] = Some(AxisLimitSpecification::Single(limits.into(), condition));
self
}
/// Convenience function to directly set the Y limits for the first Y axis. To programmatically
/// (or on demand) decide which axis to set limits for, use [`Plot::y_limits`]
#[inline]
pub fn y1_limits<L: Into<ImPlotRange>>(self, limits: L, condition: Condition) -> Self {
self.y_limits(limits, YAxisChoice::First, condition)
}
/// Convenience function to directly set the Y limits for the second Y axis. To
/// programmatically (or on demand) decide which axis to set limits for, use [`Plot::y_limits`]
#[inline]
pub fn y2_limits<L: Into<ImPlotRange>>(self, limits: L, condition: Condition) -> Self {
self.y_limits(limits, YAxisChoice::Second, condition)
}
/// Convenience function to directly set the Y limits for the third Y axis. To programmatically
/// (or on demand) decide which axis to set limits for, use [`Plot::y_limits`]
#[inline]
pub fn y3_limits<L: Into<ImPlotRange>>(self, limits: L, condition: Condition) -> Self {
self.y_limits(limits, YAxisChoice::Third, condition)
}
/// Set linked Y limits of the plot for the given Y axis. Pass clones of the same `Rc` into
/// other plots to link their limits with the same values. Call multiple times with different
/// `y_axis_choice` values to set for multiple axes, or use the convenience methods such as
/// [`Plot::y1_limits`].
///
/// Note: This conflicts with `y_limits`, whichever is called last on plot construction takes
/// effect for a given axis.
#[inline]
pub fn linked_y_limits(
mut self,
limits: Rc<RefCell<ImPlotRange>>,
y_axis_choice: YAxisChoice,
) -> Self {
let axis_index = y_axis_choice as usize;
self.y_limits[axis_index] = Some(AxisLimitSpecification::Linked(limits));
self
}
/// Convenience function to directly set linked Y limits for the first Y axis. To
/// programmatically (or on demand) decide which axis to set limits for, use
/// [`Plot::linked_y_limits`].
#[inline]
pub fn linked_y1_limits(self, limits: Rc<RefCell<ImPlotRange>>) -> Self {
self.linked_y_limits(limits, YAxisChoice::First)
}
/// Convenience function to directly set linked Y limits for the second Y axis. To
/// programmatically (or on demand) decide which axis to set limits for, use
/// [`Plot::linked_y_limits`].
#[inline]
pub fn linked_y2_limits(self, limits: Rc<RefCell<ImPlotRange>>) -> Self {
self.linked_y_limits(limits, YAxisChoice::Second)
}
/// Convenience function to directly set linked Y limits for the third Y axis. To
/// programmatically (or on demand) decide which axis to set limits for, use
/// [`Plot::linked_y_limits`].
#[inline]
pub fn linked_y3_limits(self, limits: Rc<RefCell<ImPlotRange>>) -> Self {
self.linked_y_limits(limits, YAxisChoice::Third)
}
/// Set X ticks without labels for the plot. The vector contains one label each in
/// the form of a tuple `(label_position, label_string)`. The `show_default` setting
/// determines whether the default ticks are also shown.
#[inline]
pub fn x_ticks(mut self, ticks: &[f64], show_default: bool) -> Self {
self.x_tick_positions = Some(ticks.into());
self.show_x_default_ticks = show_default;
self
}
/// Set X ticks without labels for the plot. The vector contains one label each in
/// the form of a tuple `(label_position, label_string)`. The `show_default` setting
/// determines whether the default ticks are also shown.
#[inline]
pub fn y_ticks(
mut self,
y_axis_choice: YAxisChoice,
ticks: &[f64],
show_default: bool,
) -> Self {
let axis_index = y_axis_choice as usize;
self.y_tick_positions[axis_index] = Some(ticks.into());
self.show_y_default_ticks[axis_index] = show_default;
self
}
/// Set X ticks with labels for the plot. The vector contains one position and label
/// each in the form of a tuple `(label_position, label_string)`. The `show_default`
/// setting determines whether the default ticks are also shown.
///
/// # Panics
/// Will panic if any of the tick label strings contain internal null bytes.
#[inline]
pub fn x_ticks_with_labels(
mut self,
tick_labels: &[(f64, String)],
show_default: bool,
) -> Self {
self.x_tick_positions = Some(tick_labels.iter().map(|x| x.0).collect());
self.x_tick_labels = Some(
tick_labels
.iter()
.map(|x| {
CString::new(x.1.as_str())
.unwrap_or_else(|_| panic!("String contains internal null bytes: {}", x.1))
})
.collect(),
);
self.show_x_default_ticks = show_default;
self
}
/// Set Y ticks with labels for the plot. The vector contains one position and label
/// each in the form of a tuple `(label_position, label_string)`. The `show_default`
/// setting determines whether the default ticks are also shown.
///
/// # Panics
/// Will panic if any of the tick label strings contain internal null bytes.
#[inline]
pub fn y_ticks_with_labels(
mut self,
y_axis_choice: YAxisChoice,
tick_labels: &[(f64, String)],
show_default: bool,
) -> Self {
let axis_index = y_axis_choice as usize;
self.y_tick_positions[axis_index] = Some(tick_labels.iter().map(|x| x.0).collect());
self.y_tick_labels[axis_index] = Some(
tick_labels
.iter()
.map(|x| {
CString::new(x.1.as_str())
.unwrap_or_else(|_| panic!("String contains internal null bytes: {}", x.1))
})
.collect(),
);
self.show_y_default_ticks[axis_index] = show_default;
self
}
/// Set the plot flags, see the help for `PlotFlags` for what the available flags are
#[inline]
pub fn with_plot_flags(mut self, flags: &PlotFlags) -> Self {
self.plot_flags = flags.bits() as sys::ImPlotFlags;
self
}
/// Set the axis flags for the X axis in this plot
#[inline]
pub fn with_x_axis_flags(mut self, flags: &AxisFlags) -> Self {
self.x_flags = flags.bits() as sys::ImPlotAxisFlags;
self
}
/// Set the axis flags for the selected Y axis in this plot
#[inline]
pub fn with_y_axis_flags(mut self, y_axis_choice: YAxisChoice, flags: &AxisFlags) -> Self {
let axis_index = y_axis_choice as usize;
self.y_flags[axis_index] = flags.bits() as sys::ImPlotAxisFlags;
self
}
/// Set the legend location, orientation and whether it is to be drawn outside the plot
#[rustversion::attr(since(1.48), doc(alias = "SetLegendLocation"))]
#[inline]
pub fn with_legend_location(
mut self,
location: &PlotLocation,
orientation: &PlotOrientation,
outside: bool,
) -> Self {
self.legend_configuration = Some((*location, *orientation, outside));
self
}
/// Internal helper function to set axis limits in case they are specified.
fn maybe_set_axis_limits(&self) {
// Limit-setting can either happen via direct limits or through linked limits. The version
// of implot we link to here has different APIs for the two (separate per-axis calls for
// direct, and one call for everything together for linked), hence the code here is a bit
// clunky and takes the two approaches separately instead of a unified "match".
// --- Direct limit-setting ---
if let Some(AxisLimitSpecification::Single(limits, condition)) = &self.x_limits {
unsafe {
sys::ImPlot_SetNextPlotLimitsX(
limits.Min,
limits.Max,
*condition as sys::ImGuiCond,
);
}
}
self.y_limits
.iter()
.enumerate()
.for_each(|(k, limit_spec)| {
if let Some(AxisLimitSpecification::Single(limits, condition)) = limit_spec {
unsafe {
sys::ImPlot_SetNextPlotLimitsY(
limits.Min,
limits.Max,
*condition as sys::ImGuiCond,
k as i32,
);
}
}
});
// --- Linked limit-setting ---
let (xmin_pointer, xmax_pointer) =
if let Some(AxisLimitSpecification::Linked(value)) = &self.x_limits {
let mut borrowed = value.borrow_mut();
(
&mut (*borrowed).Min as *mut _,
&mut (*borrowed).Max as *mut _,
)
} else {
(std::ptr::null_mut(), std::ptr::null_mut())
};
let y_limit_pointers: Vec<(*mut f64, *mut f64)> = self
.y_limits
.iter()
.map(|limit_spec| {
if let Some(AxisLimitSpecification::Linked(value)) = limit_spec {
let mut borrowed = value.borrow_mut();
(
&mut (*borrowed).Min as *mut _,
&mut (*borrowed).Max as *mut _,
)
} else {
(std::ptr::null_mut(), std::ptr::null_mut())
}
})
.collect();
unsafe {
// Calling this unconditionally here as calling it with all NULL pointers should not
// affect anything. In terms of unsafety, the pointers should be OK as long as any plot
// struct that has an Rc to the same data is alive.
sys::ImPlot_LinkNextPlotLimits(
xmin_pointer,
xmax_pointer,
y_limit_pointers[0].0,
y_limit_pointers[0].1,
y_limit_pointers[1].0,
y_limit_pointers[1].1,
y_limit_pointers[2].0,
y_limit_pointers[2].1,
)
}
}
/// Internal helper function to set tick labels in case they are specified. This does the
/// preparation work that is the same for both the X and Y axis plots, then calls the
/// "set next plot ticks" wrapper functions for both X and Y.
fn maybe_set_tick_labels(&self) {
// Show x ticks if they are available
if self.x_tick_positions.is_some() && !self.x_tick_positions.as_ref().unwrap().is_empty() {
let mut pointer_vec; // The vector of pointers we create has to have a longer lifetime
let labels_pointer = if let Some(labels_value) = &self.x_tick_labels {
pointer_vec = labels_value
.iter()
.map(|x| x.as_ptr() as *const c_char)
.collect::<Vec<*const c_char>>();
pointer_vec.as_mut_ptr()
} else {
std::ptr::null_mut()
};
unsafe {
sys::ImPlot_SetNextPlotTicksXdoublePtr(
self.x_tick_positions.as_ref().unwrap().as_ptr(),
self.x_tick_positions.as_ref().unwrap().len() as i32,
labels_pointer,
self.show_x_default_ticks,
)
}
}
self.y_tick_positions
.iter()
.zip(self.y_tick_labels.iter())
.zip(self.show_y_default_ticks.iter())
.enumerate()
.for_each(|(k, ((positions, labels), show_defaults))| {
if positions.is_some() && !positions.as_ref().unwrap().is_empty() {
// The vector of pointers we create has to have a longer lifetime
let mut pointer_vec;
let labels_pointer = if let Some(labels_value) = &labels {
pointer_vec = labels_value
.iter()
.map(|x| x.as_ptr() as *const c_char)
.collect::<Vec<*const c_char>>();
pointer_vec.as_mut_ptr()
} else {
std::ptr::null_mut()
};
unsafe {
sys::ImPlot_SetNextPlotTicksYdoublePtr(
positions.as_ref().unwrap().as_ptr(),
positions.as_ref().unwrap().len() as i32,
labels_pointer,
*show_defaults,
k as i32,
)
}
}
});
}
/// Attempt to show the plot. If this returns a token, the plot will actually
/// be drawn. In this case, use the drawing functionality to draw things on the
/// plot, and then call `end()` on the token when done with the plot.
/// If none was returned, that means the plot is not rendered.
///
/// For a convenient implementation of all this, use [`build()`](struct.Plot.html#method.build)
/// instead.
#[rustversion::attr(since(1.48), doc(alias = "BeginPlot"))]
pub fn begin(&self, plot_ui: &PlotUi) -> Option<PlotToken> {
self.maybe_set_axis_limits();
self.maybe_set_tick_labels();
let should_render = unsafe {
let size_vec: ImVec2 = ImVec2 {
x: self.size[0],
y: self.size[1],
};
sys::ImPlot_BeginPlot(
self.title.as_ptr(),
self.x_label.as_ptr(),
self.y_label.as_ptr(),
size_vec,
self.plot_flags,
self.x_flags,
self.y_flags[0],
self.y_flags[1],
self.y_flags[2],
)
let should_render = sys::ImPlot_BeginPlot(self.title.as_ptr(), size_vec, self.flags);
should_render
};
if should_render {
// Configure legend location, if one was set. This has to be called between begin() and
// end(), but since only the last call to it actually affects the outcome, I'm adding
// it here instead of as a freestanding function. If this is too restrictive (for
// example, if you want to set the location based on code running _during_ the plotting
// for some reason), file an issue and we'll move it.
if let Some(legend_config) = &self.legend_configuration {
// We introduce variables with typechecks here to safeguard against accidental
// changes in order in the config tuple
let location: PlotLocation = legend_config.0;
let orientation: PlotOrientation = legend_config.1;
let outside_plot: bool = legend_config.2;
unsafe {
sys::ImPlot_SetLegendLocation(location as i32, orientation as i32, outside_plot)
}
sys::ImPlot_SetupAxis(Axis::X1 as i32, self.x_label.as_ptr(), self.x_flags);
sys::ImPlot_SetupAxis(Axis::Y1 as i32, self.y_label.as_ptr(), self.y_flags);
}
Some(PlotToken {
@ -627,19 +143,10 @@ impl Plot {
plot_title: self.title.clone(),
})
} else {
// In contrast with imgui windows, end() does not have to be
// called if we don't render. This is more like an imgui popup modal.
None
}
}
/// Creates a window and runs a closure to construct the contents. This internally
/// calls `begin` and `end`.
///
/// Note: the closure is not called if ImPlot::BeginPlot() returned
/// false - TODO(4bb4) figure out if this is if things are not rendered
#[rustversion::attr(since(1.48), doc(alias = "BeginPlot"))]
#[rustversion::attr(since(1.48), doc(alias = "EndPlot"))]
pub fn build<F: FnOnce()>(self, plot_ui: &PlotUi, f: F) {
if let Some(token) = self.begin(plot_ui) {
f();
@ -648,16 +155,12 @@ impl Plot {
}
}
/// Tracks a plot that must be ended by calling `.end()`
pub struct PlotToken {
context: *const Context,
/// For better error messages
plot_title: CString,
}
impl PlotToken {
/// End a previously begin()'ed plot.
#[rustversion::attr(since(1.48), doc(alias = "EndPlot"))]
pub fn end(mut self) {
self.context = std::ptr::null();
unsafe { sys::ImPlot_EndPlot() };
@ -668,7 +171,7 @@ impl Drop for PlotToken {
fn drop(&mut self) {
if !self.context.is_null() && !std::thread::panicking() {
panic!(
"Warning: A PlotToken for plot \"{:?}\" was not called end() on",
"warning a plottoken for plot \"{:?}\" was not called end() on.",
self.plot_title
);
}

View file

@ -1,435 +1 @@
//! # Plot elements module
//!
//! This module defines the various structs that can be used for drawing different things such
//! as lines, bars, scatter plots and text in a plot. For the module to create plots themselves,
//! see `plot`.
use crate::sys;
use std::ffi::CString;
use std::os::raw::c_char;
pub use crate::sys::ImPlotPoint;
// --- Actual plotting functionality -------------------------------------------------------------
/// Struct to provide functionality for plotting a line in a plot.
pub struct PlotLine {
/// Label to show in the legend for this line
label: CString,
}
impl PlotLine {
/// Create a new line to be plotted. Does not draw anything yet.
///
/// # Panics
/// Will panic if the label string contains internal null bytes.
pub fn new(label: &str) -> Self {
Self {
label: CString::new(label)
.unwrap_or_else(|_| panic!("Label string has internal null bytes: {}", label)),
}
}
/// Plot a line. Use this in closures passed to [`Plot::build()`](struct.Plot.html#method.build)
pub fn plot(&self, x: &[f64], y: &[f64]) {
// If there is no data to plot, we stop here
if x.len().min(y.len()) == 0 {
return;
}
unsafe {
sys::ImPlot_PlotLinedoublePtrdoublePtr(
self.label.as_ptr() as *const c_char,
x.as_ptr(),
y.as_ptr(),
x.len().min(y.len()) as i32, // "as" casts saturate as of Rust 1.45. This is safe here.
0, // No offset
std::mem::size_of::<f64>() as i32, // Stride, set to one f64 for the standard use case
);
}
}
}
/// Struct to provide functionality for plotting a line in a plot with stairs style.
pub struct PlotStairs {
/// Label to show in the legend for this line
label: CString,
}
impl PlotStairs {
/// Create a new line to be plotted. Does not draw anything yet.
///
/// # Panics
/// Will panic if the label string contains internal null bytes.
pub fn new(label: &str) -> Self {
Self {
label: CString::new(label)
.unwrap_or_else(|_| panic!("Label string has internal null bytes: {}", label)),
}
}
/// Plot a stairs style line. Use this in closures passed to
/// [`Plot::build()`](struct.Plot.html#method.build)
pub fn plot(&self, x: &[f64], y: &[f64]) {
// If there is no data to plot, we stop here
if x.len().min(y.len()) == 0 {
return;
}
unsafe {
sys::ImPlot_PlotStairsdoublePtrdoublePtr(
self.label.as_ptr() as *const c_char,
x.as_ptr(),
y.as_ptr(),
x.len().min(y.len()) as i32, // "as" casts saturate as of Rust 1.45. This is safe here.
0, // No offset
std::mem::size_of::<f64>() as i32, // Stride, set to one f64 for the standard use case
);
}
}
}
/// Struct to provide functionality for creating a scatter plot
pub struct PlotScatter {
/// Label to show in the legend for this scatter plot
///
/// # Panics
/// Will panic if the label string contains internal null bytes.
label: CString,
}
impl PlotScatter {
/// Create a new scatter plot to be shown. Does not draw anything yet.
pub fn new(label: &str) -> Self {
Self {
label: CString::new(label)
.unwrap_or_else(|_| panic!("Label string has internal null bytes: {}", label)),
}
}
/// Draw a previously-created scatter plot. Use this in closures passed to
/// [`Plot::build()`](struct.Plot.html#method.build)
pub fn plot(&self, x: &[f64], y: &[f64]) {
// If there is no data to plot, we stop here
if x.len().min(y.len()) == 0 {
return;
}
unsafe {
sys::ImPlot_PlotScatterdoublePtrdoublePtr(
self.label.as_ptr() as *const c_char,
x.as_ptr(),
y.as_ptr(),
x.len().min(y.len()) as i32, // "as" casts saturate as of Rust 1.45. This is safe here.
0, // No offset
std::mem::size_of::<f64>() as i32, // Stride, set to one f64 for the standard use case
);
}
}
}
/// Struct to provide bar plotting functionality.
pub struct PlotBars {
/// Label to show in the legend for this line
label: CString,
/// Width of the bars, in plot coordinate terms
bar_width: f64,
/// Horizontal bar mode
horizontal_bars: bool,
}
impl PlotBars {
/// Create a new bar plot to be shown. Defaults to drawing vertical bars.
/// Does not draw anything yet.
///
/// # Panics
/// Will panic if the label string contains internal null bytes.
pub fn new(label: &str) -> Self {
Self {
label: CString::new(label)
.unwrap_or_else(|_| panic!("Label string has internal null bytes: {}", label)),
bar_width: 0.67, // Default value taken from C++ implot
horizontal_bars: false,
}
}
/// Set the width of the bars
pub fn with_bar_width(mut self, bar_width: f64) -> Self {
self.bar_width = bar_width;
self
}
/// Set the bars to be horizontal (default is vertical)
pub fn with_horizontal_bars(mut self) -> Self {
self.horizontal_bars = true;
self
}
/// Draw a previously-created bar plot. Use this in closures passed to
/// [`Plot::build()`](struct.Plot.html#method.build). The `axis_positions`
/// specify where on the corresponding axis (X for vertical mode, Y for horizontal mode) the
/// bar is drawn, and the `bar_values` specify what values the bars have.
pub fn plot(&self, axis_positions: &[f64], bar_values: &[f64]) {
let number_of_points = axis_positions.len().min(bar_values.len());
// If there is no data to plot, we stop here
if number_of_points == 0 {
return;
}
unsafe {
// C++ implot has separate functions for the two variants, but the interfaces
// are the same, so they are unified here. The x and y values have different
// meanings though, hence the swapping around before they are passed to the
// plotting function.
let (plot_function, x, y);
if self.horizontal_bars {
plot_function = sys::ImPlot_PlotBarsHdoublePtrdoublePtr
as unsafe extern "C" fn(
*const c_char,
*const f64,
*const f64,
i32,
f64,
i32,
i32,
);
x = bar_values;
y = axis_positions;
} else {
plot_function = sys::ImPlot_PlotBarsdoublePtrdoublePtr
as unsafe extern "C" fn(
*const c_char,
*const f64,
*const f64,
i32,
f64,
i32,
i32,
);
x = axis_positions;
y = bar_values;
};
plot_function(
self.label.as_ptr() as *const c_char,
x.as_ptr(),
y.as_ptr(),
number_of_points as i32, // "as" casts saturate as of Rust 1.45. This is safe here.
self.bar_width,
0, // No offset
std::mem::size_of::<f64>() as i32, // Stride, set to one f64 for the standard use case
);
}
}
}
/// Struct to provide functionality for adding text within a plot
pub struct PlotText {
/// Label to show in plot
label: CString,
/// X component of the pixel offset to be used. Will be used independently of the actual plot
/// scaling. Defaults to 0.
pixel_offset_x: f32,
/// Y component of the pixel offset to be used. Will be used independently of the actual plot
/// scaling. Defaults to 0.
pixel_offset_y: f32,
}
impl PlotText {
/// Create a new text label to be shown. Does not draw anything yet.
///
/// # Panics
/// Will panic if the label string contains internal null bytes.
pub fn new(label: &str) -> Self {
Self {
label: CString::new(label)
.unwrap_or_else(|_| panic!("Label string has internal null bytes: {}", label)),
pixel_offset_x: 0.0,
pixel_offset_y: 0.0,
}
}
/// Add a pixel offset to the text to be plotted. This offset will be independent of the
/// scaling of the plot itself.
pub fn with_pixel_offset(mut self, offset_x: f32, offset_y: f32) -> Self {
self.pixel_offset_x = offset_x;
self.pixel_offset_y = offset_y;
self
}
/// Draw the text label in the plot at the given position, optionally vertically. Use this in
/// closures passed to [`Plot::build()`](struct.Plot.html#method.build)
pub fn plot(&self, x: f64, y: f64, vertical: bool) {
// If there is nothing to show, don't do anything
if self.label.as_bytes().is_empty() {
return;
}
unsafe {
sys::ImPlot_PlotText(
self.label.as_ptr() as *const c_char,
x,
y,
vertical,
sys::ImVec2 {
x: self.pixel_offset_x,
y: self.pixel_offset_y,
},
);
}
}
}
/// Struct to provide functionality for creating headmaps.
pub struct PlotHeatmap {
/// Label to show in plot
label: CString,
/// Scale range of the values shown. If this is set to `None`, the scale
/// is computed based on the values given to the `plot` function. If there
/// is a value, the tuple is interpreted as `(minimum, maximum)`.
scale_range: Option<(f64, f64)>,
/// Label C style format string, this is shown when a a value point is hovered.
/// None means don't show a label. The label is stored directly as an ImString because
/// that is what's needed for the plot call anyway. Conversion is done in the setter.
label_format: Option<CString>,
/// Lower left point for the bounding rectangle. This is called `bounds_min` in the C++ code.
drawarea_lower_left: ImPlotPoint,
/// Upper right point for the bounding rectangle. This is called `bounds_max` in the C++ code.
drawarea_upper_right: ImPlotPoint,
}
impl PlotHeatmap {
/// Create a new heatmap to be shown. Uses the same defaults as the C++ version (see code for
/// what those are), aside from the `scale_min` and `scale_max` values, which default to
/// `None`, which is interpreted as "automatically make the scale fit the data". Does not draw
/// anything yet.
pub fn new(label: &str) -> Self {
Self {
label: CString::new(label)
.unwrap_or_else(|_| panic!("Label string has internal null bytes: {}", label)),
scale_range: None,
label_format: Some(CString::new("%.1f").unwrap()),
drawarea_lower_left: ImPlotPoint { x: 0.0, y: 0.0 },
drawarea_upper_right: ImPlotPoint { x: 1.0, y: 1.0 },
}
}
/// Specify the scale for the shown colors by minimum and maximum value.
pub fn with_scale(mut self, scale_min: f64, scale_max: f64) -> Self {
self.scale_range = Some((scale_min, scale_max));
self
}
/// Specify the label format for hovered data points. `None` means no label is shown.
///
/// # Panics
/// Will panic if the label format string contains internal null bytes.
///
/// # Safety
/// This function directly sets the format string of a C formatting function (`sprintf`). As
/// such, one has to check oneself that the formatted numbers do not yield strings exceeding
/// the length of the buffer used in the C++ code (32 bytes right now, this might change in the
/// future, make sure to check in the vendored-in C++ code to be sure). While the string is
/// not used until later and hence the function here is strictly speaking safe, the effect
/// of this function can lead to unsoundness later, hence it is marked as unsafe.
pub unsafe fn with_label_format(mut self, label_format: Option<&str>) -> Self {
self.label_format = label_format.map(|x| {
CString::new(x)
.unwrap_or_else(|_| panic!("Format label string has internal null bytes: {}", x))
});
self
}
/// Specify the drawing area as the lower left and upper right point
pub fn with_drawing_area(mut self, lower_left: ImPlotPoint, upper_right: ImPlotPoint) -> Self {
self.drawarea_lower_left = lower_left;
self.drawarea_upper_right = upper_right;
self
}
/// Plot the heatmap, with the given values (assumed to be in row-major order),
/// number of rows and number of columns.
pub fn plot(&self, values: &[f64], number_of_rows: u32, number_of_cols: u32) {
// If no range was given, determine that range
let scale_range = self.scale_range.unwrap_or_else(|| {
let mut min_seen = values[0];
let mut max_seen = values[0];
values.iter().for_each(|value| {
min_seen = min_seen.min(*value);
max_seen = max_seen.max(*value);
});
(min_seen, max_seen)
});
unsafe {
sys::ImPlot_PlotHeatmapdoublePtr(
self.label.as_ptr() as *const c_char,
values.as_ptr(),
number_of_rows as i32, // Not sure why C++ code uses a signed value here
number_of_cols as i32, // Not sure why C++ code uses a signed value here
scale_range.0,
scale_range.1,
// "no label" is taken as null pointer in the C++ code, but we're using
// option types in the Rust bindings because they are more idiomatic.
if self.label_format.is_some() {
self.label_format.as_ref().unwrap().as_ptr() as *const c_char
} else {
std::ptr::null()
},
self.drawarea_lower_left,
self.drawarea_upper_right,
);
}
}
}
/// Struct to provide stem plotting functionality.
pub struct PlotStems {
/// Label to show in the legend for this line
label: CString,
/// Reference value for the y value, which the stems are "with respect to"
reference_y: f64,
}
impl PlotStems {
/// Create a new stem plot to be shown. Does not draw anything by itself, call
/// [`PlotStems::plot`] on the struct for that.
pub fn new(label: &str) -> Self {
Self {
label: CString::new(label)
.unwrap_or_else(|_| panic!("Label string has internal null bytes: {}", label)),
reference_y: 0.0, // Default value taken from C++ implot
}
}
/// Set the reference y value for the stems
pub fn with_reference_y(mut self, reference_y: f64) -> Self {
self.reference_y = reference_y;
self
}
/// Draw a previously-created stem plot. Use this in closures passed to
/// [`Plot::build()`](struct.Plot.html#method.build). The `axis_positions` specify where on the
/// X axis the stems are drawn, and the `stem_values` specify what values the stems have.
pub fn plot(&self, axis_positions: &[f64], stem_values: &[f64]) {
let number_of_points = axis_positions.len().min(stem_values.len());
// If there is no data to plot, we stop here
if number_of_points == 0 {
return;
}
unsafe {
sys::ImPlot_PlotStemsdoublePtrdoublePtr(
self.label.as_ptr() as *const c_char,
axis_positions.as_ptr(),
stem_values.as_ptr(),
number_of_points as i32, // "as" casts saturate as of Rust 1.45. This is safe here.
self.reference_y,
0, // No offset
std::mem::size_of::<f64>() as i32, // Stride, set to one f64 for the standard use case
);
}
}
}

22
src/rect.rs Normal file
View file

@ -0,0 +1,22 @@
use sys::{ImPlotRect, ImVec4};
use crate::sys;
pub fn drag_rect(rect: &mut ImPlotRect) {
unsafe {
sys::ImPlot_DragRect(
0,
&mut rect.X.Min,
&mut rect.Y.Min,
&mut rect.X.Max,
&mut rect.Y.Max,
ImVec4 {
x: 1.0,
y: 0.0,
z: 1.0,
w: 0.4,
},
0,
);
}
}