Use Bevy ECS
This commit is contained in:
parent
dafebdabee
commit
fdd93fa7e8
340
Cargo.lock
generated
340
Cargo.lock
generated
@ -92,6 +92,37 @@ dependencies = [
|
|||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-channel"
|
||||||
|
version = "1.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2114d64672151c0c5eaa5e131ec84a74f06e1e559830dabba01ca30605d66319"
|
||||||
|
dependencies = [
|
||||||
|
"concurrent-queue",
|
||||||
|
"event-listener",
|
||||||
|
"futures-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-executor"
|
||||||
|
version = "1.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "871f9bb5e0a22eeb7e8cf16641feb87c9dc67032ccf8ff49e772eb9941d3a965"
|
||||||
|
dependencies = [
|
||||||
|
"async-task",
|
||||||
|
"concurrent-queue",
|
||||||
|
"fastrand",
|
||||||
|
"futures-lite",
|
||||||
|
"once_cell",
|
||||||
|
"slab",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-task"
|
||||||
|
version = "4.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "30696a84d817107fc028e049980e09d5e140e8da8f1caeb17e8e950658a3cea9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "atomic_refcell"
|
name = "atomic_refcell"
|
||||||
version = "0.1.8"
|
version = "0.1.8"
|
||||||
@ -115,6 +146,157 @@ version = "1.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bevy_app"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "32660ae99fa3498ca379de28b7e2f447e6531b0e432bf200901efeec075553c1"
|
||||||
|
dependencies = [
|
||||||
|
"bevy_derive",
|
||||||
|
"bevy_ecs",
|
||||||
|
"bevy_reflect",
|
||||||
|
"bevy_utils",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"web-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bevy_core"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "12c0f8614b6014671ab60bacb8bf681373d08b0bb15633b8ef72b895cf966d29"
|
||||||
|
dependencies = [
|
||||||
|
"bevy_app",
|
||||||
|
"bevy_derive",
|
||||||
|
"bevy_ecs",
|
||||||
|
"bevy_math",
|
||||||
|
"bevy_reflect",
|
||||||
|
"bevy_tasks",
|
||||||
|
"bevy_utils",
|
||||||
|
"bytemuck",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bevy_derive"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6abddf2ed415f31d28a9bf9ab3c0bc857e98a722858d38dba65bdda481f8d714"
|
||||||
|
dependencies = [
|
||||||
|
"bevy_macro_utils",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bevy_ecs"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "79e67dd06b14e787d2026fe6e2b63f67482afcc62284f20ea2784d8b0662e95f"
|
||||||
|
dependencies = [
|
||||||
|
"async-channel",
|
||||||
|
"bevy_ecs_macros",
|
||||||
|
"bevy_reflect",
|
||||||
|
"bevy_tasks",
|
||||||
|
"bevy_utils",
|
||||||
|
"downcast-rs",
|
||||||
|
"fixedbitset",
|
||||||
|
"fxhash",
|
||||||
|
"serde",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bevy_ecs_macros"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "718923a491490bd81074492d61fc08134f9c62a29ba8666818cd7a6630421246"
|
||||||
|
dependencies = [
|
||||||
|
"bevy_macro_utils",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bevy_macro_utils"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b7ddfc33a99547e36718e56e414541e461c74ec318ff987a1e9f4ff46d0dacbb"
|
||||||
|
dependencies = [
|
||||||
|
"cargo-manifest",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bevy_math"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "20288df0f70ff258bbaffaf55209f1271a7436438591bbffc3d81e4d84b423f2"
|
||||||
|
dependencies = [
|
||||||
|
"bevy_reflect",
|
||||||
|
"glam",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bevy_reflect"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4d0793107bc4b7c6bd04232d739fc8d70aa5fb313bfad6e850f91f79b2557eed"
|
||||||
|
dependencies = [
|
||||||
|
"bevy_reflect_derive",
|
||||||
|
"bevy_utils",
|
||||||
|
"downcast-rs",
|
||||||
|
"erased-serde",
|
||||||
|
"glam",
|
||||||
|
"parking_lot 0.11.2",
|
||||||
|
"serde",
|
||||||
|
"smallvec",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bevy_reflect_derive"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "81c88de8067d19dfde31662ee78e3ee6971e2df27715799f91b515b37a636677"
|
||||||
|
dependencies = [
|
||||||
|
"bevy_macro_utils",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"uuid",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bevy_tasks"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "db2b0f0b86c8f78c53a2d4c669522f45e725ed9d9c3d734f54ec30876494e04e"
|
||||||
|
dependencies = [
|
||||||
|
"async-channel",
|
||||||
|
"async-executor",
|
||||||
|
"event-listener",
|
||||||
|
"futures-lite",
|
||||||
|
"num_cpus",
|
||||||
|
"wasm-bindgen-futures",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bevy_utils"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2f354c584812996febd48cc885f36b23004b49d6680e73fc95a69a2bb17a48e5"
|
||||||
|
dependencies = [
|
||||||
|
"ahash",
|
||||||
|
"bevy_derive",
|
||||||
|
"getrandom",
|
||||||
|
"hashbrown",
|
||||||
|
"instant",
|
||||||
|
"tracing",
|
||||||
|
"uuid",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bincode"
|
name = "bincode"
|
||||||
version = "1.3.3"
|
version = "1.3.3"
|
||||||
@ -174,12 +356,24 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byteorder"
|
||||||
|
version = "1.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytes"
|
name = "bytes"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8"
|
checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cache-padded"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c1db59621ec70f09c5e9b597b220c7a2b43611f4710dc03ceb8748637775692c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "calloop"
|
name = "calloop"
|
||||||
version = "0.9.3"
|
version = "0.9.3"
|
||||||
@ -190,6 +384,17 @@ dependencies = [
|
|||||||
"nix",
|
"nix",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cargo-manifest"
|
||||||
|
version = "0.2.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "af6d65c7592744998c67947ec771c62687c76f00179a83ffd563c0482046bb98"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
"serde_derive",
|
||||||
|
"toml",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cast"
|
name = "cast"
|
||||||
version = "0.2.7"
|
version = "0.2.7"
|
||||||
@ -295,6 +500,15 @@ dependencies = [
|
|||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "concurrent-queue"
|
||||||
|
version = "1.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3"
|
||||||
|
dependencies = [
|
||||||
|
"cache-padded",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "core-foundation"
|
name = "core-foundation"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
@ -655,6 +869,15 @@ dependencies = [
|
|||||||
"parking_lot 0.12.0",
|
"parking_lot 0.12.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "erased-serde"
|
||||||
|
version = "0.3.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ad132dd8d0d0b546348d7d86cb3191aad14b34e5f979781fc005c80d4ac67ffd"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "error-code"
|
name = "error-code"
|
||||||
version = "2.3.1"
|
version = "2.3.1"
|
||||||
@ -665,6 +888,27 @@ dependencies = [
|
|||||||
"str-buf",
|
"str-buf",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "event-listener"
|
||||||
|
version = "2.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "77f3309417938f28bf8228fcff79a4a37103981e3e186d2ccd19c74b38f4eb71"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fastrand"
|
||||||
|
version = "1.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf"
|
||||||
|
dependencies = [
|
||||||
|
"instant",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fixedbitset"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "279fb028e20b3c4c320317955b77c5e0c9701f05a1d309905d6fc702cdc5053e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fnv"
|
name = "fnv"
|
||||||
version = "1.0.7"
|
version = "1.0.7"
|
||||||
@ -696,6 +940,42 @@ dependencies = [
|
|||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-core"
|
||||||
|
version = "0.3.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-io"
|
||||||
|
version = "0.3.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-lite"
|
||||||
|
version = "1.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48"
|
||||||
|
dependencies = [
|
||||||
|
"fastrand",
|
||||||
|
"futures-core",
|
||||||
|
"futures-io",
|
||||||
|
"memchr",
|
||||||
|
"parking",
|
||||||
|
"pin-project-lite",
|
||||||
|
"waker-fn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fxhash"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gethostname"
|
name = "gethostname"
|
||||||
version = "0.2.3"
|
version = "0.2.3"
|
||||||
@ -730,6 +1010,16 @@ dependencies = [
|
|||||||
"xml-rs",
|
"xml-rs",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "glam"
|
||||||
|
version = "0.20.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f43e957e744be03f5801a55472f593d43fabdebf25a4585db250f04d86b1675f"
|
||||||
|
dependencies = [
|
||||||
|
"bytemuck",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "glow"
|
name = "glow"
|
||||||
version = "0.11.2"
|
version = "0.11.2"
|
||||||
@ -825,6 +1115,10 @@ name = "hashbrown"
|
|||||||
version = "0.11.2"
|
version = "0.11.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
|
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
|
||||||
|
dependencies = [
|
||||||
|
"ahash",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "hermit-abi"
|
||||||
@ -895,6 +1189,18 @@ version = "1.0.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d"
|
checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "iyes_loopless"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e37cbe1fdc9aeed2d5ec064d3306ba4318723c20c5b0e4662d03c49fedcd491b"
|
||||||
|
dependencies = [
|
||||||
|
"bevy_app",
|
||||||
|
"bevy_core",
|
||||||
|
"bevy_ecs",
|
||||||
|
"bevy_utils",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jni"
|
name = "jni"
|
||||||
version = "0.19.0"
|
version = "0.19.0"
|
||||||
@ -1389,6 +1695,12 @@ dependencies = [
|
|||||||
"ttf-parser",
|
"ttf-parser",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "parking"
|
||||||
|
version = "2.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking_lot"
|
name = "parking_lot"
|
||||||
version = "0.11.2"
|
version = "0.11.2"
|
||||||
@ -1761,15 +2073,23 @@ name = "sketchrs"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"argmin",
|
"argmin",
|
||||||
|
"bevy_ecs",
|
||||||
"criterion",
|
"criterion",
|
||||||
"eframe",
|
"eframe",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
|
"iyes_loopless",
|
||||||
"levenberg-marquardt",
|
"levenberg-marquardt",
|
||||||
"nalgebra",
|
"nalgebra",
|
||||||
"nalgebra-sparse",
|
"nalgebra-sparse",
|
||||||
"nohash-hasher",
|
"nohash-hasher",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "slab"
|
||||||
|
version = "0.4.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "slog"
|
name = "slog"
|
||||||
version = "2.7.0"
|
version = "2.7.0"
|
||||||
@ -1827,6 +2147,9 @@ name = "smallvec"
|
|||||||
version = "1.8.0"
|
version = "1.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83"
|
checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smithay-client-toolkit"
|
name = "smithay-client-toolkit"
|
||||||
@ -1974,6 +2297,7 @@ version = "0.5.9"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7"
|
checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"indexmap",
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -2060,12 +2384,28 @@ dependencies = [
|
|||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "uuid"
|
||||||
|
version = "0.8.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "version_check"
|
name = "version_check"
|
||||||
version = "0.9.4"
|
version = "0.9.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "waker-fn"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "walkdir"
|
name = "walkdir"
|
||||||
version = "2.3.2"
|
version = "2.3.2"
|
||||||
|
@ -7,8 +7,10 @@ edition = "2021"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
argmin = { version = "0.5.1", features = ["nalgebra"] }
|
argmin = { version = "0.5.1", features = ["nalgebra"] }
|
||||||
|
bevy_ecs = "0.7.0"
|
||||||
eframe = { version = "0.18.0", features = [] }
|
eframe = { version = "0.18.0", features = [] }
|
||||||
indexmap = "1.8.1"
|
indexmap = "1.8.1"
|
||||||
|
iyes_loopless = "0.5.1"
|
||||||
levenberg-marquardt = "0.12.0"
|
levenberg-marquardt = "0.12.0"
|
||||||
nalgebra = "0.30.1"
|
nalgebra = "0.30.1"
|
||||||
nalgebra-sparse = "0.6.0"
|
nalgebra-sparse = "0.6.0"
|
||||||
|
178
src/geometry.rs
178
src/geometry.rs
@ -1,131 +1,139 @@
|
|||||||
mod entity;
|
|
||||||
mod var;
|
mod var;
|
||||||
|
|
||||||
use self::entity::{EntityId, EntityMap};
|
use std::ops::DerefMut;
|
||||||
|
|
||||||
|
use bevy_ecs::{
|
||||||
|
entity::Entity,
|
||||||
|
prelude::Component,
|
||||||
|
query::QueryEntityError,
|
||||||
|
system::{Commands, Query, SystemParam},
|
||||||
|
};
|
||||||
|
|
||||||
pub use self::var::*;
|
pub use self::var::*;
|
||||||
|
|
||||||
pub type Scalar = f64;
|
pub type Scalar = f64;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug, Component)]
|
||||||
pub struct PointEntity<V = VarId> {
|
pub struct Point<V = VarId> {
|
||||||
pub x: V,
|
pub x: V,
|
||||||
pub y: V,
|
pub y: V,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V> PointEntity<V> {
|
impl<V> Point<V> {
|
||||||
pub fn new(x: V, y: V) -> Self {
|
pub fn new(x: V, y: V) -> Self {
|
||||||
Self { x, y }
|
Self { x, y }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V> From<(V, V)> for PointEntity<V> {
|
impl<V> From<(V, V)> for Point<V> {
|
||||||
fn from(p: (V, V)) -> Self {
|
fn from(p: (V, V)) -> Self {
|
||||||
Self { x: p.0, y: p.1 }
|
Self { x: p.0, y: p.1 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type PointPos = PointEntity<Scalar>;
|
pub type PointPos = Point<Scalar>;
|
||||||
pub type PointId = EntityId<PointEntity>;
|
pub type PointId = Entity;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug, Component)]
|
||||||
// TODO: segment, ray and full line
|
// TODO: segment, ray and full line
|
||||||
// TODO: what if start and end are coincident?
|
// TODO: what if start and end are coincident?
|
||||||
pub struct LineEntity<P = PointId> {
|
pub struct Line<P = PointId> {
|
||||||
pub start: P,
|
pub start: P,
|
||||||
pub end: P,
|
pub end: P,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P> LineEntity<P> {
|
impl<P> Line<P> {
|
||||||
pub fn new(start: P, end: P) -> Self {
|
pub fn new(start: P, end: P) -> Self {
|
||||||
Self { start, end }
|
Self { start, end }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type LinePos = LineEntity<PointPos>;
|
pub type LinePos = Line<PointPos>;
|
||||||
pub type LineId = EntityId<LineEntity>;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Component)]
|
||||||
// TODO: arc. how to represent start and end of arc?
|
// TODO: arc. how to represent start and end of arc?
|
||||||
// angles, unit vectors, or a point for each?
|
// angles, unit vectors, or a point for each?
|
||||||
pub struct CircleEntity {
|
pub struct Circle {
|
||||||
pub center: PointId,
|
pub center: PointId,
|
||||||
pub radius: VarId,
|
pub radius: VarId,
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub type CirclePos = CircleEntity<PointPos>;
|
// pub type CirclePos = CircleEntity<PointPos>;
|
||||||
pub type CircleId = EntityId<CircleEntity>;
|
|
||||||
|
|
||||||
#[derive(Clone, Default)]
|
pub fn insert_point_at(commands: &mut Commands, point: impl Into<PointPos>) -> PointId {
|
||||||
pub struct SketchEntities {
|
let point = point.into();
|
||||||
vars: EntityMap<Var>,
|
let x = commands.spawn().insert(Var::new_free(point.x)).id();
|
||||||
points: EntityMap<PointEntity>,
|
let y = commands.spawn().insert(Var::new_free(point.y)).id();
|
||||||
lines: EntityMap<LineEntity>,
|
commands.spawn().insert(Point::new(x, y)).id()
|
||||||
circles: EntityMap<CircleEntity>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SketchEntities {
|
// TODO: figure out generic for this
|
||||||
pub fn vars(&self) -> &EntityMap<Var> {
|
#[derive(SystemParam)]
|
||||||
&self.vars
|
pub struct PointPosQuery<'w, 's> {
|
||||||
|
vars: Query<'w, 's, &'static Var>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// type PointPosQuery<'w, 's> = PointPosQueryImpl<'w, 's, &'static Var>;
|
||||||
|
// type PointPosQueryMut<'w, 's> = PointPosQueryImpl<'w, 's, &'static mut Var>;
|
||||||
|
|
||||||
|
// impl<'w, 's, Q> PointPosQueryImpl<'w, 's, Q>
|
||||||
|
// where
|
||||||
|
// Q: WorldQuery + 'static,
|
||||||
|
// for<'w2, 's2> <<Q as WorldQuery>::ReadOnlyFetch as Fetch<'w2, 's2>>::Item: Deref<Target = Var>,
|
||||||
|
impl<'w, 's> PointPosQuery<'w, 's> {
|
||||||
|
pub fn try_get(&self, point: &Point) -> Result<Var<PointPos>, QueryEntityError> {
|
||||||
|
let x = self.vars.get(point.x)?;
|
||||||
|
let y = self.vars.get(point.y)?;
|
||||||
|
Ok(x.merge(*y, PointPos::new))
|
||||||
}
|
}
|
||||||
|
pub fn get(&self, point: &Point) -> Var<PointPos> {
|
||||||
pub fn insert_var(&mut self, var: Var) -> VarId {
|
self.try_get(point).unwrap()
|
||||||
self.vars.insert(var)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_var_mut(&mut self, id: VarId) -> Option<&mut Var> {
|
#[derive(SystemParam)]
|
||||||
self.vars.get_mut(id)
|
pub struct PointPosQueryMut<'w, 's> {
|
||||||
}
|
vars: Query<'w, 's, &'static mut Var>,
|
||||||
|
}
|
||||||
pub fn points(&self) -> &EntityMap<PointEntity> {
|
|
||||||
&self.points
|
impl<'w, 's> PointPosQueryMut<'w, 's>
|
||||||
}
|
// impl<'w, 's, R> PointPosQueryImpl<'w, 's, Query<'w, 's, R>>
|
||||||
|
// where
|
||||||
pub fn insert_point(&mut self, point: PointEntity) -> PointId {
|
// R: WorldQuery,
|
||||||
assert!(self.vars.contains(point.x));
|
// for<'w2, 's2> <<R as WorldQuery>::Fetch as Fetch<'w2, 's2>>::Item: DerefMut<Target = Var>,
|
||||||
assert!(self.vars.contains(point.y));
|
{
|
||||||
self.points.insert(point)
|
pub fn get(&self, point: &Point) -> Result<Var<PointPos>, QueryEntityError> {
|
||||||
}
|
let x = self.vars.get(point.x)?;
|
||||||
|
let y = self.vars.get(point.y)?;
|
||||||
pub fn insert_point_at(&mut self, point: impl Into<PointPos>) -> PointId {
|
Ok(x.merge(*y, PointPos::new))
|
||||||
let point = point.into();
|
}
|
||||||
let x = self.insert_var(Var::new_free(point.x));
|
|
||||||
let y = self.insert_var(Var::new_free(point.y));
|
pub fn set(&mut self, point: &Point, move_to: PointPos) -> Result<(), QueryEntityError> {
|
||||||
self.insert_point(PointEntity::new(x, y))
|
for (id, val) in [(point.x, move_to.x), (point.y, move_to.y)] {
|
||||||
}
|
self.vars.get_mut(id)?.deref_mut().value = val;
|
||||||
|
}
|
||||||
fn remove_point(&mut self, point_id: PointId) -> bool {
|
Ok(())
|
||||||
// TODO: check if used by any line
|
}
|
||||||
self.points.remove(point_id)
|
}
|
||||||
}
|
|
||||||
|
#[derive(SystemParam)]
|
||||||
pub fn point_pos(&self, point: &PointEntity) -> Var<PointPos> {
|
pub struct LinePosQuery<'w, 's> {
|
||||||
// TODO: error handling?
|
point_pos: PointPosQuery<'w, 's>,
|
||||||
let x = self.vars.get(point.x).unwrap();
|
points: Query<'w, 's, &'static Point>,
|
||||||
let y = self.vars.get(point.y).unwrap();
|
}
|
||||||
x.merge(*y, PointPos::new)
|
|
||||||
}
|
impl<'w, 's> LinePosQuery<'w, 's> {
|
||||||
|
pub fn get(&self, line: &Line) -> Var<LinePos> {
|
||||||
pub fn lines(&self) -> &EntityMap<LineEntity> {
|
self.try_get(line).unwrap()
|
||||||
&self.lines
|
}
|
||||||
}
|
|
||||||
|
pub fn try_get(&self, line: &Line) -> Result<Var<LinePos>, QueryEntityError> {
|
||||||
pub fn insert_line(&mut self, line: LineEntity) -> LineId {
|
// TODO: error handling?
|
||||||
assert!(self.points.contains(line.start));
|
let start = self.points.get(line.start)?;
|
||||||
assert!(self.points.contains(line.end));
|
let start = self.point_pos.try_get(start)?;
|
||||||
self.lines.insert(line)
|
|
||||||
}
|
let end = self.points.get(line.end)?;
|
||||||
|
let end = self.point_pos.try_get(end)?;
|
||||||
fn remove_line(&mut self, line_id: LineId) -> bool {
|
Ok(start.merge(end, LinePos::new))
|
||||||
self.lines.remove(line_id)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn line_pos(&self, line: &LineEntity) -> Var<LinePos> {
|
|
||||||
// TODO: error handling?
|
|
||||||
let start = self.points.get(line.start).unwrap();
|
|
||||||
let start = self.point_pos(start);
|
|
||||||
|
|
||||||
let end = self.points.get(line.end).unwrap();
|
|
||||||
let end = self.point_pos(end);
|
|
||||||
start.merge(end, LinePos::new)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,117 +0,0 @@
|
|||||||
use std::marker::PhantomData;
|
|
||||||
|
|
||||||
use indexmap::IndexMap;
|
|
||||||
|
|
||||||
// HashMap with fast no-op hash function and preserves insertion order
|
|
||||||
type IntIndexMap<K, V> = IndexMap<K, V, nohash_hasher::BuildNoHashHasher<K>>;
|
|
||||||
|
|
||||||
pub struct EntityId<T>(u32, PhantomData<T>);
|
|
||||||
|
|
||||||
impl<T> Default for EntityId<T> {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self(1, Default::default())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> nohash_hasher::IsEnabled for EntityId<T> {}
|
|
||||||
|
|
||||||
impl<T> EntityId<T> {
|
|
||||||
pub fn id(&self) -> u32 {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
|
|
||||||
fn take_next(&mut self) -> Self {
|
|
||||||
let id = *self;
|
|
||||||
self.0 += 1;
|
|
||||||
id
|
|
||||||
}
|
|
||||||
|
|
||||||
fn invalid() -> Self {
|
|
||||||
Self(u32::MAX, Default::default())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct EntityMap<T> {
|
|
||||||
map: IntIndexMap<EntityId<T>, T>,
|
|
||||||
next_id: EntityId<T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> EntityMap<T> {
|
|
||||||
pub fn insert(&mut self, entity: T) -> EntityId<T> {
|
|
||||||
let id = self.next_id.take_next();
|
|
||||||
self.map.insert(id, entity);
|
|
||||||
id
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn contains(&self, id: EntityId<T>) -> bool {
|
|
||||||
self.map.contains_key(&id)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn remove(&mut self, id: EntityId<T>) -> bool {
|
|
||||||
self.map.remove(&id).is_some()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get(&self, id: EntityId<T>) -> Option<&T> {
|
|
||||||
self.map.get(&id)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_mut(&mut self, id: EntityId<T>) -> Option<&mut T> {
|
|
||||||
self.map.get_mut(&id)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn iter(&self) -> impl Iterator<Item = (EntityId<T>, &T)> {
|
|
||||||
self.map.iter().map(|(id, v)| (*id, v))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Need to reimplement all of this without the T bound :/
|
|
||||||
|
|
||||||
impl<T> PartialEq for EntityId<T> {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
self.0 == other.0 && self.1 == other.1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Eq for EntityId<T> {}
|
|
||||||
|
|
||||||
impl<T> PartialOrd for EntityId<T> {
|
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
|
||||||
self.0.partial_cmp(&other.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Ord for EntityId<T> {
|
|
||||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
|
||||||
self.0.cmp(&other.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Clone for EntityId<T> {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
Self(self.0.clone(), self.1.clone())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Copy for EntityId<T> {}
|
|
||||||
|
|
||||||
impl<T> std::hash::Hash for EntityId<T> {
|
|
||||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
|
||||||
self.0.hash(state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> std::fmt::Debug for EntityId<T> {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
f.debug_tuple("EntityId").field(&self.0).finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Default for EntityMap<T> {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
map: Default::default(),
|
|
||||||
next_id: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,4 +1,6 @@
|
|||||||
use super::{EntityId, Scalar};
|
use bevy_ecs::{prelude::Component, entity::Entity};
|
||||||
|
|
||||||
|
use super::Scalar;
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
pub enum VarStatus {
|
pub enum VarStatus {
|
||||||
@ -20,7 +22,7 @@ impl VarStatus {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug, Component)]
|
||||||
pub struct Var<T = Scalar> {
|
pub struct Var<T = Scalar> {
|
||||||
pub value: T,
|
pub value: T,
|
||||||
pub status: VarStatus,
|
pub status: VarStatus,
|
||||||
@ -59,4 +61,4 @@ impl<T> std::ops::DerefMut for Var<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type VarId = EntityId<Var>;
|
pub type VarId = Entity;
|
||||||
|
607
src/main.rs
607
src/main.rs
@ -1,9 +1,14 @@
|
|||||||
|
use bevy_ecs::{
|
||||||
|
prelude::*,
|
||||||
|
system::{Commands, IntoSystem, Query, Res, ResMut, System},
|
||||||
|
};
|
||||||
use eframe::{
|
use eframe::{
|
||||||
egui::{self, CursorIcon, Frame, PointerButton, Sense, Ui},
|
egui::{self, CursorIcon, Painter, Response, Sense, Ui},
|
||||||
emath::{Pos2, Rect, RectTransform, Vec2},
|
emath::{Pos2, Rect, RectTransform, Vec2},
|
||||||
epaint::{color::Hsva, Color32, Stroke},
|
epaint::{color::Hsva, Color32, Stroke},
|
||||||
};
|
};
|
||||||
use geometry::{LineEntity, LineId, PointId, PointPos, SketchEntities};
|
use geometry::{Line, LinePosQuery, Point, PointId, PointPos, PointPosQuery, PointPosQueryMut};
|
||||||
|
use iyes_loopless::prelude::*;
|
||||||
|
|
||||||
mod geometry;
|
mod geometry;
|
||||||
mod optimization;
|
mod optimization;
|
||||||
@ -18,7 +23,7 @@ fn main() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
#[derive(Clone, Copy, PartialEq)]
|
||||||
enum Tool {
|
enum Tool {
|
||||||
Select,
|
Select,
|
||||||
Move,
|
Move,
|
||||||
@ -32,35 +37,29 @@ impl Default for Tool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
struct ToScreen(RectTransform);
|
||||||
struct ViewState {
|
|
||||||
tool: Tool,
|
|
||||||
hover_point: Option<PointId>,
|
|
||||||
select_point: Option<PointId>,
|
|
||||||
hover_line: Option<LineId>,
|
|
||||||
select_line: Option<LineId>,
|
|
||||||
drag_delta: Vec2,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct MyApp {
|
impl ToScreen {
|
||||||
state: ViewState,
|
fn transform_pos(&self, pos: &PointPos) -> Pos2 {
|
||||||
entities: SketchEntities,
|
self.0 * Pos2::new(pos.x as f32, pos.y as f32)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for MyApp {
|
fn inverse_transform(&self, pos: Pos2) -> Pos2 {
|
||||||
fn default() -> Self {
|
self.0.inverse() * pos
|
||||||
let mut entities = SketchEntities::default();
|
}
|
||||||
let p1 = entities.insert_point_at((10., 30.));
|
|
||||||
let p2 = entities.insert_point_at((-20., 15.));
|
fn inverse_transform_to_point(&self, pos: Pos2) -> PointPos {
|
||||||
entities.insert_point_at((0., -10.));
|
let pos = self.inverse_transform(pos);
|
||||||
entities.insert_line(LineEntity::new(p1, p2));
|
PointPos::new(pos.x as f64, pos.y as f64)
|
||||||
Self {
|
|
||||||
state: ViewState::default(),
|
|
||||||
entities,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
struct Hovered;
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
struct Selected;
|
||||||
|
|
||||||
fn color_for_var_status(status: geometry::VarStatus) -> Hsva {
|
fn color_for_var_status(status: geometry::VarStatus) -> Hsva {
|
||||||
use geometry::VarStatus::*;
|
use geometry::VarStatus::*;
|
||||||
match status {
|
match status {
|
||||||
@ -73,13 +72,359 @@ fn color_for_var_status(status: geometry::VarStatus) -> Hsva {
|
|||||||
|
|
||||||
const POINT_RADIUS: f32 = 3.0;
|
const POINT_RADIUS: f32 = 3.0;
|
||||||
|
|
||||||
|
fn update_hover_point(
|
||||||
|
response: Res<Response>,
|
||||||
|
to_screen: Res<ToScreen>,
|
||||||
|
point_pos: PointPosQuery,
|
||||||
|
points: Query<(PointId, &Point)>,
|
||||||
|
mut commands: Commands,
|
||||||
|
) {
|
||||||
|
points.for_each(|(id, point)| {
|
||||||
|
let hovered = if let Some(hover_pos) = response.hover_pos() {
|
||||||
|
let pos = point_pos.get(point);
|
||||||
|
let center = to_screen.transform_pos(&*pos);
|
||||||
|
|
||||||
|
(hover_pos - center).length() < (POINT_RADIUS * 3.)
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
|
if hovered {
|
||||||
|
commands.entity(id).insert(Hovered);
|
||||||
|
} else {
|
||||||
|
commands.entity(id).remove::<Hovered>();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_hover_line(
|
||||||
|
response: Res<Response>,
|
||||||
|
to_screen: Res<ToScreen>,
|
||||||
|
lines: Query<(Entity, &Line)>,
|
||||||
|
line_pos: LinePosQuery,
|
||||||
|
mut commands: Commands,
|
||||||
|
) {
|
||||||
|
lines.for_each(|(id, line)| {
|
||||||
|
let hovered = if let Some(hover_pos) = response.hover_pos() {
|
||||||
|
let pos = line_pos.get(line);
|
||||||
|
let points = [
|
||||||
|
to_screen.transform_pos(&pos.start),
|
||||||
|
to_screen.transform_pos(&pos.end),
|
||||||
|
];
|
||||||
|
|
||||||
|
let b = points[1] - points[0];
|
||||||
|
let a = hover_pos - points[0];
|
||||||
|
let p = a.dot(b) / b.dot(b);
|
||||||
|
let perp = a - (p * b);
|
||||||
|
((0.)..=(1.)).contains(&p) && perp.length() < 5.0
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
|
if hovered {
|
||||||
|
commands.entity(id).insert(Hovered);
|
||||||
|
} else {
|
||||||
|
commands.entity(id).remove::<Hovered>();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_cursor_icon(
|
||||||
|
response: Res<Response>,
|
||||||
|
tool: Res<Tool>,
|
||||||
|
hovered: Query<(), With<Hovered>>,
|
||||||
|
selected: Query<(), With<Selected>>,
|
||||||
|
) {
|
||||||
|
response.ctx.output().cursor_icon = match *tool {
|
||||||
|
Tool::Select => {
|
||||||
|
if !hovered.is_empty() {
|
||||||
|
CursorIcon::PointingHand
|
||||||
|
} else {
|
||||||
|
CursorIcon::Default
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Tool::Move => {
|
||||||
|
if !selected.is_empty() {
|
||||||
|
CursorIcon::Grabbing
|
||||||
|
} else if !hovered.is_empty() {
|
||||||
|
CursorIcon::Grab
|
||||||
|
} else {
|
||||||
|
CursorIcon::Move
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Tool::AddPoint => CursorIcon::None,
|
||||||
|
Tool::AddLine => CursorIcon::None,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn select_tool(
|
||||||
|
response: Res<Response>,
|
||||||
|
hovered: Query<Entity, With<Hovered>>,
|
||||||
|
selected: Query<Entity, With<Selected>>,
|
||||||
|
mut commands: Commands,
|
||||||
|
) {
|
||||||
|
response.ctx.output().cursor_icon = if !hovered.is_empty() {
|
||||||
|
CursorIcon::PointingHand
|
||||||
|
} else {
|
||||||
|
CursorIcon::Default
|
||||||
|
};
|
||||||
|
|
||||||
|
if response.clicked() {
|
||||||
|
selected.for_each(|selected| {
|
||||||
|
commands.entity(selected).remove::<Selected>();
|
||||||
|
});
|
||||||
|
// TODO: choose which to select
|
||||||
|
if let Some(hovered) = hovered.iter().next() {
|
||||||
|
commands.entity(hovered).insert(Selected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct DragDelta(Vec2);
|
||||||
|
|
||||||
|
// TODO: move other entities
|
||||||
|
fn move_tool(
|
||||||
|
response: Res<Response>,
|
||||||
|
to_screen: Res<ToScreen>,
|
||||||
|
mut drag_delta: Local<DragDelta>,
|
||||||
|
mut point_pos: PointPosQueryMut,
|
||||||
|
hovered: Query<(Entity, &Point), With<Hovered>>,
|
||||||
|
selected: Query<(Entity, &Point), With<Selected>>,
|
||||||
|
mut commands: Commands,
|
||||||
|
) {
|
||||||
|
let hover_pos = response.hover_pos().unwrap();
|
||||||
|
|
||||||
|
response.ctx.output().cursor_icon = if !selected.is_empty() {
|
||||||
|
CursorIcon::Grabbing
|
||||||
|
} else if !hovered.is_empty() {
|
||||||
|
CursorIcon::Grab
|
||||||
|
} else {
|
||||||
|
CursorIcon::Move
|
||||||
|
};
|
||||||
|
|
||||||
|
let selected = if response.drag_started() {
|
||||||
|
// TODO: choose which to select
|
||||||
|
let to_select = hovered.iter().next();
|
||||||
|
if let Some(hovered) = to_select {
|
||||||
|
commands.entity(hovered.0).insert(Selected);
|
||||||
|
}
|
||||||
|
to_select
|
||||||
|
} else if response.drag_released() {
|
||||||
|
selected.for_each(|selected| {
|
||||||
|
commands.entity(selected.0).remove::<Selected>();
|
||||||
|
});
|
||||||
|
drag_delta.0 = Vec2::ZERO;
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
selected.iter().next()
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some((_, point)) = selected {
|
||||||
|
if response.drag_started() {
|
||||||
|
let drag_point_pos = point_pos.get(point).unwrap();
|
||||||
|
drag_delta.0 = hover_pos - to_screen.transform_pos(&*drag_point_pos);
|
||||||
|
}
|
||||||
|
let move_to = to_screen.inverse_transform_to_point(hover_pos - drag_delta.0);
|
||||||
|
point_pos.set(point, move_to).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_point(commands: &mut Commands, pos: Pos2, to_screen: &ToScreen) -> PointId {
|
||||||
|
let point_pos = to_screen.inverse_transform(pos);
|
||||||
|
let point_pos = (point_pos.x as f64, point_pos.y as f64);
|
||||||
|
geometry::insert_point_at(commands, point_pos)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_point_tool(
|
||||||
|
response: Res<Response>,
|
||||||
|
to_screen: Res<ToScreen>,
|
||||||
|
painter: ResMut<egui::Painter>,
|
||||||
|
mut commands: Commands,
|
||||||
|
) {
|
||||||
|
let hover_pos = response.hover_pos().unwrap();
|
||||||
|
if response.clicked() {
|
||||||
|
add_point(&mut commands, hover_pos, &*to_screen);
|
||||||
|
} else {
|
||||||
|
painter.circle_filled(hover_pos, POINT_RADIUS, Color32::WHITE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_line_tool(
|
||||||
|
response: Res<Response>,
|
||||||
|
to_screen: Res<ToScreen>,
|
||||||
|
painter: ResMut<egui::Painter>,
|
||||||
|
hovered: Query<Entity, (With<Hovered>, With<Point>)>,
|
||||||
|
selected: Query<(Entity, &Point), With<Selected>>,
|
||||||
|
point_pos: PointPosQuery,
|
||||||
|
mut commands: Commands,
|
||||||
|
) {
|
||||||
|
let hover_pos = response.hover_pos().unwrap();
|
||||||
|
|
||||||
|
match (selected.iter().next(), response.clicked()) {
|
||||||
|
(None, false) => {
|
||||||
|
painter.circle_filled(hover_pos, POINT_RADIUS, Color32::DARK_GRAY);
|
||||||
|
}
|
||||||
|
(None, true) => {
|
||||||
|
let point_id = match hovered.iter().next() {
|
||||||
|
Some(hovered) => hovered,
|
||||||
|
None => add_point(&mut commands, hover_pos, &*to_screen),
|
||||||
|
};
|
||||||
|
commands.entity(point_id).insert(Selected);
|
||||||
|
}
|
||||||
|
(Some(start_point), false) => {
|
||||||
|
let start_point_pos = point_pos.get(start_point.1);
|
||||||
|
let points = [to_screen.transform_pos(&start_point_pos), hover_pos];
|
||||||
|
|
||||||
|
let stroke = Stroke::new(2.0, Color32::DARK_GRAY);
|
||||||
|
|
||||||
|
painter.line_segment(points, stroke);
|
||||||
|
|
||||||
|
painter.circle_filled(hover_pos, POINT_RADIUS, Color32::DARK_GRAY);
|
||||||
|
}
|
||||||
|
(Some(start_point), true) => {
|
||||||
|
// TODO: add point if no hover point
|
||||||
|
let end_point = hovered
|
||||||
|
.iter()
|
||||||
|
.next()
|
||||||
|
.unwrap_or_else(|| add_point(&mut commands, hover_pos, &*to_screen));
|
||||||
|
|
||||||
|
let line = Line::new(start_point.0, end_point);
|
||||||
|
commands.spawn().insert(line);
|
||||||
|
|
||||||
|
selected.for_each(|selected| {
|
||||||
|
commands.entity(selected.0).remove::<Selected>();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_hovered(response: Res<Response>) -> bool {
|
||||||
|
response.hover_pos().is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_tool_active(tool: Tool) -> impl System<In = (), Out = bool> {
|
||||||
|
IntoSystem::into_system(move |active_tool: Res<Tool>| *active_tool == tool)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn paint_lines(
|
||||||
|
to_screen: Res<ToScreen>,
|
||||||
|
painter: ResMut<Painter>,
|
||||||
|
lines: Query<(Entity, &Line)>,
|
||||||
|
hovered: Query<(), With<Hovered>>,
|
||||||
|
selected: Query<(), With<Selected>>,
|
||||||
|
line_pos: LinePosQuery,
|
||||||
|
) {
|
||||||
|
lines.for_each(|(id, line)| {
|
||||||
|
let pos = line_pos.get(line);
|
||||||
|
let points = [
|
||||||
|
to_screen.transform_pos(&pos.start),
|
||||||
|
to_screen.transform_pos(&pos.end),
|
||||||
|
];
|
||||||
|
|
||||||
|
let mut color = color_for_var_status(pos.status);
|
||||||
|
color.v -= 0.6;
|
||||||
|
if hovered.contains(id) || selected.contains(id) {
|
||||||
|
color.s -= 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
let stroke = Stroke::new(2.0, color);
|
||||||
|
|
||||||
|
painter.line_segment(points, stroke);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn paint_points(
|
||||||
|
to_screen: Res<ToScreen>,
|
||||||
|
painter: ResMut<Painter>,
|
||||||
|
points: Query<(Entity, &Point)>,
|
||||||
|
hovered: Query<(), With<Hovered>>,
|
||||||
|
selected: Query<(), With<Selected>>,
|
||||||
|
point_pos: PointPosQuery,
|
||||||
|
) {
|
||||||
|
points.for_each(|(id, point)| {
|
||||||
|
let pos = point_pos.get(point);
|
||||||
|
|
||||||
|
let center = to_screen.transform_pos(&*pos);
|
||||||
|
|
||||||
|
let color = color_for_var_status(pos.status);
|
||||||
|
let stroke = if selected.contains(id) || hovered.contains(id) {
|
||||||
|
// color.s -= 0.8;
|
||||||
|
Stroke::new(1.0, Color32::WHITE)
|
||||||
|
} else {
|
||||||
|
Stroke::default()
|
||||||
|
};
|
||||||
|
painter.circle(center, POINT_RADIUS, color, stroke);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MyApp {
|
||||||
|
world: World,
|
||||||
|
show_entities_stage: SystemStage,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init(mut commands: Commands) {
|
||||||
|
let p1 = geometry::insert_point_at(&mut commands, (10., 30.));
|
||||||
|
let p2 = geometry::insert_point_at(&mut commands, (-20., 15.));
|
||||||
|
geometry::insert_point_at(&mut commands, (0., -10.));
|
||||||
|
commands.spawn().insert(Line::new(p1, p2));
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for MyApp {
|
||||||
|
fn default() -> Self {
|
||||||
|
let mut world = World::default();
|
||||||
|
|
||||||
|
world.init_resource::<Tool>();
|
||||||
|
|
||||||
|
let mut init_stage = SystemStage::single_threaded().with_system(init);
|
||||||
|
init_stage.run(&mut world);
|
||||||
|
Self {
|
||||||
|
world,
|
||||||
|
show_entities_stage: Self::create_show_entities_stage(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl MyApp {
|
impl MyApp {
|
||||||
|
fn create_show_entities_stage() -> SystemStage {
|
||||||
|
#[derive(SystemLabel, Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
struct InputGroup;
|
||||||
|
|
||||||
|
#[derive(SystemLabel, Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
struct ToolsGroup;
|
||||||
|
|
||||||
|
SystemStage::single_threaded()
|
||||||
|
.with_system_set(
|
||||||
|
ConditionSet::new()
|
||||||
|
.label("input")
|
||||||
|
.with_system(update_hover_point)
|
||||||
|
.with_system(update_hover_line)
|
||||||
|
.into(),
|
||||||
|
)
|
||||||
|
.with_system_set(
|
||||||
|
ConditionSet::new()
|
||||||
|
.label("tools")
|
||||||
|
.after("input")
|
||||||
|
.run_if(is_hovered)
|
||||||
|
.with_system(update_cursor_icon)
|
||||||
|
.with_system(select_tool.run_if(is_tool_active(Tool::Select)))
|
||||||
|
.with_system(move_tool.run_if(is_tool_active(Tool::Move)))
|
||||||
|
.with_system(add_point_tool.run_if(is_tool_active(Tool::AddPoint)))
|
||||||
|
.with_system(add_line_tool.run_if(is_tool_active(Tool::AddLine)))
|
||||||
|
.into(),
|
||||||
|
)
|
||||||
|
.with_system(paint_lines.label("paint_lines").after("tools")) // TODO order dependency
|
||||||
|
.with_system(paint_points.after("paint_lines"))
|
||||||
|
}
|
||||||
|
|
||||||
fn show_toolbar(&mut self, ui: &mut Ui) {
|
fn show_toolbar(&mut self, ui: &mut Ui) {
|
||||||
ui.heading("sketchrs");
|
ui.heading("sketchrs");
|
||||||
|
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.label("Tool: ");
|
ui.label("Tool: ");
|
||||||
let mut tool = &mut self.state.tool;
|
|
||||||
|
let tool = &mut *self.world.resource_mut::<Tool>();
|
||||||
|
|
||||||
ui.selectable_value(tool, Tool::Select, "Select");
|
ui.selectable_value(tool, Tool::Select, "Select");
|
||||||
ui.selectable_value(tool, Tool::Move, "Move");
|
ui.selectable_value(tool, Tool::Move, "Move");
|
||||||
ui.selectable_value(tool, Tool::AddPoint, "+ Point");
|
ui.selectable_value(tool, Tool::AddPoint, "+ Point");
|
||||||
@ -88,200 +433,44 @@ impl MyApp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn show_entities(&mut self, ui: &mut Ui) {
|
fn show_entities(&mut self, ui: &mut Ui) {
|
||||||
let mut state = &mut self.state;
|
let sense = match *self.world.resource::<Tool>() {
|
||||||
|
|
||||||
let sense = match state.tool {
|
|
||||||
Tool::Move => Sense::drag(),
|
Tool::Move => Sense::drag(),
|
||||||
Tool::Select | Tool::AddPoint | Tool::AddLine => Sense::click(),
|
Tool::Select | Tool::AddPoint | Tool::AddLine => Sense::click(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let (response, painter) = ui.allocate_painter(ui.available_size(), sense);
|
let (response, painter) = ui.allocate_painter(ui.available_size(), sense);
|
||||||
let ctx = response.ctx.clone();
|
let to_screen = ToScreen(RectTransform::from_to(
|
||||||
let to_screen = RectTransform::from_to(
|
|
||||||
Rect::from_center_size(Pos2::ZERO, response.rect.size() / 2.0),
|
Rect::from_center_size(Pos2::ZERO, response.rect.size() / 2.0),
|
||||||
response.rect,
|
response.rect,
|
||||||
);
|
));
|
||||||
|
self.world.insert_resource(to_screen);
|
||||||
|
self.world.insert_resource(response);
|
||||||
|
self.world.insert_resource(painter);
|
||||||
|
|
||||||
let transform_pos = |pos: &PointPos| to_screen * Pos2::new(pos.x as f32, pos.y as f32);
|
self.show_entities_stage.run(&mut self.world);
|
||||||
|
|
||||||
state.hover_point = None;
|
self.world.remove_resource::<Painter>();
|
||||||
state.hover_line = None;
|
self.world.remove_resource::<Response>();
|
||||||
|
self.world.remove_resource::<ToScreen>();
|
||||||
if let Some(hover_pos) = response.hover_pos() {
|
|
||||||
for (id, point) in self
|
|
||||||
.entities
|
|
||||||
.points()
|
|
||||||
.iter()
|
|
||||||
.filter(|(id, _)| Some(*id) != state.select_point)
|
|
||||||
{
|
|
||||||
let pos = self.entities.point_pos(point);
|
|
||||||
let center = transform_pos(&*pos);
|
|
||||||
|
|
||||||
if (hover_pos - center).length() < (POINT_RADIUS * 3.) {
|
|
||||||
state.hover_point = Some(id);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (id, line) in self.entities.lines().iter() {
|
|
||||||
let pos = self.entities.line_pos(line);
|
|
||||||
let points = [transform_pos(&pos.start), transform_pos(&pos.end)];
|
|
||||||
|
|
||||||
let b = points[1] - points[0];
|
|
||||||
let a = hover_pos - points[0];
|
|
||||||
let p = a.dot(b) / b.dot(b);
|
|
||||||
let perp = a - (p * b);
|
|
||||||
let hovered = ((0.)..=(1.)).contains(&p) && perp.length() < 5.0;
|
|
||||||
|
|
||||||
if hovered {
|
|
||||||
state.hover_line = Some(id);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.output().cursor_icon = match state.tool {
|
|
||||||
Tool::Select => {
|
|
||||||
if state.hover_point.is_some() {
|
|
||||||
CursorIcon::PointingHand
|
|
||||||
} else {
|
|
||||||
CursorIcon::Default
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Tool::Move => {
|
|
||||||
if state.select_point.is_some() {
|
|
||||||
CursorIcon::Grabbing
|
|
||||||
} else if state.hover_point.is_some() {
|
|
||||||
CursorIcon::Grab
|
|
||||||
} else {
|
|
||||||
CursorIcon::Move
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Tool::AddPoint => CursorIcon::None,
|
|
||||||
Tool::AddLine => CursorIcon::None,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut add_point = || {
|
|
||||||
let point_pos = to_screen.inverse() * hover_pos;
|
|
||||||
let point_pos = (point_pos.x as f64, point_pos.y as f64);
|
|
||||||
self.entities.insert_point_at(point_pos)
|
|
||||||
};
|
|
||||||
|
|
||||||
match state.tool {
|
|
||||||
Tool::Select => {
|
|
||||||
if response.clicked() {
|
|
||||||
state.select_point = None;
|
|
||||||
state.select_line = None;
|
|
||||||
if state.hover_point.is_some() {
|
|
||||||
state.select_point = state.hover_point;
|
|
||||||
} else if state.hover_line.is_some() {
|
|
||||||
state.select_line = state.hover_line;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Tool::Move => {
|
|
||||||
let drag_started = response.drag_started();
|
|
||||||
if drag_started {
|
|
||||||
state.select_point = state.hover_point;
|
|
||||||
} else if response.drag_released() {
|
|
||||||
state.select_point = None;
|
|
||||||
state.drag_delta = Vec2::ZERO;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(point_id) = state.select_point {
|
|
||||||
let point = self.entities.points().get(point_id).unwrap();
|
|
||||||
if drag_started {
|
|
||||||
let point_pos = self.entities.point_pos(point);
|
|
||||||
state.drag_delta = hover_pos - transform_pos(&*point_pos);
|
|
||||||
}
|
|
||||||
let move_to = to_screen.inverse() * (hover_pos - state.drag_delta);
|
|
||||||
for (id, val) in [(point.x, move_to.x), (point.y, move_to.y)] {
|
|
||||||
self.entities.get_var_mut(id).unwrap().value = val as f64;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Tool::AddPoint => {
|
|
||||||
if response.clicked() {
|
|
||||||
add_point();
|
|
||||||
} else {
|
|
||||||
painter.circle_filled(hover_pos, POINT_RADIUS, Color32::WHITE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Tool::AddLine => {
|
|
||||||
match (state.select_point, response.clicked()) {
|
|
||||||
(Some(start_point_id), true) => {
|
|
||||||
// TODO: add point if no hover point
|
|
||||||
let end_point = state.hover_point.unwrap_or_else(add_point);
|
|
||||||
|
|
||||||
let line = LineEntity::new(start_point_id, end_point);
|
|
||||||
self.entities.insert_line(line);
|
|
||||||
|
|
||||||
state.select_point = None;
|
|
||||||
}
|
|
||||||
(None, true) => {
|
|
||||||
state.select_point = Some(state.hover_point.unwrap_or_else(add_point));
|
|
||||||
}
|
|
||||||
(Some(first_point_id), false) => {
|
|
||||||
let first_point = self.entities.points().get(first_point_id).unwrap();
|
|
||||||
let first_point_pos = self.entities.point_pos(first_point);
|
|
||||||
let points = [transform_pos(&first_point_pos), hover_pos];
|
|
||||||
|
|
||||||
let stroke = Stroke::new(2.0, Color32::DARK_GRAY);
|
|
||||||
|
|
||||||
painter.line_segment(points, stroke);
|
|
||||||
|
|
||||||
painter.circle_filled(hover_pos, POINT_RADIUS, Color32::DARK_GRAY);
|
|
||||||
}
|
|
||||||
(None, false) => {
|
|
||||||
painter.circle_filled(hover_pos, POINT_RADIUS, Color32::DARK_GRAY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (id, line) in self.entities.lines().iter() {
|
|
||||||
let pos = self.entities.line_pos(line);
|
|
||||||
let points = [transform_pos(&pos.start), transform_pos(&pos.end)];
|
|
||||||
|
|
||||||
let mut color = color_for_var_status(pos.status);
|
|
||||||
color.v -= 0.6;
|
|
||||||
if state.hover_point.is_none()
|
|
||||||
&& (state.select_point.is_none() || state.tool != Tool::Move)
|
|
||||||
&& (Some(id) == state.hover_line || Some(id) == state.select_line)
|
|
||||||
{
|
|
||||||
color.s -= 0.8;
|
|
||||||
}
|
|
||||||
|
|
||||||
let stroke = Stroke::new(2.0, color);
|
|
||||||
|
|
||||||
painter.line_segment(points, stroke);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (id, point) in self.entities.points().iter() {
|
|
||||||
let pos = self.entities.point_pos(point);
|
|
||||||
|
|
||||||
let center = transform_pos(&*pos);
|
|
||||||
|
|
||||||
let mut color = color_for_var_status(pos.status);
|
|
||||||
let stroke = match (state.select_point, state.hover_point) {
|
|
||||||
(Some(sid), _) | (_, Some(sid)) if id == sid => {
|
|
||||||
// color.s -= 0.8;
|
|
||||||
Stroke::new(1.0, Color32::WHITE)
|
|
||||||
}
|
|
||||||
_ => Stroke::default(),
|
|
||||||
};
|
|
||||||
painter.circle(center, POINT_RADIUS, color, stroke);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show_side_panel(&mut self, ui: &mut Ui) {
|
fn show_side_panel(&mut self, ui: &mut Ui) {
|
||||||
ui.vertical(|ui| match self.state.tool {
|
let tool = *self.world.resource::<Tool>();
|
||||||
|
ui.vertical(|ui| match tool {
|
||||||
Tool::Select => {
|
Tool::Select => {
|
||||||
if let Some(point_id) = self.state.select_point {
|
let mut selected = self
|
||||||
ui.label(format!("Selected point {}", point_id.id()));
|
.world
|
||||||
} else if let Some(line_id) = self.state.select_line {
|
.query_filtered::<(Entity, Option<&Point>, Option<&Line>), With<Selected>>();
|
||||||
ui.label(format!("Selected line {}", line_id.id()));
|
let mut count = 0;
|
||||||
} else {
|
selected.for_each(&self.world, |(id, point, line)| {
|
||||||
|
count += 1;
|
||||||
|
if point.is_some() {
|
||||||
|
ui.label(format!("Selected point {}", id.id()));
|
||||||
|
} else if line.is_some() {
|
||||||
|
ui.label(format!("Selected line {}", id.id()));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if count == 0 {
|
||||||
ui.label("No selection");
|
ui.label("No selection");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user