Compare commits
No commits in common. "4189c5188edf646d7739ab2a778db91927a256c4" and "37f8edb5c186e8a5e0cbb141aca5d595506dfe4d" have entirely different histories.
4189c5188e
...
37f8edb5c1
6 changed files with 105 additions and 645 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,2 +1 @@
|
||||||
/target
|
/target
|
||||||
*.json
|
|
||||||
|
|
249
Cargo.lock
generated
249
Cargo.lock
generated
|
@ -23,10 +23,6 @@ name = "accesskit"
|
||||||
version = "0.12.3"
|
version = "0.12.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "74a4b14f3d99c1255dcba8f45621ab1a2e7540a0009652d33989005a4d0bfc6b"
|
checksum = "74a4b14f3d99c1255dcba8f45621ab1a2e7540a0009652d33989005a4d0bfc6b"
|
||||||
dependencies = [
|
|
||||||
"enumn",
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "accesskit_consumer"
|
name = "accesskit_consumer"
|
||||||
|
@ -108,7 +104,6 @@ dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"getrandom",
|
"getrandom",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"serde",
|
|
||||||
"version_check",
|
"version_check",
|
||||||
"zerocopy",
|
"zerocopy",
|
||||||
]
|
]
|
||||||
|
@ -197,12 +192,6 @@ version = "1.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b"
|
checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ascii"
|
|
||||||
version = "1.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d92bec98840b8f03a5ff5413de5293bfcd8bf96467cf5452609f939ec6f5de16"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ash"
|
name = "ash"
|
||||||
version = "0.37.3+1.3.251"
|
version = "0.37.3+1.3.251"
|
||||||
|
@ -662,22 +651,6 @@ dependencies = [
|
||||||
"error-code",
|
"error-code",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cocoa"
|
|
||||||
version = "0.24.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f425db7937052c684daec3bd6375c8abe2d146dca4b8b143d6db777c39138f3a"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 1.3.2",
|
|
||||||
"block",
|
|
||||||
"cocoa-foundation",
|
|
||||||
"core-foundation",
|
|
||||||
"core-graphics 0.22.3",
|
|
||||||
"foreign-types 0.3.2",
|
|
||||||
"libc",
|
|
||||||
"objc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cocoa"
|
name = "cocoa"
|
||||||
version = "0.25.0"
|
version = "0.25.0"
|
||||||
|
@ -688,8 +661,8 @@ dependencies = [
|
||||||
"block",
|
"block",
|
||||||
"cocoa-foundation",
|
"cocoa-foundation",
|
||||||
"core-foundation",
|
"core-foundation",
|
||||||
"core-graphics 0.23.2",
|
"core-graphics",
|
||||||
"foreign-types 0.5.0",
|
"foreign-types",
|
||||||
"libc",
|
"libc",
|
||||||
"objc",
|
"objc",
|
||||||
]
|
]
|
||||||
|
@ -790,19 +763,6 @@ version = "0.8.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
|
checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "core-graphics"
|
|
||||||
version = "0.22.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 1.3.2",
|
|
||||||
"core-foundation",
|
|
||||||
"core-graphics-types",
|
|
||||||
"foreign-types 0.3.2",
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "core-graphics"
|
name = "core-graphics"
|
||||||
version = "0.23.2"
|
version = "0.23.2"
|
||||||
|
@ -812,7 +772,7 @@ dependencies = [
|
||||||
"bitflags 1.3.2",
|
"bitflags 1.3.2",
|
||||||
"core-foundation",
|
"core-foundation",
|
||||||
"core-graphics-types",
|
"core-graphics-types",
|
||||||
"foreign-types 0.5.0",
|
"foreign-types",
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -861,12 +821,6 @@ dependencies = [
|
||||||
"typenum",
|
"typenum",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cty"
|
|
||||||
version = "0.2.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cursor-icon"
|
name = "cursor-icon"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
@ -894,27 +848,6 @@ dependencies = [
|
||||||
"crypto-common",
|
"crypto-common",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "dirs-next"
|
|
||||||
version = "2.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"dirs-sys-next",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "dirs-sys-next"
|
|
||||||
version = "0.1.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"redox_users",
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dispatch"
|
name = "dispatch"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
|
@ -952,7 +885,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "20930a432bbd57a6d55e07976089708d4893f3d556cf42a0d79e9e321fa73b10"
|
checksum = "20930a432bbd57a6d55e07976089708d4893f3d556cf42a0d79e9e321fa73b10"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"serde",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -962,7 +894,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "020e2ccef6bbcec71dbc542f7eed64a5846fc3076727f5746da8fd307c91bab2"
|
checksum = "020e2ccef6bbcec71dbc542f7eed64a5846fc3076727f5746da8fd307c91bab2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"cocoa 0.25.0",
|
"cocoa",
|
||||||
"document-features",
|
"document-features",
|
||||||
"egui",
|
"egui",
|
||||||
"egui-wgpu",
|
"egui-wgpu",
|
||||||
|
@ -1000,7 +932,6 @@ dependencies = [
|
||||||
"epaint",
|
"epaint",
|
||||||
"log",
|
"log",
|
||||||
"nohash-hasher",
|
"nohash-hasher",
|
||||||
"serde",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1054,12 +985,6 @@ dependencies = [
|
||||||
"winit",
|
"winit",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "either"
|
|
||||||
version = "1.11.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "emath"
|
name = "emath"
|
||||||
version = "0.27.2"
|
version = "0.27.2"
|
||||||
|
@ -1067,7 +992,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e4c3a552cfca14630702449d35f41c84a0d15963273771c6059175a803620f3f"
|
checksum = "e4c3a552cfca14630702449d35f41c84a0d15963273771c6059175a803620f3f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"serde",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1091,17 +1015,6 @@ dependencies = [
|
||||||
"syn 2.0.60",
|
"syn 2.0.60",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "enumn"
|
|
||||||
version = "0.1.13"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6fd000fd6988e73bbe993ea3db9b1aa64906ab88766d654973924340c8cddb42"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 2.0.60",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "epaint"
|
name = "epaint"
|
||||||
version = "0.27.2"
|
version = "0.27.2"
|
||||||
|
@ -1116,7 +1029,6 @@ dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"nohash-hasher",
|
"nohash-hasher",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"serde",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1234,15 +1146,6 @@ dependencies = [
|
||||||
"miniz_oxide",
|
"miniz_oxide",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "foreign-types"
|
|
||||||
version = "0.3.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
|
||||||
dependencies = [
|
|
||||||
"foreign-types-shared 0.1.1",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "foreign-types"
|
name = "foreign-types"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
|
@ -1250,7 +1153,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965"
|
checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"foreign-types-macros",
|
"foreign-types-macros",
|
||||||
"foreign-types-shared 0.3.1",
|
"foreign-types-shared",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1264,12 +1167,6 @@ dependencies = [
|
||||||
"syn 2.0.60",
|
"syn 2.0.60",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "foreign-types-shared"
|
|
||||||
version = "0.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "foreign-types-shared"
|
name = "foreign-types-shared"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
|
@ -1640,12 +1537,6 @@ dependencies = [
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "itoa"
|
|
||||||
version = "1.0.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jni"
|
name = "jni"
|
||||||
version = "0.21.1"
|
version = "0.21.1"
|
||||||
|
@ -1740,16 +1631,6 @@ dependencies = [
|
||||||
"redox_syscall 0.4.1",
|
"redox_syscall 0.4.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "libredox"
|
|
||||||
version = "0.1.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 2.5.0",
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linux-raw-sys"
|
name = "linux-raw-sys"
|
||||||
version = "0.3.8"
|
version = "0.3.8"
|
||||||
|
@ -1835,7 +1716,7 @@ dependencies = [
|
||||||
"bitflags 2.5.0",
|
"bitflags 2.5.0",
|
||||||
"block",
|
"block",
|
||||||
"core-graphics-types",
|
"core-graphics-types",
|
||||||
"foreign-types 0.5.0",
|
"foreign-types",
|
||||||
"log",
|
"log",
|
||||||
"objc",
|
"objc",
|
||||||
"paste",
|
"paste",
|
||||||
|
@ -1871,27 +1752,6 @@ dependencies = [
|
||||||
"unicode-xid",
|
"unicode-xid",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "native-dialog"
|
|
||||||
version = "0.6.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1bbf55edb2747e4e4b3a9cd3989194b88aae32274b4422635dcf98aa6e84197b"
|
|
||||||
dependencies = [
|
|
||||||
"ascii",
|
|
||||||
"block",
|
|
||||||
"cocoa 0.24.1",
|
|
||||||
"dirs-next",
|
|
||||||
"objc",
|
|
||||||
"objc-foundation",
|
|
||||||
"objc_id",
|
|
||||||
"once_cell",
|
|
||||||
"raw-window-handle 0.4.3",
|
|
||||||
"thiserror",
|
|
||||||
"wfd",
|
|
||||||
"which",
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ndk"
|
name = "ndk"
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
|
@ -1981,17 +1841,6 @@ dependencies = [
|
||||||
"objc_exception",
|
"objc_exception",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "objc-foundation"
|
|
||||||
version = "0.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9"
|
|
||||||
dependencies = [
|
|
||||||
"block",
|
|
||||||
"objc",
|
|
||||||
"objc_id",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objc-sys"
|
name = "objc-sys"
|
||||||
version = "0.2.0-beta.2"
|
version = "0.2.0-beta.2"
|
||||||
|
@ -2098,15 +1947,6 @@ dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "objc_id"
|
|
||||||
version = "0.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b"
|
|
||||||
dependencies = [
|
|
||||||
"objc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.19.0"
|
version = "1.19.0"
|
||||||
|
@ -2119,7 +1959,7 @@ version = "0.3.47"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "52f0d54bde9774d3a51dcf281a5def240c71996bc6ca05d2c847ec8b2b216166"
|
checksum = "52f0d54bde9774d3a51dcf281a5def240c71996bc6ca05d2c847ec8b2b216166"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libredox 0.0.2",
|
"libredox",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2187,8 +2027,6 @@ name = "petri"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rand",
|
"rand",
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2358,15 +2196,6 @@ dependencies = [
|
||||||
"getrandom",
|
"getrandom",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "raw-window-handle"
|
|
||||||
version = "0.4.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b800beb9b6e7d2df1fe337c9e3d04e3af22a124460fb4c30fcc22c9117cefb41"
|
|
||||||
dependencies = [
|
|
||||||
"cty",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "raw-window-handle"
|
name = "raw-window-handle"
|
||||||
version = "0.5.2"
|
version = "0.5.2"
|
||||||
|
@ -2406,17 +2235,6 @@ dependencies = [
|
||||||
"bitflags 2.5.0",
|
"bitflags 2.5.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "redox_users"
|
|
||||||
version = "0.4.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891"
|
|
||||||
dependencies = [
|
|
||||||
"getrandom",
|
|
||||||
"libredox 0.1.3",
|
|
||||||
"thiserror",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.10.4"
|
version = "1.10.4"
|
||||||
|
@ -2485,12 +2303,6 @@ dependencies = [
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ryu"
|
|
||||||
version = "1.0.17"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "same-file"
|
name = "same-file"
|
||||||
version = "1.0.6"
|
version = "1.0.6"
|
||||||
|
@ -2527,35 +2339,24 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.200"
|
version = "1.0.199"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ddc6f9cc94d67c0e21aaf7eda3a010fd3af78ebf6e096aa6e2e13c79749cce4f"
|
checksum = "0c9f6e76df036c77cd94996771fb40db98187f096dd0b9af39c6c6e452ba966a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.200"
|
version = "1.0.199"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "856f046b9400cee3c8c94ed572ecdb752444c24528c035cd35882aad6f492bcb"
|
checksum = "11bd257a6541e141e42ca6d24ae26f7714887b47e89aa739099104c7e4d3b7fc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.60",
|
"syn 2.0.60",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "serde_json"
|
|
||||||
version = "1.0.116"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813"
|
|
||||||
dependencies = [
|
|
||||||
"itoa",
|
|
||||||
"ryu",
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_repr"
|
name = "serde_repr"
|
||||||
version = "0.1.19"
|
version = "0.1.19"
|
||||||
|
@ -2942,12 +2743,8 @@ name = "uscope"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"eframe",
|
"eframe",
|
||||||
"egui",
|
|
||||||
"native-dialog",
|
|
||||||
"petri",
|
"petri",
|
||||||
"rand",
|
"rand",
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -3190,16 +2987,6 @@ dependencies = [
|
||||||
"web-sys",
|
"web-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wfd"
|
|
||||||
version = "0.1.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e713040b67aae5bf1a0ae3e1ebba8cc29ab2b90da9aa1bff6e09031a8a41d7a8"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wgpu"
|
name = "wgpu"
|
||||||
version = "0.19.4"
|
version = "0.19.4"
|
||||||
|
@ -3302,18 +3089,6 @@ dependencies = [
|
||||||
"web-sys",
|
"web-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "which"
|
|
||||||
version = "4.4.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7"
|
|
||||||
dependencies = [
|
|
||||||
"either",
|
|
||||||
"home",
|
|
||||||
"once_cell",
|
|
||||||
"rustix 0.38.34",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "widestring"
|
name = "widestring"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
@ -3622,7 +3397,7 @@ dependencies = [
|
||||||
"calloop",
|
"calloop",
|
||||||
"cfg_aliases",
|
"cfg_aliases",
|
||||||
"core-foundation",
|
"core-foundation",
|
||||||
"core-graphics 0.23.2",
|
"core-graphics",
|
||||||
"cursor-icon",
|
"cursor-icon",
|
||||||
"icrate",
|
"icrate",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
|
|
|
@ -7,5 +7,3 @@ edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
serde = "1.0.200"
|
|
||||||
serde_json = "1.0.116"
|
|
||||||
|
|
161
petri/src/lib.rs
161
petri/src/lib.rs
|
@ -1,16 +1,14 @@
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
pub const CHUNK_SIZE: usize = 32;
|
pub const CHUNK_SIZE: usize = 32;
|
||||||
|
|
||||||
#[derive(Default, Debug, PartialEq, Clone, Copy, Serialize, Deserialize)]
|
#[derive(Default, Debug, PartialEq, Clone, Copy)]
|
||||||
pub struct Cell(pub u16);
|
pub struct Cell(pub u16);
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Dish {
|
pub struct Dish {
|
||||||
pub chunk: Chunk,
|
pub chunk: Chunk,
|
||||||
pub rules: Vec<Rule>,
|
pub rules: Vec<Rule>,
|
||||||
pub cell_groups: Vec<Vec<Option<Cell>>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -18,10 +16,9 @@ pub struct Chunk {
|
||||||
pub contents: Box<[[Cell; CHUNK_SIZE]; CHUNK_SIZE]>,
|
pub contents: Box<[[Cell; CHUNK_SIZE]; CHUNK_SIZE]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug)]
|
||||||
pub struct Rule {
|
pub struct Rule {
|
||||||
base: SubRule,
|
base: SubRule,
|
||||||
#[serde(skip)]
|
|
||||||
variants: Vec<SubRule>,
|
variants: Vec<SubRule>,
|
||||||
pub enabled: bool,
|
pub enabled: bool,
|
||||||
// probability: u8
|
// probability: u8
|
||||||
|
@ -30,35 +27,11 @@ pub struct Rule {
|
||||||
pub rotate: bool,
|
pub rotate: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
struct SubRule {
|
struct SubRule {
|
||||||
width: usize,
|
width: usize,
|
||||||
height: usize,
|
height: usize,
|
||||||
contents: Vec<(RuleCellFrom, RuleCellTo)>,
|
contents: Vec<(Option<Cell>, Option<Cell>)>,
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
|
|
||||||
pub enum RuleCellFrom {
|
|
||||||
/// matches anything
|
|
||||||
#[default]
|
|
||||||
Any,
|
|
||||||
/// matches one cell type
|
|
||||||
One(Cell),
|
|
||||||
/// matches anything defined in the group referenced by this index
|
|
||||||
Group(usize),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
|
|
||||||
pub enum RuleCellTo {
|
|
||||||
/// don't modify this cell
|
|
||||||
#[default]
|
|
||||||
None,
|
|
||||||
/// set to this cell
|
|
||||||
One(Cell),
|
|
||||||
/// randomly choose from the group
|
|
||||||
GroupRandom(usize),
|
|
||||||
/// copy the cell from the corresponding input position
|
|
||||||
Copy(usize),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SubRule {
|
impl SubRule {
|
||||||
|
@ -66,36 +39,36 @@ impl SubRule {
|
||||||
Self {
|
Self {
|
||||||
width: 1,
|
width: 1,
|
||||||
height: 1,
|
height: 1,
|
||||||
contents: vec![Default::default()],
|
contents: vec![(None, None)],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get(&self, x: usize, y: usize) -> (RuleCellFrom, RuleCellTo) {
|
fn get(&self, x: usize, y: usize) -> (Option<Cell>, Option<Cell>) {
|
||||||
if x >= self.width || y >= self.height {
|
if x >= self.width || y >= self.height {
|
||||||
Default::default()
|
(None, None)
|
||||||
} else {
|
} else {
|
||||||
self.contents[x + self.width * y].clone()
|
self.contents[x + self.width * y].clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_mut(&mut self, x: usize, y: usize) -> &mut (RuleCellFrom, RuleCellTo) {
|
fn get_mut(&mut self, x: usize, y: usize) -> &mut (Option<Cell>, Option<Cell>) {
|
||||||
assert!(x < self.width || y < self.height);
|
assert!(x < self.width || y < self.height);
|
||||||
&mut self.contents[x + self.width * y]
|
&mut self.contents[x + self.width * y]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_both(&mut self, x: usize, y: usize, cells: (RuleCellFrom, RuleCellTo)) {
|
fn set_both(&mut self, x: usize, y: usize, cells: (Option<Cell>, Option<Cell>)) {
|
||||||
if x < self.width && y < self.height {
|
if x < self.width && y < self.height {
|
||||||
self.contents[x + self.width * y] = cells;
|
self.contents[x + self.width * y] = cells;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_from(&mut self, x: usize, y: usize, cell: RuleCellFrom) {
|
fn set_from(&mut self, x: usize, y: usize, cell: Option<Cell>) {
|
||||||
if x < self.width && y < self.height {
|
if x < self.width && y < self.height {
|
||||||
self.contents[x + self.width * y].0 = cell;
|
self.contents[x + self.width * y].0 = cell;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_to(&mut self, x: usize, y: usize, cell: RuleCellTo) {
|
fn set_to(&mut self, x: usize, y: usize, cell: Option<Cell>) {
|
||||||
if x < self.width && y < self.height {
|
if x < self.width && y < self.height {
|
||||||
self.contents[x + self.width * y].1 = cell;
|
self.contents[x + self.width * y].1 = cell;
|
||||||
}
|
}
|
||||||
|
@ -124,20 +97,20 @@ impl Rule {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self, x: usize, y: usize) -> (RuleCellFrom, RuleCellTo) {
|
pub fn get(&self, x: usize, y: usize) -> (Option<Cell>, Option<Cell>) {
|
||||||
self.base.get(x, y)
|
self.base.get(x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_mut(&mut self, x: usize, y: usize) -> &mut (RuleCellFrom, RuleCellTo) {
|
pub fn get_mut(&mut self, x: usize, y: usize) -> &mut (Option<Cell>, Option<Cell>) {
|
||||||
self.base.get_mut(x, y)
|
self.base.get_mut(x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_from(&mut self, x: usize, y: usize, cell: RuleCellFrom) {
|
pub fn set_from(&mut self, x: usize, y: usize, cell: Option<Cell>) {
|
||||||
self.base.set_from(x, y, cell);
|
self.base.set_from(x, y, cell);
|
||||||
self.generate_variants();
|
self.generate_variants();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_to(&mut self, x: usize, y: usize, cell: RuleCellTo) {
|
pub fn set_to(&mut self, x: usize, y: usize, cell: Option<Cell>) {
|
||||||
self.base.set_to(x, y, cell);
|
self.base.set_to(x, y, cell);
|
||||||
self.generate_variants();
|
self.generate_variants();
|
||||||
}
|
}
|
||||||
|
@ -158,7 +131,7 @@ impl Rule {
|
||||||
if new_width < 1 || new_height < 1 {
|
if new_width < 1 || new_height < 1 {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let mut new_contents = vec![Default::default(); new_width * new_height];
|
let mut new_contents = vec![(None, None); new_width * new_height];
|
||||||
|
|
||||||
for nx in 0..new_width {
|
for nx in 0..new_width {
|
||||||
let oldx = nx.wrapping_add_signed(dx);
|
let oldx = nx.wrapping_add_signed(dx);
|
||||||
|
@ -281,8 +254,8 @@ impl Dish {
|
||||||
width: 1,
|
width: 1,
|
||||||
height: 2,
|
height: 2,
|
||||||
contents: vec![
|
contents: vec![
|
||||||
(RuleCellFrom::One(Cell(1)), RuleCellTo::One(Cell(0))),
|
(Some(Cell(1)), Some(Cell(0))),
|
||||||
(RuleCellFrom::One(Cell(0)), RuleCellTo::One(Cell(1))),
|
(Some(Cell(0)), Some(Cell(1))),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
..Rule::new()
|
..Rule::new()
|
||||||
|
@ -293,10 +266,10 @@ impl Dish {
|
||||||
width: 2,
|
width: 2,
|
||||||
height: 2,
|
height: 2,
|
||||||
contents: vec![
|
contents: vec![
|
||||||
(RuleCellFrom::One(Cell(1)), RuleCellTo::One(Cell(0))),
|
(Some(Cell(1)), Some(Cell(0))),
|
||||||
(RuleCellFrom::Any, RuleCellTo::None),
|
(None, None),
|
||||||
(RuleCellFrom::One(Cell(1)), RuleCellTo::None),
|
(Some(Cell(1)), None),
|
||||||
(RuleCellFrom::One(Cell(0)), RuleCellTo::One(Cell(1))),
|
(Some(Cell(0)), Some(Cell(1))),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
flip_h: true,
|
flip_h: true,
|
||||||
|
@ -311,13 +284,6 @@ impl Dish {
|
||||||
Self {
|
Self {
|
||||||
chunk: Chunk::new().fill_random(),
|
chunk: Chunk::new().fill_random(),
|
||||||
rules: default_rules,
|
rules: default_rules,
|
||||||
cell_groups: vec![vec![None, Some(Cell(1))]],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update_rules(&mut self) {
|
|
||||||
for rule in &mut self.rules {
|
|
||||||
rule.generate_variants();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -325,6 +291,8 @@ impl Dish {
|
||||||
if self.rules.is_empty() {
|
if self.rules.is_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
let x = random::<usize>() % CHUNK_SIZE;
|
||||||
|
let y = random::<usize>() % CHUNK_SIZE;
|
||||||
let enabled_rules = self
|
let enabled_rules = self
|
||||||
.rules
|
.rules
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -336,82 +304,47 @@ impl Dish {
|
||||||
}
|
}
|
||||||
let rule = random::<usize>() % enabled_rules.len();
|
let rule = random::<usize>() % enabled_rules.len();
|
||||||
let rule = enabled_rules[rule];
|
let rule = enabled_rules[rule];
|
||||||
self.fire_rule(rule);
|
self.fire_rule(rule, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fire_rule(&mut self, rule_index: usize) {
|
fn fire_rule(&mut self, rule_index: usize, x: usize, y: usize) {
|
||||||
let rule = &self.rules[rule_index];
|
let rule = &self.rules[rule_index];
|
||||||
let variant_index = random::<usize>() % rule.variants.len();
|
// find matching variants
|
||||||
let variant = &rule.variants[variant_index].clone();
|
let mut matching_variants = Vec::new();
|
||||||
let border_x = variant.width - 1;
|
for (i, v) in rule.variants.iter().enumerate() {
|
||||||
let border_y = variant.height - 1;
|
if self.subrule_matches(x, y, v) {
|
||||||
let x = ((random::<usize>() % (CHUNK_SIZE + border_x)) as isize)
|
matching_variants.push(i);
|
||||||
.wrapping_sub_unsigned(border_x);
|
}
|
||||||
let y = ((random::<usize>() % (CHUNK_SIZE + border_y)) as isize)
|
}
|
||||||
.wrapping_sub_unsigned(border_y);
|
if matching_variants.is_empty() {
|
||||||
|
|
||||||
if !self.subrule_matches(x, y, variant) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let variant_index = random::<usize>() % matching_variants.len();
|
||||||
|
let variant = rule.variants[matching_variants[variant_index]].clone();
|
||||||
|
|
||||||
let width = variant.width;
|
let width = variant.width;
|
||||||
let height = variant.height;
|
let height = variant.height;
|
||||||
let mut old_state = Vec::new();
|
|
||||||
for dy in 0..height {
|
|
||||||
for dx in 0..width {
|
|
||||||
old_state.push(
|
|
||||||
self.get_cell((x as usize).wrapping_add(dx), (y as usize).wrapping_add(dy)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for dx in 0..width {
|
for dx in 0..width {
|
||||||
for dy in 0..height {
|
for dy in 0..height {
|
||||||
let px = x.wrapping_add_unsigned(dx) as usize;
|
let x = x + dx;
|
||||||
let py = y.wrapping_add_unsigned(dy) as usize;
|
let y = y + dy;
|
||||||
match variant.get(dx, dy).1 {
|
if let Some(rule_cell) = variant.get(dx, dy).1 {
|
||||||
RuleCellTo::One(rule_cell) => {
|
self.set_cell(x, y, rule_cell.clone());
|
||||||
self.set_cell(px, py, rule_cell.clone());
|
|
||||||
}
|
|
||||||
RuleCellTo::GroupRandom(group_id) => {
|
|
||||||
let group = &self.cell_groups[group_id];
|
|
||||||
let i = random::<usize>() % group.len();
|
|
||||||
let cell = group[i];
|
|
||||||
if let Some(cell) = cell {
|
|
||||||
self.set_cell(px, py, cell);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RuleCellTo::Copy(index) => {
|
|
||||||
let cell = old_state[index];
|
|
||||||
if let Some(cell) = cell {
|
|
||||||
// if the copy source is outside the world, do nothing
|
|
||||||
self.set_cell(px, py, cell);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RuleCellTo::None => (),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn subrule_matches(&self, x: isize, y: isize, subrule: &SubRule) -> bool {
|
fn subrule_matches(&self, x: usize, y: usize, subrule: &SubRule) -> bool {
|
||||||
for dx in 0..subrule.width {
|
for dx in 0..subrule.width {
|
||||||
for dy in 0..subrule.height {
|
for dy in 0..subrule.height {
|
||||||
let x = x.wrapping_add_unsigned(dx) as usize;
|
let x = x + dx;
|
||||||
let y = y.wrapping_add_unsigned(dy) as usize;
|
let y = y + dy;
|
||||||
let cell = self.get_cell(x, y);
|
if let Some(rule_cell) = subrule.get(dx, dy).0 {
|
||||||
match subrule.get(dx, dy).0 {
|
if self.get_cell(x, y) != Some(rule_cell) {
|
||||||
RuleCellFrom::One(rule_cell) => {
|
return false;
|
||||||
if cell != Some(rule_cell) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
RuleCellFrom::Group(group_id) => {
|
|
||||||
if !self.cell_groups[group_id].contains(&cell) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RuleCellFrom::Any => (),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,9 +7,5 @@ edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
petri = { path = "../petri" }
|
petri = { path = "../petri" }
|
||||||
eframe = "0.27"
|
eframe = "0.27.2"
|
||||||
egui = { version = "*", features = ["serde"] }
|
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
serde = "1.0.200"
|
|
||||||
serde_json = "1.0.116"
|
|
||||||
native-dialog = "0.6.4"
|
|
||||||
|
|
|
@ -1,8 +1,3 @@
|
||||||
use std::{
|
|
||||||
fs::{self, File},
|
|
||||||
io::Write,
|
|
||||||
};
|
|
||||||
|
|
||||||
use eframe::{
|
use eframe::{
|
||||||
egui::{
|
egui::{
|
||||||
CentralPanel, Color32, Painter, Pos2, Rect, ScrollArea, Sense, SidePanel, Slider, Ui, Vec2,
|
CentralPanel, Color32, Painter, Pos2, Rect, ScrollArea, Sense, SidePanel, Slider, Ui, Vec2,
|
||||||
|
@ -10,17 +5,12 @@ use eframe::{
|
||||||
epaint::Hsva,
|
epaint::Hsva,
|
||||||
NativeOptions,
|
NativeOptions,
|
||||||
};
|
};
|
||||||
use egui::PointerButton;
|
use petri::{Cell, Chunk, Dish, Rule, CHUNK_SIZE};
|
||||||
use native_dialog::FileDialog;
|
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use petri::{Cell, Chunk, Dish, Rule, RuleCellFrom, RuleCellTo, CHUNK_SIZE};
|
|
||||||
use serde_json::{json, Value};
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
eframe::run_native(
|
eframe::run_native(
|
||||||
"µscope",
|
"V3 World Editor",
|
||||||
NativeOptions::default(),
|
NativeOptions::default(),
|
||||||
Box::new(|_cc| Box::new(UScope::new(_cc))),
|
Box::new(|_cc| Box::new(UScope::new(_cc))),
|
||||||
)
|
)
|
||||||
|
@ -33,10 +23,10 @@ struct UScope {
|
||||||
brush: Cell,
|
brush: Cell,
|
||||||
speed: usize,
|
speed: usize,
|
||||||
show_grid: bool,
|
show_grid: bool,
|
||||||
cell_types: Vec<CellData>,
|
celltypes: Vec<CellData>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug, Serialize, Deserialize)]
|
#[derive(Default, Debug)]
|
||||||
pub struct CellData {
|
pub struct CellData {
|
||||||
name: String,
|
name: String,
|
||||||
color: Color32,
|
color: Color32,
|
||||||
|
@ -46,52 +36,15 @@ impl UScope {
|
||||||
fn new(_cc: &eframe::CreationContext<'_>) -> Self {
|
fn new(_cc: &eframe::CreationContext<'_>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
dish: Dish::new(),
|
dish: Dish::new(),
|
||||||
speed: 500,
|
speed: 250,
|
||||||
show_grid: false,
|
show_grid: false,
|
||||||
brush: Cell(1),
|
brush: Cell(1),
|
||||||
cell_types: vec![
|
celltypes: vec![
|
||||||
CellData::new("air", 0, 0, 0),
|
CellData::new("air", 0, 0, 0),
|
||||||
CellData::new("pink_sand", 255, 147, 219),
|
CellData::new("pink_sand", 255, 147, 219),
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn save_universe(&self) -> Option<()> {
|
|
||||||
if let Ok(Some(path)) = FileDialog::new()
|
|
||||||
.set_filename("universe_1.json")
|
|
||||||
.add_filter("JSON", &["json"])
|
|
||||||
.show_save_single_file()
|
|
||||||
{
|
|
||||||
let out = json!({
|
|
||||||
"cell_types": self.cell_types,
|
|
||||||
"rules": self.dish.rules,
|
|
||||||
"groups": self.dish.cell_groups,
|
|
||||||
});
|
|
||||||
let out = serde_json::to_string(&out).ok()?;
|
|
||||||
let mut file = File::create(path).ok()?;
|
|
||||||
file.write_all(out.as_bytes()).ok()?;
|
|
||||||
}
|
|
||||||
Some(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn open_universe(&mut self) -> Option<()> {
|
|
||||||
if let Ok(Some(path)) = FileDialog::new()
|
|
||||||
.set_filename("universe_1.json")
|
|
||||||
.add_filter("JSON", &["json"])
|
|
||||||
.show_open_single_file()
|
|
||||||
{
|
|
||||||
let s = fs::read_to_string(path).ok()?;
|
|
||||||
let data: Value = serde_json::from_str(&s).ok()?;
|
|
||||||
let cell_types = serde_json::from_value(data["cell_types"].clone()).ok()?;
|
|
||||||
let groups = serde_json::from_value(data["groups"].clone()).ok()?;
|
|
||||||
let rules = serde_json::from_value(data["rules"].clone()).ok()?;
|
|
||||||
self.cell_types = cell_types;
|
|
||||||
self.dish.rules = rules;
|
|
||||||
self.dish.cell_groups = groups;
|
|
||||||
self.dish.update_rules();
|
|
||||||
}
|
|
||||||
Some(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl eframe::App for UScope {
|
impl eframe::App for UScope {
|
||||||
|
@ -105,18 +58,13 @@ impl eframe::App for UScope {
|
||||||
ui.label("speed");
|
ui.label("speed");
|
||||||
ui.add(Slider::new(&mut self.speed, 0..=5000));
|
ui.add(Slider::new(&mut self.speed, 0..=5000));
|
||||||
ui.checkbox(&mut self.show_grid, "show grid");
|
ui.checkbox(&mut self.show_grid, "show grid");
|
||||||
ui.horizontal(|ui| {
|
if ui.button("fill").clicked() {
|
||||||
if ui.button("Save").clicked() {
|
self.dish.chunk.contents.fill([self.brush; CHUNK_SIZE]);
|
||||||
self.save_universe();
|
}
|
||||||
}
|
|
||||||
if ui.button("Open").clicked() {
|
|
||||||
self.open_universe();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
ui.separator();
|
ui.separator();
|
||||||
|
|
||||||
ui.heading("Cells");
|
ui.heading("Cells");
|
||||||
for (i, cell) in self.cell_types.iter_mut().enumerate() {
|
for (i, cell) in self.celltypes.iter_mut().enumerate() {
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.set_width(120.);
|
ui.set_width(120.);
|
||||||
ui.radio_value(&mut self.brush.0, i as u16, "");
|
ui.radio_value(&mut self.brush.0, i as u16, "");
|
||||||
|
@ -130,49 +78,17 @@ impl eframe::App for UScope {
|
||||||
let s = random::<f32>() * 0.5 + 0.5;
|
let s = random::<f32>() * 0.5 + 0.5;
|
||||||
let v = random::<f32>() * 0.5 + 0.5;
|
let v = random::<f32>() * 0.5 + 0.5;
|
||||||
let color = Hsva::new(h, s, v, 1.).into();
|
let color = Hsva::new(h, s, v, 1.).into();
|
||||||
let name = format!("cell #{}", self.cell_types.len());
|
let name = format!("cell #{}", self.celltypes.len());
|
||||||
self.cell_types.push(CellData { name, color })
|
self.celltypes.push(CellData { name, color })
|
||||||
}
|
|
||||||
if ui.button("fill").clicked() {
|
|
||||||
self.dish.chunk.contents.fill([self.brush; CHUNK_SIZE]);
|
|
||||||
}
|
}
|
||||||
ui.separator();
|
ui.separator();
|
||||||
|
|
||||||
ui.heading("Groups");
|
|
||||||
for group in &mut self.dish.cell_groups {
|
|
||||||
let (rect, _response) = ui.allocate_exact_size(Vec2::splat(CSIZE), Sense::click());
|
|
||||||
draw_group(ui, rect, group, &self.cell_types);
|
|
||||||
ui.menu_button("edit", |ui| {
|
|
||||||
let mut void = group.contains(&None);
|
|
||||||
if ui.checkbox(&mut void, "void").changed() {
|
|
||||||
if void {
|
|
||||||
group.push(None);
|
|
||||||
} else {
|
|
||||||
group.retain(|c| c.is_some());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (i, celldata) in self.cell_types.iter().enumerate() {
|
|
||||||
let mut included = group.contains(&Some(Cell(i as u16)));
|
|
||||||
if ui.checkbox(&mut included, &celldata.name).changed() {
|
|
||||||
if included {
|
|
||||||
group.push(Some(Cell(i as u16)));
|
|
||||||
} else {
|
|
||||||
group.retain(|c| c != &Some(Cell(i as u16)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if ui.button("add group").clicked() {
|
|
||||||
self.dish.cell_groups.push(Vec::new());
|
|
||||||
}
|
|
||||||
|
|
||||||
ui.heading("Rules");
|
ui.heading("Rules");
|
||||||
ScrollArea::vertical().show(ui, |ui| {
|
ScrollArea::vertical().show(ui, |ui| {
|
||||||
let mut to_remove = None;
|
let mut to_remove = None;
|
||||||
for (i, rule) in self.dish.rules.iter_mut().enumerate() {
|
for (i, rule) in self.dish.rules.iter_mut().enumerate() {
|
||||||
ui.separator();
|
ui.separator();
|
||||||
rule_editor(ui, rule, &self.cell_types, &self.dish.cell_groups);
|
rule_editor(ui, rule, &self.celltypes);
|
||||||
if ui.button("delete").clicked() {
|
if ui.button("delete").clicked() {
|
||||||
to_remove = Some(i);
|
to_remove = Some(i);
|
||||||
}
|
}
|
||||||
|
@ -189,7 +105,7 @@ impl eframe::App for UScope {
|
||||||
CentralPanel::default().show(ctx, |ui| {
|
CentralPanel::default().show(ctx, |ui| {
|
||||||
let bounds = ui.available_rect_before_wrap();
|
let bounds = ui.available_rect_before_wrap();
|
||||||
let painter = ui.painter_at(bounds);
|
let painter = ui.painter_at(bounds);
|
||||||
paint_chunk(painter, &self.dish.chunk, &self.cell_types, self.show_grid);
|
paint_chunk(painter, &self.dish.chunk, &self.celltypes, self.show_grid);
|
||||||
|
|
||||||
let rect = ui.allocate_rect(bounds, Sense::click_and_drag());
|
let rect = ui.allocate_rect(bounds, Sense::click_and_drag());
|
||||||
if let Some(pos) = rect.interact_pointer_pos() {
|
if let Some(pos) = rect.interact_pointer_pos() {
|
||||||
|
@ -221,10 +137,8 @@ fn paint_chunk(painter: Painter, chunk: &Chunk, cells: &[CellData], grid: bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
const CSIZE: f32 = 24.;
|
const CSIZE: f32 = 24.;
|
||||||
const RESIZE_BUTTON_WIDTH: f32 = 8.;
|
|
||||||
|
|
||||||
const OUTLINE: (f32, Color32) = (2., Color32::GRAY);
|
const OUTLINE: (f32, Color32) = (2., Color32::GRAY);
|
||||||
fn rule_editor(ui: &mut Ui, rule: &mut Rule, cells: &[CellData], groups: &[Vec<Option<Cell>>]) {
|
fn rule_editor(ui: &mut Ui, rule: &mut Rule, cells: &[CellData]) {
|
||||||
ui.checkbox(&mut rule.enabled, "enable rule");
|
ui.checkbox(&mut rule.enabled, "enable rule");
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.label("flip");
|
ui.label("flip");
|
||||||
|
@ -241,41 +155,29 @@ fn rule_editor(ui: &mut Ui, rule: &mut Rule, cells: &[CellData], groups: &[Vec<O
|
||||||
|
|
||||||
let cells_y = rule.height();
|
let cells_y = rule.height();
|
||||||
let cells_x = rule.width();
|
let cells_x = rule.width();
|
||||||
|
let margin = 8.;
|
||||||
let patt_width = CSIZE * cells_x as f32;
|
let patt_width = CSIZE * cells_x as f32;
|
||||||
let patt_height = CSIZE * cells_y as f32;
|
let patt_height = CSIZE * cells_y as f32;
|
||||||
|
|
||||||
let (_, bounds) = ui.allocate_space(Vec2::new(
|
let (_, bounds) = ui.allocate_space(Vec2::new(
|
||||||
patt_width * 2. + RESIZE_BUTTON_WIDTH * 4. + CSIZE,
|
patt_width * 2. + margin * 4. + CSIZE,
|
||||||
patt_height + RESIZE_BUTTON_WIDTH * 2.,
|
patt_height + margin * 2.,
|
||||||
));
|
));
|
||||||
|
|
||||||
let from_cells_rect = Rect::from_min_size(
|
let from_cells_rect = Rect::from_min_size(
|
||||||
bounds.min + Vec2::splat(RESIZE_BUTTON_WIDTH),
|
bounds.min + Vec2::splat(margin),
|
||||||
Vec2::new(patt_width, patt_height),
|
Vec2::new(patt_width, patt_height),
|
||||||
);
|
);
|
||||||
let to_cells_rect = Rect::from_min_size(
|
let to_cells_rect = Rect::from_min_size(
|
||||||
bounds.min
|
bounds.min + Vec2::splat(margin) + Vec2::X * (patt_width + margin * 2. + CSIZE),
|
||||||
+ Vec2::splat(RESIZE_BUTTON_WIDTH)
|
|
||||||
+ Vec2::X * (patt_width + RESIZE_BUTTON_WIDTH * 2. + CSIZE),
|
|
||||||
Vec2::new(patt_width, patt_height),
|
Vec2::new(patt_width, patt_height),
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut overlay_lines = Vec::new();
|
|
||||||
for x in 0..cells_x {
|
for x in 0..cells_x {
|
||||||
for y in 0..cells_y {
|
for y in 0..cells_y {
|
||||||
let (left, right) = rule.get_mut(x, y);
|
let (left, right) = rule.get_mut(x, y);
|
||||||
let changed_left =
|
let changed_left = rule_cell_edit(ui, from_cells_rect.min, left, x, y, cells);
|
||||||
rule_cell_edit_from(ui, from_cells_rect.min, left, x, y, cells, groups);
|
let changed_right = rule_cell_edit(ui, to_cells_rect.min, right, x, y, cells);
|
||||||
let changed_right = rule_cell_edit_to(
|
|
||||||
ui,
|
|
||||||
to_cells_rect.min,
|
|
||||||
right,
|
|
||||||
(x, y),
|
|
||||||
cells,
|
|
||||||
groups,
|
|
||||||
(cells_x, cells_y),
|
|
||||||
&mut overlay_lines,
|
|
||||||
);
|
|
||||||
if changed_left || changed_right {
|
if changed_left || changed_right {
|
||||||
rule.generate_variants();
|
rule.generate_variants();
|
||||||
}
|
}
|
||||||
|
@ -304,12 +206,7 @@ fn rule_editor(ui: &mut Ui, rule: &mut Rule, cells: &[CellData], groups: &[Vec<O
|
||||||
|
|
||||||
result.clicked()
|
result.clicked()
|
||||||
};
|
};
|
||||||
if resize_box(
|
if resize_box(bounds.min.x, bounds.min.y + margin, margin, patt_height) {
|
||||||
bounds.min.x,
|
|
||||||
bounds.min.y + RESIZE_BUTTON_WIDTH,
|
|
||||||
RESIZE_BUTTON_WIDTH,
|
|
||||||
patt_height,
|
|
||||||
) {
|
|
||||||
if delete_mode {
|
if delete_mode {
|
||||||
rule.resize(Rule::SHRINK_LEFT);
|
rule.resize(Rule::SHRINK_LEFT);
|
||||||
} else {
|
} else {
|
||||||
|
@ -318,8 +215,8 @@ fn rule_editor(ui: &mut Ui, rule: &mut Rule, cells: &[CellData], groups: &[Vec<O
|
||||||
}
|
}
|
||||||
if resize_box(
|
if resize_box(
|
||||||
from_cells_rect.max.x,
|
from_cells_rect.max.x,
|
||||||
bounds.min.y + RESIZE_BUTTON_WIDTH,
|
bounds.min.y + margin,
|
||||||
RESIZE_BUTTON_WIDTH,
|
margin,
|
||||||
patt_height,
|
patt_height,
|
||||||
) {
|
) {
|
||||||
if delete_mode {
|
if delete_mode {
|
||||||
|
@ -328,12 +225,7 @@ fn rule_editor(ui: &mut Ui, rule: &mut Rule, cells: &[CellData], groups: &[Vec<O
|
||||||
rule.resize(Rule::EXTEND_RIGHT);
|
rule.resize(Rule::EXTEND_RIGHT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if resize_box(
|
if resize_box(bounds.min.x + margin, bounds.min.y, patt_width, margin) {
|
||||||
bounds.min.x + RESIZE_BUTTON_WIDTH,
|
|
||||||
bounds.min.y,
|
|
||||||
patt_width,
|
|
||||||
RESIZE_BUTTON_WIDTH,
|
|
||||||
) {
|
|
||||||
if delete_mode {
|
if delete_mode {
|
||||||
rule.resize(Rule::SHRINK_UP);
|
rule.resize(Rule::SHRINK_UP);
|
||||||
} else {
|
} else {
|
||||||
|
@ -341,10 +233,10 @@ fn rule_editor(ui: &mut Ui, rule: &mut Rule, cells: &[CellData], groups: &[Vec<O
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if resize_box(
|
if resize_box(
|
||||||
bounds.min.x + RESIZE_BUTTON_WIDTH,
|
bounds.min.x + margin,
|
||||||
bounds.max.y - RESIZE_BUTTON_WIDTH,
|
bounds.max.y - margin,
|
||||||
patt_width,
|
patt_width,
|
||||||
RESIZE_BUTTON_WIDTH,
|
margin,
|
||||||
) {
|
) {
|
||||||
if delete_mode {
|
if delete_mode {
|
||||||
rule.resize(Rule::SHRINK_DOWN);
|
rule.resize(Rule::SHRINK_DOWN);
|
||||||
|
@ -352,20 +244,15 @@ fn rule_editor(ui: &mut Ui, rule: &mut Rule, cells: &[CellData], groups: &[Vec<O
|
||||||
rule.resize(Rule::EXTEND_DOWN);
|
rule.resize(Rule::EXTEND_DOWN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (a, b) in overlay_lines {
|
|
||||||
ui.painter().line_segment([a, b], (2., Color32::WHITE));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rule_cell_edit_from(
|
fn rule_cell_edit(
|
||||||
ui: &mut Ui,
|
ui: &mut Ui,
|
||||||
origin: Pos2,
|
origin: Pos2,
|
||||||
rule: &mut RuleCellFrom,
|
rule: &mut Option<Cell>,
|
||||||
x: usize,
|
x: usize,
|
||||||
y: usize,
|
y: usize,
|
||||||
cells: &[CellData],
|
cells: &[CellData],
|
||||||
groups: &[Vec<Option<Cell>>],
|
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let mut changed = false;
|
let mut changed = false;
|
||||||
let rect = Rect::from_min_size(
|
let rect = Rect::from_min_size(
|
||||||
|
@ -373,150 +260,22 @@ fn rule_cell_edit_from(
|
||||||
Vec2::splat(CSIZE),
|
Vec2::splat(CSIZE),
|
||||||
);
|
);
|
||||||
let aabb = ui.allocate_rect(rect, Sense::click());
|
let aabb = ui.allocate_rect(rect, Sense::click());
|
||||||
let cycle_colors = aabb.clicked_by(PointerButton::Primary);
|
if let Some(cell) = rule {
|
||||||
let switch_type = aabb.clicked_by(PointerButton::Secondary);
|
|
||||||
|
|
||||||
// draw
|
|
||||||
match rule {
|
|
||||||
RuleCellFrom::Any => (),
|
|
||||||
RuleCellFrom::One(cell) => {
|
|
||||||
let color = cells[cell.id()].color;
|
|
||||||
ui.painter()
|
|
||||||
.rect(rect.shrink(OUTLINE.0 / 2.), 0., color, OUTLINE);
|
|
||||||
}
|
|
||||||
RuleCellFrom::Group(group_id) => {
|
|
||||||
let group = &groups[*group_id];
|
|
||||||
draw_group(ui, rect, group, cells);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// update
|
|
||||||
if cycle_colors {
|
|
||||||
match rule {
|
|
||||||
RuleCellFrom::Any => (),
|
|
||||||
RuleCellFrom::One(cell) => {
|
|
||||||
cell.0 += 1;
|
|
||||||
cell.0 %= cells.len() as u16;
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
RuleCellFrom::Group(group_id) => {
|
|
||||||
*group_id += 1;
|
|
||||||
*group_id %= groups.len();
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if switch_type {
|
|
||||||
changed = true;
|
|
||||||
match rule {
|
|
||||||
RuleCellFrom::Any => {
|
|
||||||
*rule = RuleCellFrom::One(Cell(0));
|
|
||||||
}
|
|
||||||
RuleCellFrom::One(_) => {
|
|
||||||
*rule = RuleCellFrom::Group(0);
|
|
||||||
}
|
|
||||||
RuleCellFrom::Group(_) => {
|
|
||||||
*rule = RuleCellFrom::Any;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
changed
|
|
||||||
}
|
|
||||||
|
|
||||||
fn rule_cell_edit_to(
|
|
||||||
ui: &mut Ui,
|
|
||||||
origin: Pos2,
|
|
||||||
rule: &mut RuleCellTo,
|
|
||||||
(x, y): (usize, usize),
|
|
||||||
cells: &[CellData],
|
|
||||||
groups: &[Vec<Option<Cell>>],
|
|
||||||
(rule_width, rule_height): (usize, usize),
|
|
||||||
overlay_lines: &mut Vec<(Pos2, Pos2)>,
|
|
||||||
) -> bool {
|
|
||||||
let mut changed = false;
|
|
||||||
let rect = Rect::from_min_size(
|
|
||||||
origin + Vec2::from((x as f32, y as f32)) * CSIZE,
|
|
||||||
Vec2::splat(CSIZE),
|
|
||||||
);
|
|
||||||
let aabb = ui.allocate_rect(rect, Sense::click());
|
|
||||||
let cycle_colors = aabb.clicked_by(PointerButton::Primary);
|
|
||||||
let switch_type = aabb.clicked_by(PointerButton::Secondary);
|
|
||||||
|
|
||||||
// draw
|
|
||||||
match rule {
|
|
||||||
RuleCellTo::None => (),
|
|
||||||
RuleCellTo::One(cell) => {
|
|
||||||
let color = cells[cell.id()].color;
|
|
||||||
ui.painter()
|
|
||||||
.rect(rect.shrink(OUTLINE.0 / 2.), 0., color, OUTLINE);
|
|
||||||
}
|
|
||||||
RuleCellTo::GroupRandom(group_id) => {
|
|
||||||
let group = &groups[*group_id];
|
|
||||||
draw_group(ui, rect, group, cells);
|
|
||||||
}
|
|
||||||
RuleCellTo::Copy(index) => {
|
|
||||||
let this = rect.center();
|
|
||||||
let x = *index % rule_width;
|
|
||||||
let y = *index / rule_width;
|
|
||||||
let target = origin + Vec2::from((x as f32, y as f32)) * CSIZE
|
|
||||||
- Vec2::X * (CSIZE * (rule_width as f32 + 1.) + RESIZE_BUTTON_WIDTH * 2.)
|
|
||||||
+ Vec2::splat(CSIZE) * 0.5;
|
|
||||||
overlay_lines.push((this, target));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if cycle_colors {
|
|
||||||
match rule {
|
|
||||||
RuleCellTo::None => (),
|
|
||||||
RuleCellTo::One(cell) => {
|
|
||||||
cell.0 += 1;
|
|
||||||
cell.0 %= cells.len() as u16;
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
RuleCellTo::GroupRandom(group_id) => {
|
|
||||||
*group_id += 1;
|
|
||||||
*group_id %= groups.len();
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
RuleCellTo::Copy(index) => {
|
|
||||||
*index = (*index + 1) % (rule_width * rule_height);
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if switch_type {
|
|
||||||
changed = true;
|
|
||||||
match rule {
|
|
||||||
RuleCellTo::None => {
|
|
||||||
*rule = RuleCellTo::One(Cell(0));
|
|
||||||
}
|
|
||||||
RuleCellTo::One(_) => {
|
|
||||||
*rule = RuleCellTo::GroupRandom(0);
|
|
||||||
}
|
|
||||||
RuleCellTo::GroupRandom(_) => {
|
|
||||||
*rule = RuleCellTo::Copy(0);
|
|
||||||
}
|
|
||||||
RuleCellTo::Copy(_) => {
|
|
||||||
*rule = RuleCellTo::None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
changed
|
|
||||||
}
|
|
||||||
|
|
||||||
fn draw_group(ui: &mut Ui, rect: Rect, group: &[Option<Cell>], cells: &[CellData]) {
|
|
||||||
let group_size = group.len();
|
|
||||||
let radius_per_color = (CSIZE * 0.7) / (group_size as f32);
|
|
||||||
for (i, cell) in group.iter().flatten().enumerate() {
|
|
||||||
let color = cells[cell.id()].color;
|
let color = cells[cell.id()].color;
|
||||||
let radius = radius_per_color * ((group_size - i) as f32);
|
ui.painter()
|
||||||
ui.painter_at(rect)
|
.rect(rect.shrink(OUTLINE.0 / 2.), 0., color, OUTLINE);
|
||||||
.circle_filled(rect.center(), radius, color);
|
if aabb.clicked() {
|
||||||
}
|
changed = true;
|
||||||
if group.contains(&None) {
|
cell.0 += 1;
|
||||||
ui.painter_at(rect)
|
if cell.0 as usize == cells.len() {
|
||||||
.line_segment([rect.min, rect.max], (1., Color32::WHITE));
|
*rule = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if aabb.clicked() {
|
||||||
|
*rule = Some(Cell(0));
|
||||||
|
changed = true;
|
||||||
}
|
}
|
||||||
|
changed
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CellData {
|
impl CellData {
|
||||||
|
|
Loading…
Reference in a new issue