diff --git a/.github/workflows/website.yml b/.github/workflows/website.yml
index 0451d4226e..93bda7e01d 100644
--- a/.github/workflows/website.yml
+++ b/.github/workflows/website.yml
@@ -9,6 +9,7 @@ on:
pull_request:
paths:
- website/**
+ workflow_dispatch: {}
env:
CARGO_TERM_COLOR: always
INDEX_HTML_HEAD_INCLUSION:
@@ -80,8 +81,32 @@ jobs:
- name: 🚚 Move `website/other/dist` contents to `website/public`
run: |
+ mkdir -p website/public
mv website/other/dist/* website/public
+ - name: 💿 Obtain cache of auto-generated code docs artifacts
+ id: cache-website-code-docs
+ uses: actions/cache/restore@v3
+ with:
+ path: artifacts
+ key: website-code-docs
+
+ - name: 📁 Fallback in case auto-generated code docs artifacts weren't cached
+ if: steps.cache-website-code-docs.outputs.cache-hit != 'true'
+ run: |
+ echo "🦀 Initial system version of Rust:"
+ rustc --version
+ rustup update stable
+ echo "🦀 Latest updated version of Rust:"
+ rustc --version
+ cargo test --package graphite-editor --lib -- messages::message::test::generate_message_tree
+ mkdir artifacts
+ mv hierarchical_message_system_tree.txt artifacts/hierarchical_message_system_tree.txt
+
+ - name: 🚚 Move `artifacts` contents to `website/public`
+ run: |
+ mv artifacts/* website/public
+
- name: 📤 Publish to Cloudflare Pages
id: cloudflare
uses: cloudflare/pages-action@1
diff --git a/.gitignore b/.gitignore
index 5700f4e89b..bdfa416126 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,3 +6,4 @@ profile.json
flamegraph.svg
.idea/
.direnv
+hierarchical_message_system_tree.txt
diff --git a/Cargo.lock b/Cargo.lock
index da16bddb21..5487e27d28 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1,6 +1,6 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
-version = 4
+version = 3
[[package]]
name = "Inflector"
@@ -10,9 +10,9 @@ checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3"
[[package]]
name = "ab_glyph"
-version = "0.2.29"
+version = "0.2.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec3672c180e71eeaaac3a541fbbc5f5ad4def8b747c595ad30d674e43049f7b0"
+checksum = "1e0f4f6fbdc5ee39f2ede9f5f3ec79477271a6d6a2baff22310d51736bda6cea"
dependencies = [
"ab_glyph_rasterizer",
"owned_ttf_parser",
@@ -20,9 +20,9 @@ dependencies = [
[[package]]
name = "ab_glyph_rasterizer"
-version = "0.1.8"
+version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046"
+checksum = "b2187590a23ab1e3df8681afdf0987c48504d80291f002fcdb651f0ef5e25169"
[[package]]
name = "addr2line"
@@ -35,21 +35,21 @@ dependencies = [
[[package]]
name = "adler2"
-version = "2.0.0"
+version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
+checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
[[package]]
name = "ahash"
-version = "0.8.11"
+version = "0.8.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
+checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75"
dependencies = [
"cfg-if",
- "getrandom 0.2.15",
+ "getrandom 0.3.3",
"once_cell",
"version_check",
- "zerocopy 0.7.35",
+ "zerocopy",
]
[[package]]
@@ -63,9 +63,12 @@ dependencies = [
[[package]]
name = "aligned-vec"
-version = "0.5.0"
+version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4aa90d7ce82d4be67b64039a3d588d38dbcc6736577de4a847025ce5b0c468d1"
+checksum = "dc890384c8602f339876ded803c97ad529f3842aba97f6392b3dba0dd171769b"
+dependencies = [
+ "equator",
+]
[[package]]
name = "alloc-no-stdlib"
@@ -95,7 +98,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee91c0c2905bae44f84bfa4e044536541df26b7703fd0888deeb9060fcc44289"
dependencies = [
"android-properties",
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
"cc",
"cesu8",
"jni",
@@ -138,9 +141,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
[[package]]
name = "anstream"
-version = "0.6.18"
+version = "0.6.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
+checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933"
dependencies = [
"anstyle",
"anstyle-parse",
@@ -153,44 +156,44 @@ dependencies = [
[[package]]
name = "anstyle"
-version = "1.0.10"
+version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
+checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd"
[[package]]
name = "anstyle-parse"
-version = "0.2.6"
+version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
+checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
-version = "1.1.2"
+version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
+checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9"
dependencies = [
"windows-sys 0.59.0",
]
[[package]]
name = "anstyle-wincon"
-version = "3.0.7"
+version = "3.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e"
+checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882"
dependencies = [
"anstyle",
- "once_cell",
+ "once_cell_polyfill",
"windows-sys 0.59.0",
]
[[package]]
name = "anyhow"
-version = "1.0.97"
+version = "1.0.98"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f"
+checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
[[package]]
name = "arbitrary"
@@ -206,7 +209,7 @@ checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.99",
+ "syn 2.0.104",
]
[[package]]
@@ -233,7 +236,7 @@ version = "0.38.0+1.3.281"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bb44936d800fea8f016d7f2311c6a4f97aebd5dc86f09906139ec848cf3a46f"
dependencies = [
- "libloading 0.8.6",
+ "libloading 0.8.8",
]
[[package]]
@@ -267,15 +270,15 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
[[package]]
name = "autocfg"
-version = "1.4.0"
+version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
+checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
[[package]]
name = "av1-grain"
-version = "0.2.3"
+version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6678909d8c5d46a42abcf571271e15fdbc0a225e3646cf23762cd415046c78bf"
+checksum = "4f3efb2ca85bc610acfa917b5aaa36f3fcbebed5b3182d7f877b02531c4b80c8"
dependencies = [
"anyhow",
"arrayvec",
@@ -287,18 +290,18 @@ dependencies = [
[[package]]
name = "avif-serialize"
-version = "0.8.3"
+version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "98922d6a4cfbcb08820c69d8eeccc05bb1f29bfa06b4f5b1dbfe9a868bd7608e"
+checksum = "19135c0c7a60bfee564dbe44ab5ce0557c6bf3884e5291a50be76a15640c4fbd"
dependencies = [
"arrayvec",
]
[[package]]
name = "axum"
-version = "0.8.1"
+version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6d6fd624c75e18b3b4c6b9caf42b1afe24437daaee904069137d8bab077be8b8"
+checksum = "021e862c184ae977658b36c4500f7feac3221ca5da43e3f25bd04ab6c79a29b5"
dependencies = [
"axum-core",
"bytes",
@@ -309,7 +312,7 @@ dependencies = [
"http-body-util",
"hyper",
"hyper-util",
- "itoa 1.0.15",
+ "itoa",
"matchit",
"memchr",
"mime",
@@ -330,12 +333,12 @@ dependencies = [
[[package]]
name = "axum-core"
-version = "0.5.0"
+version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "df1362f362fd16024ae199c1970ce98f9661bf5ef94b9808fee734bc3698b733"
+checksum = "68464cd0412f486726fb3373129ef5d2993f90c34bc2bc1c1e9943b2f4fc7ca6"
dependencies = [
"bytes",
- "futures-util",
+ "futures-core",
"http",
"http-body",
"http-body-util",
@@ -350,9 +353,9 @@ dependencies = [
[[package]]
name = "backtrace"
-version = "0.3.74"
+version = "0.3.75"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a"
+checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002"
dependencies = [
"addr2line",
"cfg-if",
@@ -434,9 +437,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
-version = "2.9.0"
+version = "2.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
+checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
dependencies = [
"serde",
]
@@ -501,9 +504,9 @@ dependencies = [
[[package]]
name = "brotli"
-version = "7.0.0"
+version = "8.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cc97b8f16f944bba54f0433f07e30be199b6dc2bd25937444bbad560bcea29bd"
+checksum = "9991eea70ea4f293524138648e41ee89b0b2b12ddef3b255effa43c8056e0e0d"
dependencies = [
"alloc-no-stdlib",
"alloc-stdlib",
@@ -512,9 +515,9 @@ dependencies = [
[[package]]
name = "brotli-decompressor"
-version = "4.0.2"
+version = "5.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74fa05ad7d803d413eb8380983b092cbbaf9a85f151b871360e7b00cd7060b37"
+checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03"
dependencies = [
"alloc-no-stdlib",
"alloc-stdlib",
@@ -528,9 +531,9 @@ checksum = "56ed6191a7e78c36abdb16ab65341eefd73d64d303fffccdbb00d51e4205967b"
[[package]]
name = "bumpalo"
-version = "3.17.0"
+version = "3.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
+checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
[[package]]
name = "bytemuck"
@@ -543,13 +546,13 @@ dependencies = [
[[package]]
name = "bytemuck_derive"
-version = "1.8.1"
+version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3fa76293b4f7bb636ab88fd78228235b5248b4d05cc589aed610f954af5d7c7a"
+checksum = "7ecc273b49b3205b83d648f0690daa588925572cc5063745bfe547fe7ec8e1a1"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.99",
+ "syn 2.0.104",
]
[[package]]
@@ -579,7 +582,7 @@ version = "0.18.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2"
dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
"cairo-sys-rs",
"glib",
"libc",
@@ -604,7 +607,7 @@ version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fba7adb4dd5aa98e5553510223000e7148f621165ec5f9acd7113f6ca4995298"
dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
"log",
"polling",
"rustix 0.38.44",
@@ -626,9 +629,9 @@ dependencies = [
[[package]]
name = "camino"
-version = "1.1.9"
+version = "1.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3"
+checksum = "0da45bc31171d8d6960122e222a67740df867c1dd53b4d51caa297084c185cab"
dependencies = [
"serde",
]
@@ -674,9 +677,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
[[package]]
name = "cc"
-version = "1.2.16"
+version = "1.2.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c"
+checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc"
dependencies = [
"jobserver",
"libc",
@@ -712,9 +715,9 @@ dependencies = [
[[package]]
name = "cfg-if"
-version = "1.0.0"
+version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268"
[[package]]
name = "cfg_aliases"
@@ -730,9 +733,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
[[package]]
name = "chrono"
-version = "0.4.40"
+version = "0.4.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c"
+checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d"
dependencies = [
"android-tzdata",
"iana-time-zone",
@@ -772,9 +775,9 @@ dependencies = [
[[package]]
name = "clap"
-version = "4.5.31"
+version = "4.5.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "027bb0d98429ae334a8698531da7077bdf906419543a35a55c2cb1b66437d767"
+checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f"
dependencies = [
"clap_builder",
"clap_derive",
@@ -782,9 +785,9 @@ dependencies = [
[[package]]
name = "clap_builder"
-version = "4.5.31"
+version = "4.5.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5589e0cba072e0f3d23791efac0fd8627b49c829c196a492e88168e6a669d863"
+checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e"
dependencies = [
"anstream",
"anstyle",
@@ -794,21 +797,21 @@ dependencies = [
[[package]]
name = "clap_derive"
-version = "4.5.28"
+version = "4.5.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf4ced95c6f4a675af3da73304b9ac4ed991640c36374e4b46795c49e17cf1ed"
+checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce"
dependencies = [
"heck 0.5.0",
"proc-macro2",
"quote",
- "syn 2.0.99",
+ "syn 2.0.104",
]
[[package]]
name = "clap_lex"
-version = "0.7.4"
+version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
+checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675"
[[package]]
name = "codespan-reporting"
@@ -842,9 +845,9 @@ checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
[[package]]
name = "colorchoice"
-version = "1.0.3"
+version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
+checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
[[package]]
name = "colored"
@@ -931,9 +934,9 @@ dependencies = [
[[package]]
name = "core-foundation"
-version = "0.10.0"
+version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63"
+checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6"
dependencies = [
"core-foundation-sys",
"libc",
@@ -964,8 +967,8 @@ version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1"
dependencies = [
- "bitflags 2.9.0",
- "core-foundation 0.10.0",
+ "bitflags 2.9.1",
+ "core-foundation 0.10.1",
"core-graphics-types 0.2.0",
"foreign-types 0.5.0",
"libc",
@@ -988,8 +991,8 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb"
dependencies = [
- "bitflags 2.9.0",
- "core-foundation 0.10.0",
+ "bitflags 2.9.1",
+ "core-foundation 0.10.1",
"libc",
]
@@ -1058,9 +1061,9 @@ dependencies = [
[[package]]
name = "crossbeam-channel"
-version = "0.5.14"
+version = "0.5.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471"
+checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2"
dependencies = [
"crossbeam-utils",
]
@@ -1092,9 +1095,9 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
[[package]]
name = "crunchy"
-version = "0.2.3"
+version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929"
+checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
[[package]]
name = "crypto-common"
@@ -1108,15 +1111,15 @@ dependencies = [
[[package]]
name = "cssparser"
-version = "0.27.2"
+version = "0.29.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "754b69d351cdc2d8ee09ae203db831e005560fc6030da058f86ad60c92a9cb0a"
+checksum = "f93d03419cb5950ccfd3daf3ff1c7a36ace64609a1a8746d493df1ca0afde0fa"
dependencies = [
"cssparser-macros",
"dtoa-short",
- "itoa 0.4.8",
+ "itoa",
"matches",
- "phf 0.8.0",
+ "phf 0.10.1",
"proc-macro2",
"quote",
"smallvec",
@@ -1130,7 +1133,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331"
dependencies = [
"quote",
- "syn 2.0.99",
+ "syn 2.0.104",
]
[[package]]
@@ -1140,14 +1143,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501"
dependencies = [
"quote",
- "syn 2.0.99",
+ "syn 2.0.104",
]
[[package]]
name = "cursor-icon"
-version = "1.1.0"
+version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991"
+checksum = "f27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732f"
[[package]]
name = "darling"
@@ -1170,7 +1173,7 @@ dependencies = [
"proc-macro2",
"quote",
"strsim",
- "syn 2.0.99",
+ "syn 2.0.104",
]
[[package]]
@@ -1181,7 +1184,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead"
dependencies = [
"darling_core",
"quote",
- "syn 2.0.99",
+ "syn 2.0.104",
]
[[package]]
@@ -1213,15 +1216,15 @@ dependencies = [
[[package]]
name = "derive_more"
-version = "0.99.19"
+version = "0.99.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3da29a38df43d6f156149c9b43ded5e018ddff2a855cf2cfd62e8cd7d079c69f"
+checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f"
dependencies = [
"convert_case 0.4.0",
"proc-macro2",
"quote",
"rustc_version",
- "syn 2.0.99",
+ "syn 2.0.104",
]
[[package]]
@@ -1258,7 +1261,7 @@ dependencies = [
"libc",
"option-ext",
"redox_users",
- "windows-sys 0.59.0",
+ "windows-sys 0.60.2",
]
[[package]]
@@ -1273,7 +1276,7 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec"
dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
"objc2 0.6.1",
]
@@ -1285,7 +1288,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.99",
+ "syn 2.0.104",
]
[[package]]
@@ -1294,7 +1297,7 @@ version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412"
dependencies = [
- "libloading 0.8.6",
+ "libloading 0.8.8",
]
[[package]]
@@ -1311,13 +1314,13 @@ dependencies = [
[[package]]
name = "dlopen2_derive"
-version = "0.4.0"
+version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f2b99bf03862d7f545ebc28ddd33a665b50865f4dfd84031a393823879bd4c54"
+checksum = "788160fb30de9cdd857af31c6a2675904b16ece8fc2737b2c7127ba368c9d0f4"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.99",
+ "syn 2.0.104",
]
[[package]]
@@ -1337,9 +1340,9 @@ checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2"
[[package]]
name = "dpi"
-version = "0.1.1"
+version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53"
+checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76"
dependencies = [
"serde",
]
@@ -1381,7 +1384,7 @@ dependencies = [
"dyn-any",
"proc-macro2",
"quote",
- "syn 2.0.99",
+ "syn 2.0.104",
]
[[package]]
@@ -1398,9 +1401,9 @@ checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
[[package]]
name = "embed-resource"
-version = "3.0.2"
+version = "3.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7fbc6e0d8e0c03a655b53ca813f0463d2c956bc4db8138dbc89f120b066551e3"
+checksum = "0963f530273dc3022ab2bdc3fcd6d488e850256f2284a82b7413cb9481ee85dd"
dependencies = [
"cc",
"memchr",
@@ -1437,17 +1440,37 @@ dependencies = [
[[package]]
name = "env_logger"
-version = "0.11.6"
+version = "0.11.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dcaee3d8e3cfc3fd92428d477bc97fc29ec8716d180c0d74c643bb26166660e0"
+checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f"
dependencies = [
"anstream",
"anstyle",
"env_filter",
- "humantime",
+ "jiff",
"log",
]
+[[package]]
+name = "equator"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4711b213838dfee0117e3be6ac926007d7f433d7bbe33595975d4190cb07e6fc"
+dependencies = [
+ "equator-macro",
+]
+
+[[package]]
+name = "equator-macro"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.104",
+]
+
[[package]]
name = "equivalent"
version = "1.0.2"
@@ -1466,12 +1489,12 @@ dependencies = [
[[package]]
name = "errno"
-version = "0.3.10"
+version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
+checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad"
dependencies = [
"libc",
- "windows-sys 0.59.0",
+ "windows-sys 0.60.2",
]
[[package]]
@@ -1556,9 +1579,9 @@ checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99"
[[package]]
name = "flate2"
-version = "1.1.0"
+version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "11faaf5a5236997af9848be0bef4db95824b1d534ebc64d0f0c6cf3e67bd38dc"
+checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d"
dependencies = [
"crc32fast",
"miniz_oxide",
@@ -1578,15 +1601,15 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "foldhash"
-version = "0.1.4"
+version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f"
+checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
[[package]]
name = "font-types"
-version = "0.8.3"
+version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d868ec188a98bb014c606072edd47e52e7ab7297db943b0b28503121e1d037bd"
+checksum = "1fa6a5e5a77b5f3f7f9e32879f484aa5b3632ddfbe568a16266c904a6f32cdaf"
dependencies = [
"bytemuck",
]
@@ -1612,9 +1635,9 @@ dependencies = [
[[package]]
name = "fontconfig-parser"
-version = "0.5.7"
+version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c1fcfcd44ca6e90c921fee9fa665d530b21ef1327a4c1a6c5250ea44b776ada7"
+checksum = "bbc773e24e02d4ddd8395fd30dc147524273a83e54e0f312d986ea30de5f5646"
dependencies = [
"roxmltree",
]
@@ -1683,7 +1706,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.99",
+ "syn 2.0.104",
]
[[package]]
@@ -1784,7 +1807,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.99",
+ "syn 2.0.104",
]
[[package]]
@@ -1958,34 +1981,36 @@ dependencies = [
[[package]]
name = "getrandom"
-version = "0.2.15"
+version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
+checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
dependencies = [
"cfg-if",
"js-sys",
"libc",
- "wasi 0.11.0+wasi-snapshot-preview1",
+ "wasi 0.11.1+wasi-snapshot-preview1",
"wasm-bindgen",
]
[[package]]
name = "getrandom"
-version = "0.3.1"
+version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8"
+checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
dependencies = [
"cfg-if",
+ "js-sys",
"libc",
- "wasi 0.13.3+wasi-0.2.2",
- "windows-targets 0.52.6",
+ "r-efi",
+ "wasi 0.14.2+wasi-0.2.4",
+ "wasm-bindgen",
]
[[package]]
name = "gif"
-version = "0.13.1"
+version = "0.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3fb2d69b19215e18bb912fa30f7ce15846e301408695e44e0ef719f1da9e19f2"
+checksum = "4ae047235e33e2829703574b54fdec96bfbad892062d97fed2f76022287de61b"
dependencies = [
"color_quant",
"weezl",
@@ -2042,9 +2067,9 @@ dependencies = [
[[package]]
name = "glam"
-version = "0.29.2"
+version = "0.29.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc46dd3ec48fdd8e693a98d2b8bafae273a2d54c1de02a2a7e3d57d501f39677"
+checksum = "8babf46d4c1c9d92deac9f7be466f76dfc4482b6452fc5024b5e8daf6ffeb3ee"
dependencies = [
"serde",
]
@@ -2055,7 +2080,7 @@ version = "0.18.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5"
dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
"futures-channel",
"futures-core",
"futures-executor",
@@ -2083,7 +2108,7 @@ dependencies = [
"proc-macro-error",
"proc-macro2",
"quote",
- "syn 2.0.99",
+ "syn 2.0.104",
]
[[package]]
@@ -2140,7 +2165,7 @@ version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171"
dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
"gpu-alloc-types",
]
@@ -2150,7 +2175,7 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4"
dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
]
[[package]]
@@ -2167,11 +2192,11 @@ dependencies = [
[[package]]
name = "gpu-descriptor"
-version = "0.3.1"
+version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dcf29e94d6d243368b7a56caa16bc213e4f9f8ed38c4d9557069527b5d5281ca"
+checksum = "b89c83349105e3732062a895becfc71a8f921bb71ecbbdd8ff99263e3b53a0ca"
dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
"gpu-descriptor-types",
"hashbrown 0.15.4",
]
@@ -2182,7 +2207,7 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fdf242682df893b86f33a73828fb09ca4b2d3bb6cc95249707fc684d27484b91"
dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
]
[[package]]
@@ -2281,7 +2306,7 @@ dependencies = [
"num-traits",
"parley",
"petgraph 0.7.1",
- "rand 0.9.0",
+ "rand 0.9.1",
"rand_chacha 0.9.0",
"rustc-hash 2.1.1",
"serde",
@@ -2302,7 +2327,7 @@ dependencies = [
"log",
"math-parser",
"node-macro",
- "rand 0.9.0",
+ "rand 0.9.1",
]
[[package]]
@@ -2334,7 +2359,7 @@ dependencies = [
"image",
"ndarray",
"node-macro",
- "rand 0.9.0",
+ "rand 0.9.1",
"rand_chacha 0.9.0",
"serde",
"specta",
@@ -2363,7 +2388,7 @@ dependencies = [
"log",
"ndarray",
"node-macro",
- "rand 0.9.0",
+ "rand 0.9.1",
"rand_chacha 0.9.0",
"reqwest",
"tokio",
@@ -2413,7 +2438,7 @@ name = "graphite-editor"
version = "0.0.0"
dependencies = [
"bezier-rs",
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
"derivative",
"dyn-any",
"env_logger",
@@ -2451,7 +2476,7 @@ dependencies = [
"proc-macro2",
"quote",
"serde",
- "syn 2.0.99",
+ "syn 2.0.104",
]
[[package]]
@@ -2521,7 +2546,7 @@ dependencies = [
"proc-macro-error",
"proc-macro2",
"quote",
- "syn 2.0.99",
+ "syn 2.0.104",
]
[[package]]
@@ -2536,9 +2561,9 @@ dependencies = [
[[package]]
name = "h2"
-version = "0.4.8"
+version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5017294ff4bb30944501348f6f8e42e6ad28f42c8bbef7a74029aff064a4e3c2"
+checksum = "17da50a276f1e01e0ba6c029e47b7100754904ee8a278f886546e98575380785"
dependencies = [
"atomic-waker",
"bytes",
@@ -2546,7 +2571,7 @@ dependencies = [
"futures-core",
"futures-sink",
"http",
- "indexmap 2.7.1",
+ "indexmap 2.10.0",
"slab",
"tokio",
"tokio-util",
@@ -2555,9 +2580,9 @@ dependencies = [
[[package]]
name = "half"
-version = "2.4.1"
+version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888"
+checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9"
dependencies = [
"bytemuck",
"cfg-if",
@@ -2596,15 +2621,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "hermit-abi"
-version = "0.4.0"
+version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc"
-
-[[package]]
-name = "hermit-abi"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fbd780fe5cc30f81464441920d82ac8740e2e46b29a6fad543ddd075229ce37e"
+checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
[[package]]
name = "hex"
@@ -2620,27 +2639,25 @@ checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df"
[[package]]
name = "html5ever"
-version = "0.26.0"
+version = "0.29.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bea68cab48b8459f17cf1c944c67ddc572d272d9f2b274140f223ecb1da4a3b7"
+checksum = "3b7410cae13cbc75623c98ac4cbfd1f0bedddf3227afc24f370cf0f50a44a11c"
dependencies = [
"log",
"mac",
"markup5ever",
- "proc-macro2",
- "quote",
- "syn 1.0.109",
+ "match_token",
]
[[package]]
name = "http"
-version = "1.2.0"
+version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea"
+checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565"
dependencies = [
"bytes",
"fnv",
- "itoa 1.0.15",
+ "itoa",
]
[[package]]
@@ -2655,12 +2672,12 @@ dependencies = [
[[package]]
name = "http-body-util"
-version = "0.1.2"
+version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f"
+checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a"
dependencies = [
"bytes",
- "futures-util",
+ "futures-core",
"http",
"http-body",
"pin-project-lite",
@@ -2678,12 +2695,6 @@ version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
-[[package]]
-name = "humantime"
-version = "2.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
-
[[package]]
name = "hyper"
version = "1.6.0"
@@ -2698,7 +2709,7 @@ dependencies = [
"http-body",
"httparse",
"httpdate",
- "itoa 1.0.15",
+ "itoa",
"pin-project-lite",
"smallvec",
"tokio",
@@ -2707,11 +2718,10 @@ dependencies = [
[[package]]
name = "hyper-rustls"
-version = "0.27.5"
+version = "0.27.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2"
+checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58"
dependencies = [
- "futures-util",
"http",
"hyper",
"hyper-util",
@@ -2741,21 +2751,28 @@ dependencies = [
[[package]]
name = "hyper-util"
-version = "0.1.10"
+version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4"
+checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb"
dependencies = [
+ "base64 0.22.1",
"bytes",
"futures-channel",
+ "futures-core",
"futures-util",
"http",
"http-body",
"hyper",
+ "ipnet",
+ "libc",
+ "percent-encoding",
"pin-project-lite",
"socket2",
+ "system-configuration",
"tokio",
"tower-service",
"tracing",
+ "windows-registry",
]
[[package]]
@@ -2780,7 +2797,7 @@ dependencies = [
"quote",
"serde",
"serde_json",
- "syn 2.0.99",
+ "syn 2.0.104",
]
[[package]]
@@ -2794,16 +2811,17 @@ dependencies = [
[[package]]
name = "iana-time-zone"
-version = "0.1.61"
+version = "0.1.63"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220"
+checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"iana-time-zone-haiku",
"js-sys",
+ "log",
"wasm-bindgen",
- "windows-core 0.52.0",
+ "windows-core 0.61.2",
]
[[package]]
@@ -2838,16 +2856,30 @@ dependencies = [
[[package]]
name = "icu_collections"
-version = "1.5.0"
+version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526"
+checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47"
dependencies = [
"displaydoc",
+ "potential_utf",
"yoke",
"zerofrom",
"zerovec",
]
+[[package]]
+name = "icu_locale_core"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a"
+dependencies = [
+ "displaydoc",
+ "litemap 0.8.0",
+ "tinystr 0.8.1",
+ "writeable 0.6.1",
+ "zerovec",
+]
+
[[package]]
name = "icu_locid"
version = "1.5.0"
@@ -2855,37 +2887,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637"
dependencies = [
"displaydoc",
- "litemap",
- "tinystr",
- "writeable",
- "zerovec",
+ "litemap 0.7.5",
+ "tinystr 0.7.6",
+ "writeable 0.5.5",
]
-[[package]]
-name = "icu_locid_transform"
-version = "1.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e"
-dependencies = [
- "displaydoc",
- "icu_locid",
- "icu_locid_transform_data",
- "icu_provider",
- "tinystr",
- "zerovec",
-]
-
-[[package]]
-name = "icu_locid_transform_data"
-version = "1.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e"
-
[[package]]
name = "icu_normalizer"
-version = "1.5.0"
+version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f"
+checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979"
dependencies = [
"displaydoc",
"icu_collections",
@@ -2893,67 +2904,54 @@ dependencies = [
"icu_properties",
"icu_provider",
"smallvec",
- "utf16_iter",
- "utf8_iter",
- "write16",
"zerovec",
]
[[package]]
name = "icu_normalizer_data"
-version = "1.5.0"
+version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516"
+checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3"
[[package]]
name = "icu_properties"
-version = "1.5.1"
+version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5"
+checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b"
dependencies = [
"displaydoc",
"icu_collections",
- "icu_locid_transform",
+ "icu_locale_core",
"icu_properties_data",
"icu_provider",
- "tinystr",
+ "potential_utf",
+ "zerotrie",
"zerovec",
]
[[package]]
name = "icu_properties_data"
-version = "1.5.0"
+version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569"
+checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632"
[[package]]
name = "icu_provider"
-version = "1.5.0"
+version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9"
+checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af"
dependencies = [
"displaydoc",
- "icu_locid",
- "icu_provider_macros",
+ "icu_locale_core",
"stable_deref_trait",
- "tinystr",
- "writeable",
+ "tinystr 0.8.1",
+ "writeable 0.6.1",
"yoke",
"zerofrom",
+ "zerotrie",
"zerovec",
]
-[[package]]
-name = "icu_provider_macros"
-version = "1.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.99",
-]
-
[[package]]
name = "ident_case"
version = "1.0.1"
@@ -2973,9 +2971,9 @@ dependencies = [
[[package]]
name = "idna_adapter"
-version = "1.2.0"
+version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71"
+checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344"
dependencies = [
"icu_normalizer",
"icu_properties",
@@ -2983,16 +2981,16 @@ dependencies = [
[[package]]
name = "image"
-version = "0.25.5"
+version = "0.25.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cd6f44aed642f18953a158afeb30206f4d50da59fbc66ecb53c66488de73563b"
+checksum = "db35664ce6b9810857a38a906215e75a9c879f0696556a39f59c62829710251a"
dependencies = [
"bytemuck",
"byteorder-lite",
"color_quant",
"exr",
"gif",
- "image-webp 0.2.1",
+ "image-webp 0.2.3",
"num-traits",
"png",
"qoi",
@@ -3016,9 +3014,9 @@ dependencies = [
[[package]]
name = "image-webp"
-version = "0.2.1"
+version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b77d01e822461baa8409e156015a1d91735549f0f2c17691bd2d996bef238f7f"
+checksum = "f6970fe7a5300b4b42e62c52efa0187540a5bef546c60edaf554ef595d2e6f0b"
dependencies = [
"byteorder-lite",
"quick-error",
@@ -3049,9 +3047,9 @@ dependencies = [
[[package]]
name = "indexmap"
-version = "2.7.1"
+version = "2.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652"
+checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661"
dependencies = [
"equivalent",
"hashbrown 0.15.4",
@@ -3081,7 +3079,7 @@ checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.99",
+ "syn 2.0.104",
]
[[package]]
@@ -3108,6 +3106,16 @@ version = "2.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130"
+[[package]]
+name = "iri-string"
+version = "0.7.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2"
+dependencies = [
+ "memchr",
+ "serde",
+]
+
[[package]]
name = "is-docker"
version = "0.2.0"
@@ -3123,7 +3131,7 @@ version = "0.4.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9"
dependencies = [
- "hermit-abi 0.5.0",
+ "hermit-abi",
"libc",
"windows-sys 0.59.0",
]
@@ -3162,12 +3170,6 @@ dependencies = [
"either",
]
-[[package]]
-name = "itoa"
-version = "0.4.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
-
[[package]]
name = "itoa"
version = "1.0.15"
@@ -3197,6 +3199,30 @@ dependencies = [
"system-deps",
]
+[[package]]
+name = "jiff"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49"
+dependencies = [
+ "jiff-static",
+ "log",
+ "portable-atomic",
+ "portable-atomic-util",
+ "serde",
+]
+
+[[package]]
+name = "jiff-static"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.104",
+]
+
[[package]]
name = "jni"
version = "0.21.1"
@@ -3221,18 +3247,19 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
[[package]]
name = "jobserver"
-version = "0.1.32"
+version = "0.1.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0"
+checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a"
dependencies = [
+ "getrandom 0.3.3",
"libc",
]
[[package]]
name = "jpeg-decoder"
-version = "0.3.1"
+version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0"
+checksum = "00810f1d8b74be64b13dbf3db89ac67740615d6c891f0e7b6179326533011a07"
[[package]]
name = "js-sys"
@@ -3272,7 +3299,7 @@ version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a"
dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
"serde",
"unicode-segmentation",
]
@@ -3284,7 +3311,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76"
dependencies = [
"libc",
- "libloading 0.8.6",
+ "libloading 0.8.8",
"pkg-config",
]
@@ -3296,14 +3323,13 @@ checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc"
[[package]]
name = "kuchikiki"
-version = "0.8.2"
+version = "0.8.8-speedreader"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f29e4755b7b995046f510a7520c42b2fed58b77bd94d5a87a8eb43d2fd126da8"
+checksum = "02cb977175687f33fa4afa0c95c112b987ea1443e5a51c8f8ff27dc618270cc2"
dependencies = [
"cssparser",
"html5ever",
- "indexmap 1.9.3",
- "matches",
+ "indexmap 2.10.0",
"selectors",
]
@@ -3356,9 +3382,9 @@ dependencies = [
[[package]]
name = "libc"
-version = "0.2.170"
+version = "0.2.174"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828"
+checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
[[package]]
name = "libfuzzer-sys"
@@ -3382,29 +3408,29 @@ dependencies = [
[[package]]
name = "libloading"
-version = "0.8.6"
+version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
+checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667"
dependencies = [
"cfg-if",
- "windows-targets 0.52.6",
+ "windows-targets 0.53.2",
]
[[package]]
name = "libm"
-version = "0.2.11"
+version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa"
+checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de"
[[package]]
name = "libredox"
-version = "0.1.3"
+version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
+checksum = "1580801010e535496706ba011c15f8532df6b42297d2e471fec38ceadd8c0638"
dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
"libc",
- "redox_syscall 0.5.10",
+ "redox_syscall 0.5.13",
]
[[package]]
@@ -3415,9 +3441,9 @@ checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
[[package]]
name = "linux-raw-sys"
-version = "0.9.2"
+version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6db9c683daf087dc577b7506e9695b3d556a9f3849903fa28186283afd6809e9"
+checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
[[package]]
name = "litemap"
@@ -3425,6 +3451,12 @@ version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856"
+[[package]]
+name = "litemap"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956"
+
[[package]]
name = "litrs"
version = "0.4.1"
@@ -3433,9 +3465,9 @@ checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5"
[[package]]
name = "lock_api"
-version = "0.4.12"
+version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
+checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765"
dependencies = [
"autocfg",
"scopeguard",
@@ -3443,9 +3475,9 @@ dependencies = [
[[package]]
name = "log"
-version = "0.4.26"
+version = "0.4.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e"
+checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
[[package]]
name = "loop9"
@@ -3456,6 +3488,12 @@ dependencies = [
"imgref",
]
+[[package]]
+name = "lru-slab"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154"
+
[[package]]
name = "mac"
version = "0.1.1"
@@ -3473,18 +3511,29 @@ dependencies = [
[[package]]
name = "markup5ever"
-version = "0.11.0"
+version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a2629bb1404f3d34c2e921f21fd34ba00b206124c81f65c50b43b6aaefeb016"
+checksum = "c7a7213d12e1864c0f002f52c2923d4556935a43dec5e71355c2760e0f6e7a18"
dependencies = [
"log",
- "phf 0.10.1",
- "phf_codegen 0.10.0",
+ "phf 0.11.3",
+ "phf_codegen 0.11.3",
"string_cache",
"string_cache_codegen",
"tendril",
]
+[[package]]
+name = "match_token"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.104",
+]
+
[[package]]
name = "matches"
version = "0.1.10"
@@ -3511,9 +3560,9 @@ dependencies = [
[[package]]
name = "matrixmultiply"
-version = "0.3.9"
+version = "0.3.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9380b911e3e96d10c1f415da0876389aaf1b56759054eeb0de7df940c456ba1a"
+checksum = "a06de3016e9fae57a36fd14dba131fccf49f74b40b7fbdb472f96e361ec71a08"
dependencies = [
"autocfg",
"rawpointer",
@@ -3531,9 +3580,9 @@ dependencies = [
[[package]]
name = "memchr"
-version = "2.7.4"
+version = "2.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
+checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
[[package]]
name = "memmap2"
@@ -3559,7 +3608,7 @@ version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ecfd3296f8c56b7c1f6fbac3c71cefa9d78ce009850c45000015f206dc7fa21"
dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
"block",
"core-graphics-types 0.1.3",
"foreign-types 0.5.0",
@@ -3582,9 +3631,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "miniz_oxide"
-version = "0.8.5"
+version = "0.8.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5"
+checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
dependencies = [
"adler2",
"simd-adler32",
@@ -3592,20 +3641,20 @@ dependencies = [
[[package]]
name = "mio"
-version = "1.0.3"
+version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
+checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c"
dependencies = [
"libc",
- "wasi 0.11.0+wasi-snapshot-preview1",
- "windows-sys 0.52.0",
+ "wasi 0.11.1+wasi-snapshot-preview1",
+ "windows-sys 0.59.0",
]
[[package]]
name = "muda"
-version = "0.16.1"
+version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4de14a9b5d569ca68d7c891d613b390cf5ab4f851c77aaa2f9e435555d3d9492"
+checksum = "58b89bf91c19bf036347f1ab85a81c560f08c0667c8601bece664d860a600988"
dependencies = [
"crossbeam-channel",
"dpi",
@@ -3630,11 +3679,11 @@ checksum = "364f94bc34f61332abebe8cad6f6cd82a5b65cff22c828d05d0968911462ca4f"
dependencies = [
"arrayvec",
"bit-set",
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
"cfg_aliases 0.1.1",
"codespan-reporting",
"hexf-parse",
- "indexmap 2.7.1",
+ "indexmap 2.10.0",
"log",
"petgraph 0.6.5",
"rustc-hash 1.1.0",
@@ -3682,7 +3731,7 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7"
dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
"jni-sys",
"log",
"ndk-sys 0.5.0+25.2.9519653",
@@ -3697,7 +3746,7 @@ version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4"
dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
"jni-sys",
"log",
"ndk-sys 0.6.0+11769913",
@@ -3747,7 +3796,7 @@ dependencies = [
"proc-macro-error2",
"proc-macro2",
"quote",
- "syn 2.0.99",
+ "syn 2.0.104",
]
[[package]]
@@ -3805,7 +3854,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.99",
+ "syn 2.0.104",
]
[[package]]
@@ -3839,23 +3888,24 @@ dependencies = [
[[package]]
name = "num_enum"
-version = "0.7.3"
+version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179"
+checksum = "a973b4e44ce6cad84ce69d797acf9a044532e4184c4f267913d1b546a0727b7a"
dependencies = [
"num_enum_derive",
+ "rustversion",
]
[[package]]
name = "num_enum_derive"
-version = "0.7.3"
+version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56"
+checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d"
dependencies = [
"proc-macro-crate 3.3.0",
"proc-macro2",
"quote",
- "syn 2.0.99",
+ "syn 2.0.104",
]
[[package]]
@@ -3905,11 +3955,11 @@ dependencies = [
[[package]]
name = "objc2-app-kit"
-version = "0.3.0"
+version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5906f93257178e2f7ae069efb89fbd6ee94f0592740b5f8a1512ca498814d0fb"
+checksum = "e6f29f568bec459b0ddff777cec4fe3fd8666d82d5a40ebd0ff7e66134f89bcc"
dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
"block2 0.6.1",
"libc",
"objc2 0.6.1",
@@ -3919,27 +3969,27 @@ dependencies = [
"objc2-core-graphics",
"objc2-core-image",
"objc2-foundation 0.3.1",
- "objc2-quartz-core 0.3.0",
+ "objc2-quartz-core 0.3.1",
]
[[package]]
name = "objc2-cloud-kit"
-version = "0.3.0"
+version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c1948a9be5f469deadbd6bcb86ad7ff9e47b4f632380139722f7d9840c0d42c"
+checksum = "17614fdcd9b411e6ff1117dfb1d0150f908ba83a7df81b1f118005fe0a8ea15d"
dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
"objc2 0.6.1",
"objc2-foundation 0.3.1",
]
[[package]]
name = "objc2-core-data"
-version = "0.3.0"
+version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1f860f8e841f6d32f754836f51e6bc7777cd7e7053cf18528233f6811d3eceb4"
+checksum = "291fbbf7d29287518e8686417cf7239c74700fd4b607623140a7d4a3c834329d"
dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
"objc2 0.6.1",
"objc2-foundation 0.3.1",
]
@@ -3950,18 +4000,19 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166"
dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
"dispatch2",
"objc2 0.6.1",
]
[[package]]
name = "objc2-core-graphics"
-version = "0.3.0"
+version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f8dca602628b65356b6513290a21a6405b4d4027b8b250f0b98dddbb28b7de02"
+checksum = "989c6c68c13021b5c2d6b71456ebb0f9dc78d752e86a98da7c716f4f9470f5a4"
dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
+ "dispatch2",
"objc2 0.6.1",
"objc2-core-foundation",
"objc2-io-surface",
@@ -3969,9 +4020,9 @@ dependencies = [
[[package]]
name = "objc2-core-image"
-version = "0.3.0"
+version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ffa6bea72bf42c78b0b34e89c0bafac877d5f80bf91e159a5d96ea7f693ca56"
+checksum = "79b3dc0cc4386b6ccf21c157591b34a7f44c8e75b064f85502901ab2188c007e"
dependencies = [
"objc2 0.6.1",
"objc2-foundation 0.3.1",
@@ -3983,7 +4034,7 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ba833d4a1cb1aac330f8c973fd92b6ff1858e4aef5cdd00a255eefb28022fb5"
dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
"objc2-core-foundation",
]
@@ -4014,7 +4065,7 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8"
dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
"block2 0.5.1",
"libc",
"objc2 0.5.2",
@@ -4026,7 +4077,7 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "900831247d2fe1a09a683278e5384cfb8c80c79fe6b166f9d14bfdde0ea1b03c"
dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
"block2 0.6.1",
"libc",
"objc2 0.6.1",
@@ -4035,11 +4086,11 @@ dependencies = [
[[package]]
name = "objc2-io-surface"
-version = "0.3.0"
+version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "161a8b87e32610086e1a7a9e9ec39f84459db7b3a0881c1f16ca5a2605581c19"
+checksum = "7282e9ac92529fa3457ce90ebb15f4ecbc383e8338060960760fa2cf75420c3c"
dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
"objc2 0.6.1",
"objc2-core-foundation",
]
@@ -4050,7 +4101,7 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6"
dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
"block2 0.5.1",
"objc2 0.5.2",
"objc2-foundation 0.2.2",
@@ -4062,7 +4113,7 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a"
dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
"block2 0.5.1",
"objc2 0.5.2",
"objc2-foundation 0.2.2",
@@ -4071,22 +4122,22 @@ dependencies = [
[[package]]
name = "objc2-quartz-core"
-version = "0.3.0"
+version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6fb3794501bb1bee12f08dcad8c61f2a5875791ad1c6f47faa71a0f033f20071"
+checksum = "90ffb6a0cd5f182dc964334388560b12a57f7b74b3e2dec5e2722aa2dfb2ccd5"
dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
"objc2 0.6.1",
"objc2-foundation 0.3.1",
]
[[package]]
name = "objc2-ui-kit"
-version = "0.3.0"
+version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "777a571be14a42a3990d4ebedaeb8b54cd17377ec21b92e8200ac03797b3bee1"
+checksum = "25b1312ad7bc8a0e92adae17aa10f90aae1fb618832f9b993b022b591027daed"
dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
"objc2 0.6.1",
"objc2-core-foundation",
"objc2-foundation 0.3.1",
@@ -4094,11 +4145,11 @@ dependencies = [
[[package]]
name = "objc2-web-kit"
-version = "0.3.0"
+version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b717127e4014b0f9f3e8bba3d3f2acec81f1bde01f656823036e823ed2c94dce"
+checksum = "91672909de8b1ce1c2252e95bbee8c1649c9ad9d14b9248b3d7b4c47903c47ad"
dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
"block2 0.6.1",
"objc2 0.6.1",
"objc2-app-kit",
@@ -4117,9 +4168,15 @@ dependencies = [
[[package]]
name = "once_cell"
-version = "1.20.3"
+version = "1.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e"
+checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
+
+[[package]]
+name = "once_cell_polyfill"
+version = "1.70.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad"
[[package]]
name = "oorandom"
@@ -4141,11 +4198,11 @@ dependencies = [
[[package]]
name = "openssl"
-version = "0.10.72"
+version = "0.10.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da"
+checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8"
dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
"cfg-if",
"foreign-types 0.3.2",
"libc",
@@ -4162,7 +4219,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.99",
+ "syn 2.0.104",
]
[[package]]
@@ -4173,9 +4230,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
[[package]]
name = "openssl-sys"
-version = "0.9.107"
+version = "0.9.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8288979acd84749c744a9014b4382d42b8f7b2592847b5afb2ed29e5d16ede07"
+checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571"
dependencies = [
"cc",
"libc",
@@ -4200,9 +4257,9 @@ dependencies = [
[[package]]
name = "os_pipe"
-version = "1.2.1"
+version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ffd2b0a5634335b135d5728d84c5e0fd726954b87111f7506a61c502280d982"
+checksum = "db335f4760b14ead6290116f2427bf33a14d4f0617d49f78a246de10c1831224"
dependencies = [
"libc",
"windows-sys 0.59.0",
@@ -4244,9 +4301,9 @@ dependencies = [
[[package]]
name = "parking_lot"
-version = "0.12.3"
+version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
+checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13"
dependencies = [
"lock_api",
"parking_lot_core",
@@ -4254,13 +4311,13 @@ dependencies = [
[[package]]
name = "parking_lot_core"
-version = "0.9.10"
+version = "0.9.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
+checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5"
dependencies = [
"cfg-if",
"libc",
- "redox_syscall 0.5.10",
+ "redox_syscall 0.5.13",
"smallvec",
"windows-targets 0.52.6",
]
@@ -4333,9 +4390,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
[[package]]
name = "pest"
-version = "2.7.15"
+version = "2.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc"
+checksum = "1db05f56d34358a8b1066f67cbb203ee3e7ed2ba674a6263a1d5ec6db2204323"
dependencies = [
"memchr",
"thiserror 2.0.12",
@@ -4344,9 +4401,9 @@ dependencies = [
[[package]]
name = "pest_derive"
-version = "2.7.15"
+version = "2.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "816518421cfc6887a0d62bf441b6ffb4536fcc926395a69e1a85852d4363f57e"
+checksum = "bb056d9e8ea77922845ec74a1c4e8fb17e7c218cc4fc11a15c5d25e189aa40bc"
dependencies = [
"pest",
"pest_generator",
@@ -4354,24 +4411,23 @@ dependencies = [
[[package]]
name = "pest_generator"
-version = "2.7.15"
+version = "2.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d1396fd3a870fc7838768d171b4616d5c91f6cc25e377b673d714567d99377b"
+checksum = "87e404e638f781eb3202dc82db6760c8ae8a1eeef7fb3fa8264b2ef280504966"
dependencies = [
"pest",
"pest_meta",
"proc-macro2",
"quote",
- "syn 2.0.99",
+ "syn 2.0.104",
]
[[package]]
name = "pest_meta"
-version = "2.7.15"
+version = "2.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e1e58089ea25d717bfd31fb534e4f3afcc2cc569c70de3e239778991ea3b7dea"
+checksum = "edd1101f170f5903fde0914f899bb503d9ff5271d7ba76bbb70bea63690cc0d5"
dependencies = [
- "once_cell",
"pest",
"sha2",
]
@@ -4383,7 +4439,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db"
dependencies = [
"fixedbitset 0.4.2",
- "indexmap 2.7.1",
+ "indexmap 2.10.0",
]
[[package]]
@@ -4393,7 +4449,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772"
dependencies = [
"fixedbitset 0.5.7",
- "indexmap 2.7.1",
+ "indexmap 2.10.0",
]
[[package]]
@@ -4402,9 +4458,7 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12"
dependencies = [
- "phf_macros 0.8.0",
"phf_shared 0.8.0",
- "proc-macro-hack",
]
[[package]]
@@ -4413,7 +4467,9 @@ version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259"
dependencies = [
+ "phf_macros 0.10.0",
"phf_shared 0.10.0",
+ "proc-macro-hack",
]
[[package]]
@@ -4438,12 +4494,12 @@ dependencies = [
[[package]]
name = "phf_codegen"
-version = "0.10.0"
+version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd"
+checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a"
dependencies = [
- "phf_generator 0.10.0",
- "phf_shared 0.10.0",
+ "phf_generator 0.11.3",
+ "phf_shared 0.11.3",
]
[[package]]
@@ -4478,12 +4534,12 @@ dependencies = [
[[package]]
name = "phf_macros"
-version = "0.8.0"
+version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f6fde18ff429ffc8fe78e2bf7f8b7a5a5a6e2a8b58bc5a9ac69198bbda9189c"
+checksum = "58fdf3184dd560f160dd73922bea2d5cd6e8f064bf4b13110abd81b03697b4e0"
dependencies = [
- "phf_generator 0.8.0",
- "phf_shared 0.8.0",
+ "phf_generator 0.10.0",
+ "phf_shared 0.10.0",
"proc-macro-hack",
"proc-macro2",
"quote",
@@ -4500,7 +4556,7 @@ dependencies = [
"phf_shared 0.11.3",
"proc-macro2",
"quote",
- "syn 2.0.99",
+ "syn 2.0.104",
]
[[package]]
@@ -4556,13 +4612,13 @@ checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
[[package]]
name = "plist"
-version = "1.7.1"
+version = "1.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eac26e981c03a6e53e0aee43c113e3202f5581d5360dae7bd2c70e800dd0451d"
+checksum = "3d77244ce2d584cd84f6a15f86195b8c9b2a0dfbfd817c09e0464244091a58ed"
dependencies = [
"base64 0.22.1",
- "indexmap 2.7.1",
- "quick-xml 0.32.0",
+ "indexmap 2.10.0",
+ "quick-xml",
"serde",
"time",
]
@@ -4610,24 +4666,24 @@ dependencies = [
[[package]]
name = "polling"
-version = "3.7.4"
+version = "3.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f"
+checksum = "b53a684391ad002dd6a596ceb6c74fd004fdce75f4be2e3f615068abbea5fd50"
dependencies = [
"cfg-if",
"concurrent-queue",
- "hermit-abi 0.4.0",
+ "hermit-abi",
"pin-project-lite",
- "rustix 0.38.44",
+ "rustix 1.0.7",
"tracing",
"windows-sys 0.59.0",
]
[[package]]
name = "portable-atomic"
-version = "1.11.0"
+version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e"
+checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483"
[[package]]
name = "portable-atomic-util"
@@ -4638,6 +4694,15 @@ dependencies = [
"portable-atomic",
]
+[[package]]
+name = "potential_utf"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585"
+dependencies = [
+ "zerovec",
+]
+
[[package]]
name = "powerfmt"
version = "0.2.0"
@@ -4646,11 +4711,11 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
[[package]]
name = "ppv-lite86"
-version = "0.2.20"
+version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
+checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
dependencies = [
- "zerocopy 0.7.35",
+ "zerocopy",
]
[[package]]
@@ -4709,7 +4774,7 @@ version = "3.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35"
dependencies = [
- "toml_edit 0.22.24",
+ "toml_edit 0.22.27",
]
[[package]]
@@ -4755,7 +4820,7 @@ dependencies = [
"proc-macro-error-attr2",
"proc-macro2",
"quote",
- "syn 2.0.99",
+ "syn 2.0.104",
]
[[package]]
@@ -4766,30 +4831,30 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068"
[[package]]
name = "proc-macro2"
-version = "1.0.94"
+version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
+checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
dependencies = [
"unicode-ident",
]
[[package]]
name = "profiling"
-version = "1.0.16"
+version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "afbdc74edc00b6f6a218ca6a5364d6226a259d4b8ea1af4a0ea063f27e179f4d"
+checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773"
dependencies = [
"profiling-procmacros",
]
[[package]]
name = "profiling-procmacros"
-version = "1.0.16"
+version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a65f2e60fbf1063868558d69c6beacf412dc755f9fc020f514b7955fc914fe30"
+checksum = "52717f9a02b6965224f95ca2a81e2e0c5c43baacd28ca057577988930b6c3d5b"
dependencies = [
"quote",
- "syn 2.0.99",
+ "syn 2.0.104",
]
[[package]]
@@ -4825,29 +4890,21 @@ checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
[[package]]
name = "quick-xml"
-version = "0.32.0"
+version = "0.37.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d3a6e5838b60e0e8fa7a43f22ade549a37d61f8bdbe636d0d7816191de969c2"
-dependencies = [
- "memchr",
-]
-
-[[package]]
-name = "quick-xml"
-version = "0.37.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "165859e9e55f79d67b96c5d96f4e88b6f2695a1972849c15a6a3f5c59fc2c003"
+checksum = "331e97a1af0bf59823e6eadffe373d7b27f485be8748f71471c662c1f269b7fb"
dependencies = [
"memchr",
]
[[package]]
name = "quinn"
-version = "0.11.6"
+version = "0.11.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62e96808277ec6f97351a2380e6c25114bc9e67037775464979f3037c92d05ef"
+checksum = "626214629cda6781b6dc1d316ba307189c85ba657213ce642d9c77670f8202c8"
dependencies = [
"bytes",
+ "cfg_aliases 0.2.1",
"pin-project-lite",
"quinn-proto",
"quinn-udp",
@@ -4857,17 +4914,19 @@ dependencies = [
"thiserror 2.0.12",
"tokio",
"tracing",
+ "web-time 1.1.0",
]
[[package]]
name = "quinn-proto"
-version = "0.11.9"
+version = "0.11.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d"
+checksum = "49df843a9161c85bb8aae55f101bc0bac8bcafd637a620d9122fd7e0b2f7422e"
dependencies = [
"bytes",
- "getrandom 0.2.15",
- "rand 0.8.5",
+ "getrandom 0.3.3",
+ "lru-slab",
+ "rand 0.9.1",
"ring",
"rustc-hash 2.1.1",
"rustls",
@@ -4881,9 +4940,9 @@ dependencies = [
[[package]]
name = "quinn-udp"
-version = "0.5.10"
+version = "0.5.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e46f3055866785f6b92bc6164b76be02ca8f2eb4b002c0354b28cf4c119e5944"
+checksum = "fcebb1209ee276352ef14ff8732e24cc2b02bbac986cd74a4c81bcb2f9881970"
dependencies = [
"cfg_aliases 0.2.1",
"libc",
@@ -4895,13 +4954,19 @@ dependencies = [
[[package]]
name = "quote"
-version = "1.0.39"
+version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c1f1914ce909e1658d9907913b4b91947430c7d9be598b15a1912935b8c04801"
+checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
dependencies = [
"proc-macro2",
]
+[[package]]
+name = "r-efi"
+version = "5.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
+
[[package]]
name = "rand"
version = "0.7.3"
@@ -4929,13 +4994,12 @@ dependencies = [
[[package]]
name = "rand"
-version = "0.9.0"
+version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94"
+checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97"
dependencies = [
"rand_chacha 0.9.0",
"rand_core 0.9.3",
- "zerocopy 0.8.23",
]
[[package]]
@@ -4983,7 +5047,7 @@ version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
- "getrandom 0.2.15",
+ "getrandom 0.2.16",
]
[[package]]
@@ -4992,7 +5056,7 @@ version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
dependencies = [
- "getrandom 0.3.1",
+ "getrandom 0.3.3",
]
[[package]]
@@ -5056,9 +5120,9 @@ dependencies = [
[[package]]
name = "ravif"
-version = "0.11.11"
+version = "0.11.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2413fd96bd0ea5cdeeb37eaf446a22e6ed7b981d792828721e74ded1980a45c6"
+checksum = "5825c26fddd16ab9f515930d49028a630efec172e903483c94796cfe31893e6b"
dependencies = [
"avif-serialize",
"imgref",
@@ -5108,7 +5172,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6f9e8a4f503e5c8750e4cd3b32a4e090035c46374b305a15c70bad833dca05f"
dependencies = [
"bytemuck",
- "font-types 0.8.3",
+ "font-types 0.8.4",
]
[[package]]
@@ -5142,11 +5206,11 @@ dependencies = [
[[package]]
name = "redox_syscall"
-version = "0.5.10"
+version = "0.5.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1"
+checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6"
dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
]
[[package]]
@@ -5155,11 +5219,31 @@ version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b"
dependencies = [
- "getrandom 0.2.15",
+ "getrandom 0.2.16",
"libredox",
"thiserror 2.0.12",
]
+[[package]]
+name = "ref-cast"
+version = "1.0.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf"
+dependencies = [
+ "ref-cast-impl",
+]
+
+[[package]]
+name = "ref-cast-impl"
+version = "1.0.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.104",
+]
+
[[package]]
name = "regex"
version = "1.11.1"
@@ -5197,9 +5281,9 @@ checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832"
[[package]]
name = "reqwest"
-version = "0.12.12"
+version = "0.12.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "43e734407157c3c2034e0258f5e4473ddb361b1e85f95a66690d67264d7cd1da"
+checksum = "cbc931937e6ca3a06e3b6c0aa7841849b160a90351d6ab467a8b9b9959767531"
dependencies = [
"base64 0.22.1",
"bytes",
@@ -5217,28 +5301,25 @@ dependencies = [
"hyper-rustls",
"hyper-tls",
"hyper-util",
- "ipnet",
"js-sys",
"log",
"mime",
"native-tls",
- "once_cell",
"percent-encoding",
"pin-project-lite",
"quinn",
"rustls",
- "rustls-pemfile",
"rustls-pki-types",
"serde",
"serde_json",
"serde_urlencoded",
"sync_wrapper",
- "system-configuration",
"tokio",
"tokio-native-tls",
"tokio-rustls",
"tokio-util",
"tower",
+ "tower-http",
"tower-service",
"url",
"wasm-bindgen",
@@ -5246,7 +5327,6 @@ dependencies = [
"wasm-streams",
"web-sys",
"webpki-roots",
- "windows-registry",
]
[[package]]
@@ -5277,13 +5357,13 @@ dependencies = [
[[package]]
name = "ring"
-version = "0.17.13"
+version = "0.17.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70ac5d832aa16abd7d1def883a8545280c20a60f523a370aa3a9617c2b8550ee"
+checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
dependencies = [
"cc",
"cfg-if",
- "getrandom 0.2.15",
+ "getrandom 0.2.16",
"libc",
"untrusted",
"windows-sys 0.52.0",
@@ -5296,7 +5376,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94"
dependencies = [
"base64 0.21.7",
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
"serde",
"serde_derive",
]
@@ -5309,9 +5389,9 @@ checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97"
[[package]]
name = "rustc-demangle"
-version = "0.1.24"
+version = "0.1.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
+checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f"
[[package]]
name = "rustc-hash"
@@ -5340,7 +5420,7 @@ version = "0.38.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
"errno",
"libc",
"linux-raw-sys 0.4.15",
@@ -5349,22 +5429,22 @@ dependencies = [
[[package]]
name = "rustix"
-version = "1.0.1"
+version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dade4812df5c384711475be5fcd8c162555352945401aed22a35bffeab61f657"
+checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266"
dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
"errno",
"libc",
- "linux-raw-sys 0.9.2",
+ "linux-raw-sys 0.9.4",
"windows-sys 0.59.0",
]
[[package]]
name = "rustls"
-version = "0.23.23"
+version = "0.23.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "47796c98c480fce5406ef69d1c76378375492c3b0a0de587be0c1d9feb12f395"
+checksum = "7160e3e10bf4535308537f3c4e1641468cd0e485175d6163087c0393c7d46643"
dependencies = [
"once_cell",
"ring",
@@ -5374,29 +5454,21 @@ dependencies = [
"zeroize",
]
-[[package]]
-name = "rustls-pemfile"
-version = "2.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50"
-dependencies = [
- "rustls-pki-types",
-]
-
[[package]]
name = "rustls-pki-types"
-version = "1.11.0"
+version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c"
+checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79"
dependencies = [
"web-time 1.1.0",
+ "zeroize",
]
[[package]]
name = "rustls-webpki"
-version = "0.102.8"
+version = "0.103.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9"
+checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435"
dependencies = [
"ring",
"rustls-pki-types",
@@ -5405,9 +5477,9 @@ dependencies = [
[[package]]
name = "rustversion"
-version = "1.0.20"
+version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
+checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d"
[[package]]
name = "rustybuzz"
@@ -5415,7 +5487,7 @@ version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c85d1ccd519e61834798eb52c4e886e8c2d7d698dd3d6ce0b1b47eb8557f1181"
dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
"bytemuck",
"core_maths",
"log",
@@ -5466,6 +5538,30 @@ dependencies = [
"uuid",
]
+[[package]]
+name = "schemars"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f"
+dependencies = [
+ "dyn-clone",
+ "ref-cast",
+ "serde",
+ "serde_json",
+]
+
+[[package]]
+name = "schemars"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1375ba8ef45a6f15d83fa8748f1079428295d403d6ea991d09ab100155fbc06d"
+dependencies = [
+ "dyn-clone",
+ "ref-cast",
+ "serde",
+ "serde_json",
+]
+
[[package]]
name = "schemars_derive"
version = "0.8.22"
@@ -5475,7 +5571,7 @@ dependencies = [
"proc-macro2",
"quote",
"serde_derive_internals",
- "syn 2.0.99",
+ "syn 2.0.104",
]
[[package]]
@@ -5509,7 +5605,7 @@ version = "2.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
"core-foundation 0.9.4",
"core-foundation-sys",
"libc",
@@ -5528,22 +5624,20 @@ dependencies = [
[[package]]
name = "selectors"
-version = "0.22.0"
+version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "df320f1889ac4ba6bc0cdc9c9af7af4bd64bb927bccdf32d81140dc1f9be12fe"
+checksum = "0c37578180969d00692904465fb7f6b3d50b9a2b952b87c23d0e2e5cb5013416"
dependencies = [
"bitflags 1.3.2",
"cssparser",
"derive_more",
"fxhash",
"log",
- "matches",
"phf 0.8.0",
"phf_codegen 0.8.0",
"precomputed-hash",
"servo_arc",
"smallvec",
- "thin-slice",
]
[[package]]
@@ -5594,7 +5688,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.99",
+ "syn 2.0.104",
]
[[package]]
@@ -5605,7 +5699,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.99",
+ "syn 2.0.104",
]
[[package]]
@@ -5614,7 +5708,7 @@ version = "1.0.140"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
dependencies = [
- "itoa 1.0.15",
+ "itoa",
"memchr",
"ryu",
"serde",
@@ -5626,7 +5720,7 @@ version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59fab13f937fa393d08645bf3a84bdfe86e296747b506ada67bb15f10f218b2a"
dependencies = [
- "itoa 1.0.15",
+ "itoa",
"serde",
]
@@ -5638,14 +5732,14 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.99",
+ "syn 2.0.104",
]
[[package]]
name = "serde_spanned"
-version = "0.6.8"
+version = "0.6.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1"
+checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3"
dependencies = [
"serde",
]
@@ -5657,22 +5751,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
dependencies = [
"form_urlencoded",
- "itoa 1.0.15",
+ "itoa",
"ryu",
"serde",
]
[[package]]
name = "serde_with"
-version = "3.12.0"
+version = "3.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa"
+checksum = "f2c45cd61fefa9db6f254525d46e392b852e0e61d9a1fd36e5bd183450a556d5"
dependencies = [
"base64 0.22.1",
"chrono",
"hex",
"indexmap 1.9.3",
- "indexmap 2.7.1",
+ "indexmap 2.10.0",
+ "schemars 0.9.0",
+ "schemars 1.0.3",
"serde",
"serde_derive",
"serde_json",
@@ -5682,14 +5778,14 @@ dependencies = [
[[package]]
name = "serde_with_macros"
-version = "3.12.0"
+version = "3.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e"
+checksum = "de90945e6565ce0d9a25098082ed4ee4002e047cb59892c318d66821e14bb30f"
dependencies = [
"darling",
"proc-macro2",
"quote",
- "syn 2.0.99",
+ "syn 2.0.104",
]
[[package]]
@@ -5716,9 +5812,9 @@ dependencies = [
[[package]]
name = "servo_arc"
-version = "0.1.1"
+version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d98238b800e0d1576d8b6e3de32827c2d74bee68bb97748dcf5071fb53965432"
+checksum = "d52aa42f8fdf0fed91e5ce7f23d8138441002fa31dca008acf47e6fd4721f741"
dependencies = [
"nodrop",
"stable_deref_trait",
@@ -5726,9 +5822,9 @@ dependencies = [
[[package]]
name = "sha2"
-version = "0.10.8"
+version = "0.10.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
+checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
dependencies = [
"cfg-if",
"cpufeatures",
@@ -5737,12 +5833,13 @@ dependencies = [
[[package]]
name = "shared_child"
-version = "1.0.1"
+version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09fa9338aed9a1df411814a5b2252f7cd206c55ae9bf2fa763f8de84603aa60c"
+checksum = "c2778001df1384cf20b6dc5a5a90f48da35539885edaaefd887f8d744e939c0b"
dependencies = [
"libc",
- "windows-sys 0.59.0",
+ "sigchld",
+ "windows-sys 0.60.2",
]
[[package]]
@@ -5751,6 +5848,36 @@ version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+[[package]]
+name = "sigchld"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1219ef50fc0fdb04fcc243e6aa27f855553434ffafe4fa26554efb78b5b4bf89"
+dependencies = [
+ "libc",
+ "os_pipe",
+ "signal-hook",
+]
+
+[[package]]
+name = "signal-hook"
+version = "0.3.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2"
+dependencies = [
+ "libc",
+ "signal-hook-registry",
+]
+
+[[package]]
+name = "signal-hook-registry"
+version = "1.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410"
+dependencies = [
+ "libc",
+]
+
[[package]]
name = "simd-adler32"
version = "0.3.7"
@@ -5819,12 +5946,9 @@ dependencies = [
[[package]]
name = "slab"
-version = "0.4.9"
+version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
-dependencies = [
- "autocfg",
-]
+checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d"
[[package]]
name = "slotmap"
@@ -5850,7 +5974,7 @@ version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "922fd3eeab3bd820d76537ce8f582b1cf951eceb5475c28500c7457d9d17f53a"
dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
"calloop",
"calloop-wayland-source",
"cursor-icon",
@@ -5880,9 +6004,9 @@ dependencies = [
[[package]]
name = "socket2"
-version = "0.5.8"
+version = "0.5.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8"
+checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678"
dependencies = [
"libc",
"windows-sys 0.52.0",
@@ -5904,7 +6028,7 @@ dependencies = [
"objc2-foundation 0.2.2",
"objc2-quartz-core 0.2.2",
"raw-window-handle",
- "redox_syscall 0.5.10",
+ "redox_syscall 0.5.13",
"wasm-bindgen",
"web-sys",
"windows-sys 0.59.0",
@@ -5956,7 +6080,7 @@ dependencies = [
"Inflector",
"proc-macro2",
"quote",
- "syn 2.0.99",
+ "syn 2.0.104",
]
[[package]]
@@ -5974,7 +6098,7 @@ version = "0.3.0+sdk-1.3.268.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844"
dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
]
[[package]]
@@ -6043,9 +6167,9 @@ checksum = "94afda9cd163c04f6bee8b4bf2501c91548deae308373c436f36aeff3cf3c4a3"
[[package]]
name = "svg_fmt"
-version = "0.4.4"
+version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce5d813d71d82c4cbc1742135004e4a79fd870214c155443451c139c9470a0aa"
+checksum = "0193cc4331cfd2f3d2011ef287590868599a2f33c3e69bc22c1a3d3acf9e02fb"
[[package]]
name = "svgtypes"
@@ -6092,9 +6216,9 @@ dependencies = [
[[package]]
name = "syn"
-version = "2.0.99"
+version = "2.0.104"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e02e925281e18ffd9d640e234264753c43edc62d64b2d4cf898f1bc5e75f3fc2"
+checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40"
dependencies = [
"proc-macro2",
"quote",
@@ -6112,13 +6236,13 @@ dependencies = [
[[package]]
name = "synstructure"
-version = "0.13.1"
+version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
+checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.99",
+ "syn 2.0.104",
]
[[package]]
@@ -6127,7 +6251,7 @@ version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b"
dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
"core-foundation 0.9.4",
"system-configuration-sys",
]
@@ -6157,12 +6281,12 @@ dependencies = [
[[package]]
name = "tao"
-version = "0.32.8"
+version = "0.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "63c8b1020610b9138dd7b1e06cf259ae91aa05c30f3bd0d6b42a03997b92dec1"
+checksum = "49c380ca75a231b87b6c9dd86948f035012e7171d1a7c40a9c2890489a7ffd8a"
dependencies = [
- "bitflags 2.9.0",
- "core-foundation 0.10.0",
+ "bitflags 2.9.1",
+ "core-foundation 0.10.1",
"core-graphics 0.24.0",
"crossbeam-channel",
"dispatch",
@@ -6188,8 +6312,8 @@ dependencies = [
"tao-macros",
"unicode-segmentation",
"url",
- "windows 0.60.0",
- "windows-core 0.60.1",
+ "windows 0.61.3",
+ "windows-core 0.61.2",
"windows-version",
"x11-dl",
]
@@ -6202,7 +6326,7 @@ checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.99",
+ "syn 2.0.104",
]
[[package]]
@@ -6213,17 +6337,16 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
[[package]]
name = "tauri"
-version = "2.4.1"
+version = "2.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d08db1ff9e011e04014e737ec022610d756c0eae0b3b3a9037bccaf3003173a"
+checksum = "124e129c9c0faa6bec792c5948c89e86c90094133b0b9044df0ce5f0a8efaa0d"
dependencies = [
"anyhow",
"bytes",
"dirs",
"dunce",
"embed_plist",
- "futures-util",
- "getrandom 0.2.15",
+ "getrandom 0.3.3",
"glob",
"gtk",
"heck 0.5.0",
@@ -6236,6 +6359,7 @@ dependencies = [
"objc2 0.6.1",
"objc2-app-kit",
"objc2-foundation 0.3.1",
+ "objc2-ui-kit",
"percent-encoding",
"plist",
"raw-window-handle",
@@ -6258,14 +6382,14 @@ dependencies = [
"webkit2gtk",
"webview2-com",
"window-vibrancy",
- "windows 0.60.0",
+ "windows 0.61.3",
]
[[package]]
name = "tauri-build"
-version = "2.1.1"
+version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fd20e4661c2cce65343319e6e8da256958f5af958cafc47c0d0af66a55dcd17"
+checksum = "12f025c389d3adb83114bec704da973142e82fc6ec799c7c750c5e21cefaec83"
dependencies = [
"anyhow",
"cargo_toml",
@@ -6273,7 +6397,7 @@ dependencies = [
"glob",
"heck 0.5.0",
"json-patch",
- "schemars",
+ "schemars 0.8.22",
"semver",
"serde",
"serde_json",
@@ -6285,9 +6409,9 @@ dependencies = [
[[package]]
name = "tauri-codegen"
-version = "2.1.1"
+version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "458258b19032450ccf975840116ecf013e539eadbb74420bd890e8c56ab2b1a4"
+checksum = "f5df493a1075a241065bc865ed5ef8d0fbc1e76c7afdc0bf0eccfaa7d4f0e406"
dependencies = [
"base64 0.22.1",
"brotli",
@@ -6301,7 +6425,7 @@ dependencies = [
"serde",
"serde_json",
"sha2",
- "syn 2.0.99",
+ "syn 2.0.104",
"tauri-utils",
"thiserror 2.0.12",
"time",
@@ -6312,28 +6436,28 @@ dependencies = [
[[package]]
name = "tauri-macros"
-version = "2.1.1"
+version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d402813d3b9c773a0fa58697c457c771f10e735498fdcb7b343264d18e5a601f"
+checksum = "f237fbea5866fa5f2a60a21bea807a2d6e0379db070d89c3a10ac0f2d4649bbc"
dependencies = [
"heck 0.5.0",
"proc-macro2",
"quote",
- "syn 2.0.99",
+ "syn 2.0.104",
"tauri-codegen",
"tauri-utils",
]
[[package]]
name = "tauri-plugin"
-version = "2.1.1"
+version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4190775d6ff73fe66d9af44c012739a2659720efd9c0e1e56a918678038699d"
+checksum = "1d9a0bd00bf1930ad1a604d08b0eb6b2a9c1822686d65d7f4731a7723b8901d3"
dependencies = [
"anyhow",
"glob",
"plist",
- "schemars",
+ "schemars 0.8.22",
"serde",
"serde_json",
"tauri-utils",
@@ -6343,15 +6467,15 @@ dependencies = [
[[package]]
name = "tauri-plugin-fs"
-version = "2.2.1"
+version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "88371e340ad2f07409a3b68294abe73f20bc9c1bc1b631a31dc37a3d0161f682"
+checksum = "c341290d31991dbca38b31d412c73dfbdb070bb11536784f19dd2211d13b778f"
dependencies = [
"anyhow",
"dunce",
"glob",
"percent-encoding",
- "schemars",
+ "schemars 0.8.22",
"serde",
"serde_json",
"serde_repr",
@@ -6361,14 +6485,13 @@ dependencies = [
"thiserror 2.0.12",
"toml",
"url",
- "uuid",
]
[[package]]
name = "tauri-plugin-http"
-version = "2.4.3"
+version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "40dcd6c922a1885e1f0bcebc6768fec6e005bd4b9001c5d90a2f5d4cab297729"
+checksum = "b0c1a38da944b357ffa23bafd563b1579f18e6fbd118fcd84769406d35dcc5c7"
dependencies = [
"bytes",
"cookie_store",
@@ -6376,7 +6499,7 @@ dependencies = [
"http",
"regex",
"reqwest",
- "schemars",
+ "schemars 0.8.22",
"serde",
"serde_json",
"tauri",
@@ -6390,16 +6513,16 @@ dependencies = [
[[package]]
name = "tauri-plugin-shell"
-version = "2.2.1"
+version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "69d5eb3368b959937ad2aeaf6ef9a8f5d11e01ffe03629d3530707bbcb27ff5d"
+checksum = "2b9ffadec5c3523f11e8273465cacb3d86ea7652a28e6e2a2e9b5c182f791d25"
dependencies = [
"encoding_rs",
"log",
"open",
"os_pipe",
"regex",
- "schemars",
+ "schemars 0.8.22",
"serde",
"serde_json",
"shared_child",
@@ -6411,29 +6534,31 @@ dependencies = [
[[package]]
name = "tauri-runtime"
-version = "2.5.1"
+version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "00ada7ac2f9276f09b8c3afffd3215fd5d9bff23c22df8a7c70e7ef67cacd532"
+checksum = "9e7bb73d1bceac06c20b3f755b2c8a2cb13b20b50083084a8cf3700daf397ba4"
dependencies = [
"cookie",
"dpi",
"gtk",
"http",
"jni",
+ "objc2 0.6.1",
+ "objc2-ui-kit",
"raw-window-handle",
"serde",
"serde_json",
"tauri-utils",
"thiserror 2.0.12",
"url",
- "windows 0.60.0",
+ "windows 0.61.3",
]
[[package]]
name = "tauri-runtime-wry"
-version = "2.5.1"
+version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf2e5842c57e154af43a20a49c7efee0ce2578c20b4c2bdf266852b422d2e421"
+checksum = "902b5aa9035e16f342eb64f8bf06ccdc2808e411a2525ed1d07672fa4e780bad"
dependencies = [
"gtk",
"http",
@@ -6452,15 +6577,15 @@ dependencies = [
"url",
"webkit2gtk",
"webview2-com",
- "windows 0.60.0",
+ "windows 0.61.3",
"wry",
]
[[package]]
name = "tauri-utils"
-version = "2.3.1"
+version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1f037e66c7638cc0a2213f61566932b9a06882b8346486579c90e4b019bac447"
+checksum = "41743bbbeb96c3a100d234e5a0b60a46d5aa068f266160862c7afdbf828ca02e"
dependencies = [
"anyhow",
"brotli",
@@ -6479,7 +6604,7 @@ dependencies = [
"proc-macro2",
"quote",
"regex",
- "schemars",
+ "schemars 0.8.22",
"semver",
"serde",
"serde-untagged",
@@ -6496,25 +6621,25 @@ dependencies = [
[[package]]
name = "tauri-winres"
-version = "0.3.0"
+version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "56eaa45f707bedf34d19312c26d350bc0f3c59a47e58e8adbeecdc850d2c13a0"
+checksum = "e8d321dbc6f998d825ab3f0d62673e810c861aac2d0de2cc2c395328f1d113b4"
dependencies = [
"embed-resource",
+ "indexmap 2.10.0",
"toml",
]
[[package]]
name = "tempfile"
-version = "3.18.0"
+version = "3.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2c317e0a526ee6120d8dabad239c8dadca62b24b6f168914bbbc8e2fb1f0e567"
+checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1"
dependencies = [
- "cfg-if",
"fastrand",
- "getrandom 0.3.1",
+ "getrandom 0.3.3",
"once_cell",
- "rustix 1.0.1",
+ "rustix 1.0.7",
"windows-sys 0.59.0",
]
@@ -6538,12 +6663,6 @@ dependencies = [
"winapi-util",
]
-[[package]]
-name = "thin-slice"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c"
-
[[package]]
name = "thiserror"
version = "1.0.69"
@@ -6570,7 +6689,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.99",
+ "syn 2.0.104",
]
[[package]]
@@ -6581,7 +6700,7 @@ checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.99",
+ "syn 2.0.104",
]
[[package]]
@@ -6602,7 +6721,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40"
dependencies = [
"deranged",
- "itoa 1.0.15",
+ "itoa",
"num-conv",
"powerfmt",
"serde",
@@ -6657,6 +6776,15 @@ name = "tinystr"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f"
+dependencies = [
+ "displaydoc",
+]
+
+[[package]]
+name = "tinystr"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b"
dependencies = [
"displaydoc",
"zerovec",
@@ -6689,9 +6817,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "tokio"
-version = "1.45.0"
+version = "1.45.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165"
+checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779"
dependencies = [
"backtrace",
"bytes",
@@ -6711,7 +6839,7 @@ checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.99",
+ "syn 2.0.104",
]
[[package]]
@@ -6736,9 +6864,9 @@ dependencies = [
[[package]]
name = "tokio-util"
-version = "0.7.13"
+version = "0.7.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078"
+checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df"
dependencies = [
"bytes",
"futures-core",
@@ -6749,21 +6877,21 @@ dependencies = [
[[package]]
name = "toml"
-version = "0.8.20"
+version = "0.8.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148"
+checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362"
dependencies = [
"serde",
"serde_spanned",
"toml_datetime",
- "toml_edit 0.22.24",
+ "toml_edit 0.22.27",
]
[[package]]
name = "toml_datetime"
-version = "0.6.8"
+version = "0.6.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
+checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c"
dependencies = [
"serde",
]
@@ -6774,7 +6902,7 @@ version = "0.19.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
dependencies = [
- "indexmap 2.7.1",
+ "indexmap 2.10.0",
"toml_datetime",
"winnow 0.5.40",
]
@@ -6785,24 +6913,31 @@ version = "0.20.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81"
dependencies = [
- "indexmap 2.7.1",
+ "indexmap 2.10.0",
"toml_datetime",
"winnow 0.5.40",
]
[[package]]
name = "toml_edit"
-version = "0.22.24"
+version = "0.22.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474"
+checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a"
dependencies = [
- "indexmap 2.7.1",
+ "indexmap 2.10.0",
"serde",
"serde_spanned",
"toml_datetime",
- "winnow 0.7.3",
+ "toml_write",
+ "winnow 0.7.11",
]
+[[package]]
+name = "toml_write"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801"
+
[[package]]
name = "tower"
version = "0.5.2"
@@ -6819,6 +6954,24 @@ dependencies = [
"tracing",
]
+[[package]]
+name = "tower-http"
+version = "0.6.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2"
+dependencies = [
+ "bitflags 2.9.1",
+ "bytes",
+ "futures-util",
+ "http",
+ "http-body",
+ "iri-string",
+ "pin-project-lite",
+ "tower",
+ "tower-layer",
+ "tower-service",
+]
+
[[package]]
name = "tower-layer"
version = "0.3.3"
@@ -6844,18 +6997,18 @@ dependencies = [
[[package]]
name = "tracing-core"
-version = "0.1.33"
+version = "0.1.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c"
+checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678"
dependencies = [
"once_cell",
]
[[package]]
name = "tray-icon"
-version = "0.20.0"
+version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d433764348e7084bad2c5ea22c96c71b61b17afe3a11645710f533bd72b6a2b5"
+checksum = "2da75ec677957aa21f6e0b361df0daab972f13a5bee3606de0638fd4ee1c666a"
dependencies = [
"crossbeam-channel",
"dirs",
@@ -7076,12 +7229,6 @@ version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
-[[package]]
-name = "utf16_iter"
-version = "1.0.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246"
-
[[package]]
name = "utf8_iter"
version = "1.0.4"
@@ -7096,19 +7243,21 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "uuid"
-version = "1.16.0"
+version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9"
+checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d"
dependencies = [
- "getrandom 0.3.1",
+ "getrandom 0.3.3",
+ "js-sys",
"serde",
+ "wasm-bindgen",
]
[[package]]
name = "v_frame"
-version = "0.3.8"
+version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d6f32aaa24bacd11e488aa9ba66369c7cd514885742c9fe08cfe85884db3e92b"
+checksum = "666b7727c8875d6ab5db9533418d7c764233ac9c0cff1d469aec8fa127597be2"
dependencies = [
"aligned-vec",
"num-traits",
@@ -7221,15 +7370,15 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
[[package]]
name = "wasi"
-version = "0.11.0+wasi-snapshot-preview1"
+version = "0.11.1+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
[[package]]
name = "wasi"
-version = "0.13.3+wasi-0.2.2"
+version = "0.14.2+wasi-0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2"
+checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
dependencies = [
"wit-bindgen-rt",
]
@@ -7256,7 +7405,7 @@ dependencies = [
"log",
"proc-macro2",
"quote",
- "syn 2.0.99",
+ "syn 2.0.104",
"wasm-bindgen-shared",
]
@@ -7291,7 +7440,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.99",
+ "syn 2.0.104",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@@ -7320,9 +7469,9 @@ dependencies = [
[[package]]
name = "wayland-backend"
-version = "0.3.8"
+version = "0.3.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b7208998eaa3870dad37ec8836979581506e0c5c64c20c9e79e9d2a10d6f47bf"
+checksum = "fe770181423e5fc79d3e2a7f4410b7799d5aab1de4372853de3c6aa13ca24121"
dependencies = [
"cc",
"downcast-rs",
@@ -7334,11 +7483,11 @@ dependencies = [
[[package]]
name = "wayland-client"
-version = "0.31.8"
+version = "0.31.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c2120de3d33638aaef5b9f4472bff75f07c56379cf76ea320bd3a3d65ecaf73f"
+checksum = "978fa7c67b0847dbd6a9f350ca2569174974cd4082737054dbb7fbb79d7d9a61"
dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
"rustix 0.38.44",
"wayland-backend",
"wayland-scanner",
@@ -7350,16 +7499,16 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e"
dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
"cursor-icon",
"wayland-backend",
]
[[package]]
name = "wayland-cursor"
-version = "0.31.8"
+version = "0.31.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a93029cbb6650748881a00e4922b076092a6a08c11e7fbdb923f064b23968c5d"
+checksum = "a65317158dec28d00416cb16705934070aef4f8393353d41126c54264ae0f182"
dependencies = [
"rustix 0.38.44",
"wayland-client",
@@ -7372,7 +7521,7 @@ version = "0.31.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f81f365b8b4a97f422ac0e8737c438024b5951734506b0e1d775c73030561f4"
dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
"wayland-backend",
"wayland-client",
"wayland-scanner",
@@ -7384,7 +7533,7 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23803551115ff9ea9bce586860c5c5a971e360825a0309264102a9495a5ff479"
dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
"wayland-backend",
"wayland-client",
"wayland-protocols",
@@ -7397,7 +7546,7 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad1f61b76b6c2d8742e10f9ba5c3737f6530b4c243132c2a2ccc8aa96fe25cd6"
dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
"wayland-backend",
"wayland-client",
"wayland-protocols",
@@ -7411,7 +7560,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "896fdafd5d28145fce7958917d69f2fd44469b1d4e861cb5961bcbeebc6d1484"
dependencies = [
"proc-macro2",
- "quick-xml 0.37.2",
+ "quick-xml",
"quote",
]
@@ -7503,24 +7652,24 @@ dependencies = [
[[package]]
name = "webpki-roots"
-version = "0.26.8"
+version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2210b291f7ea53617fbafcc4939f10914214ec15aace5ba62293a668f322c5c9"
+checksum = "8782dd5a41a24eed3a4f40b606249b3e236ca61adf1f25ea4d45c73de122b502"
dependencies = [
"rustls-pki-types",
]
[[package]]
name = "webview2-com"
-version = "0.36.0"
+version = "0.38.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b0d606f600e5272b514dbb66539dd068211cc20155be8d3958201b4b5bd79ed3"
+checksum = "d4ba622a989277ef3886dd5afb3e280e3dd6d974b766118950a08f8f678ad6a4"
dependencies = [
"webview2-com-macros",
"webview2-com-sys",
- "windows 0.60.0",
- "windows-core 0.60.1",
- "windows-implement 0.59.0",
+ "windows 0.61.3",
+ "windows-core 0.61.2",
+ "windows-implement 0.60.0",
"windows-interface 0.59.1",
]
@@ -7532,25 +7681,25 @@ checksum = "1d228f15bba3b9d56dde8bddbee66fa24545bd17b48d5128ccf4a8742b18e431"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.99",
+ "syn 2.0.104",
]
[[package]]
name = "webview2-com-sys"
-version = "0.36.0"
+version = "0.38.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bfb27fccd3c27f68e9a6af1bcf48c2d82534b8675b83608a4d81446d095a17ac"
+checksum = "36695906a1b53a3bf5c4289621efedac12b73eeb0b89e7e1a89b517302d5d75c"
dependencies = [
"thiserror 2.0.12",
- "windows 0.60.0",
- "windows-core 0.60.1",
+ "windows 0.61.3",
+ "windows-core 0.61.2",
]
[[package]]
name = "weezl"
-version = "0.1.8"
+version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082"
+checksum = "a751b3277700db47d3e574514de2eced5e54dc8a5436a3bf7a0b248b2cee16f3"
[[package]]
name = "wgpu"
@@ -7585,11 +7734,11 @@ checksum = "d63c3c478de8e7e01786479919c8769f62a22eec16788d8c2ac77ce2c132778a"
dependencies = [
"arrayvec",
"bit-vec",
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
"bytemuck",
"cfg_aliases 0.1.1",
"document-features",
- "indexmap 2.7.1",
+ "indexmap 2.10.0",
"log",
"naga",
"once_cell",
@@ -7631,7 +7780,7 @@ dependencies = [
"arrayvec",
"ash",
"bit-set",
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
"block",
"bytemuck",
"cfg_aliases 0.1.1",
@@ -7644,7 +7793,7 @@ dependencies = [
"js-sys",
"khronos-egl",
"libc",
- "libloading 0.8.6",
+ "libloading 0.8.8",
"log",
"metal",
"naga",
@@ -7672,7 +7821,7 @@ version = "23.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "610f6ff27778148c31093f3b03abc4840f9636d58d597ca2f5977433acfe0068"
dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
"js-sys",
"web-sys",
]
@@ -7735,12 +7884,12 @@ dependencies = [
[[package]]
name = "windows"
-version = "0.60.0"
+version = "0.61.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ddf874e74c7a99773e62b1c671427abf01a425e77c3d3fb9fb1e4883ea934529"
+checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893"
dependencies = [
"windows-collections",
- "windows-core 0.60.1",
+ "windows-core 0.61.2",
"windows-future",
"windows-link",
"windows-numerics",
@@ -7748,20 +7897,11 @@ dependencies = [
[[package]]
name = "windows-collections"
-version = "0.1.1"
+version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5467f79cc1ba3f52ebb2ed41dbb459b8e7db636cc3429458d9a852e15bc24dec"
+checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8"
dependencies = [
- "windows-core 0.60.1",
-]
-
-[[package]]
-name = "windows-core"
-version = "0.52.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
-dependencies = [
- "windows-targets 0.52.6",
+ "windows-core 0.61.2",
]
[[package]]
@@ -7779,25 +7919,26 @@ dependencies = [
[[package]]
name = "windows-core"
-version = "0.60.1"
+version = "0.61.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca21a92a9cae9bf4ccae5cf8368dce0837100ddf6e6d57936749e85f152f6247"
+checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3"
dependencies = [
- "windows-implement 0.59.0",
+ "windows-implement 0.60.0",
"windows-interface 0.59.1",
"windows-link",
- "windows-result 0.3.1",
- "windows-strings 0.3.1",
+ "windows-result 0.3.4",
+ "windows-strings 0.4.2",
]
[[package]]
name = "windows-future"
-version = "0.1.1"
+version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a787db4595e7eb80239b74ce8babfb1363d8e343ab072f2ffe901400c03349f0"
+checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e"
dependencies = [
- "windows-core 0.60.1",
+ "windows-core 0.61.2",
"windows-link",
+ "windows-threading",
]
[[package]]
@@ -7808,18 +7949,18 @@ checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.99",
+ "syn 2.0.104",
]
[[package]]
name = "windows-implement"
-version = "0.59.0"
+version = "0.60.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "83577b051e2f49a058c308f17f273b570a6a758386fc291b5f6a934dd84e48c1"
+checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.99",
+ "syn 2.0.104",
]
[[package]]
@@ -7830,7 +7971,7 @@ checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.99",
+ "syn 2.0.104",
]
[[package]]
@@ -7841,34 +7982,34 @@ checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.99",
+ "syn 2.0.104",
]
[[package]]
name = "windows-link"
-version = "0.1.0"
+version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6dccfd733ce2b1753b03b6d3c65edf020262ea35e20ccdf3e288043e6dd620e3"
+checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a"
[[package]]
name = "windows-numerics"
-version = "0.1.1"
+version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "005dea54e2f6499f2cee279b8f703b3cf3b5734a2d8d21867c8f44003182eeed"
+checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1"
dependencies = [
- "windows-core 0.60.1",
+ "windows-core 0.61.2",
"windows-link",
]
[[package]]
name = "windows-registry"
-version = "0.2.0"
+version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0"
+checksum = "5b8a9ed28765efc97bbc954883f4e6796c33a06546ebafacbabee9696967499e"
dependencies = [
- "windows-result 0.2.0",
- "windows-strings 0.1.0",
- "windows-targets 0.52.6",
+ "windows-link",
+ "windows-result 0.3.4",
+ "windows-strings 0.4.2",
]
[[package]]
@@ -7882,9 +8023,9 @@ dependencies = [
[[package]]
name = "windows-result"
-version = "0.3.1"
+version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "06374efe858fab7e4f881500e6e86ec8bc28f9462c47e5a9941a0142ad86b189"
+checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6"
dependencies = [
"windows-link",
]
@@ -7901,9 +8042,9 @@ dependencies = [
[[package]]
name = "windows-strings"
-version = "0.3.1"
+version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319"
+checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57"
dependencies = [
"windows-link",
]
@@ -7944,6 +8085,15 @@ dependencies = [
"windows-targets 0.52.6",
]
+[[package]]
+name = "windows-sys"
+version = "0.60.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
+dependencies = [
+ "windows-targets 0.53.2",
+]
+
[[package]]
name = "windows-targets"
version = "0.42.2"
@@ -7983,7 +8133,7 @@ dependencies = [
"windows_aarch64_gnullvm 0.52.6",
"windows_aarch64_msvc 0.52.6",
"windows_i686_gnu 0.52.6",
- "windows_i686_gnullvm",
+ "windows_i686_gnullvm 0.52.6",
"windows_i686_msvc 0.52.6",
"windows_x86_64_gnu 0.52.6",
"windows_x86_64_gnullvm 0.52.6",
@@ -7991,10 +8141,35 @@ dependencies = [
]
[[package]]
-name = "windows-version"
-version = "0.1.3"
+name = "windows-targets"
+version = "0.53.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7bfbcc4996dd183ff1376a20ade1242da0d2dcaff83cc76710a588d24fd4c5db"
+checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef"
+dependencies = [
+ "windows_aarch64_gnullvm 0.53.0",
+ "windows_aarch64_msvc 0.53.0",
+ "windows_i686_gnu 0.53.0",
+ "windows_i686_gnullvm 0.53.0",
+ "windows_i686_msvc 0.53.0",
+ "windows_x86_64_gnu 0.53.0",
+ "windows_x86_64_gnullvm 0.53.0",
+ "windows_x86_64_msvc 0.53.0",
+]
+
+[[package]]
+name = "windows-threading"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "windows-version"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e04a5c6627e310a23ad2358483286c7df260c964eb2d003d8efd6d0f4e79265c"
dependencies = [
"windows-link",
]
@@ -8017,6 +8192,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764"
+
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.2"
@@ -8035,6 +8216,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c"
+
[[package]]
name = "windows_i686_gnu"
version = "0.42.2"
@@ -8053,12 +8240,24 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+[[package]]
+name = "windows_i686_gnu"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3"
+
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11"
+
[[package]]
name = "windows_i686_msvc"
version = "0.42.2"
@@ -8077,6 +8276,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+[[package]]
+name = "windows_i686_msvc"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d"
+
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.2"
@@ -8095,6 +8300,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba"
+
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.2"
@@ -8113,6 +8324,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57"
+
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.2"
@@ -8131,6 +8348,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486"
+
[[package]]
name = "winit"
version = "0.29.15"
@@ -8140,7 +8363,7 @@ dependencies = [
"ahash",
"android-activity",
"atomic-waker",
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
"bytemuck",
"calloop",
"cfg_aliases 0.1.1",
@@ -8190,38 +8413,32 @@ dependencies = [
[[package]]
name = "winnow"
-version = "0.7.3"
+version = "0.7.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0e7f4ea97f6f78012141bcdb6a216b2609f0979ada50b20ca5b52dde2eac2bb1"
+checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd"
dependencies = [
"memchr",
]
[[package]]
name = "winreg"
-version = "0.52.0"
+version = "0.55.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5"
+checksum = "cb5a765337c50e9ec252c2069be9bf91c7df47afb103b642ba3a53bf8101be97"
dependencies = [
"cfg-if",
- "windows-sys 0.48.0",
+ "windows-sys 0.59.0",
]
[[package]]
name = "wit-bindgen-rt"
-version = "0.33.0"
+version = "0.39.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c"
+checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
]
-[[package]]
-name = "write16"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936"
-
[[package]]
name = "writeable"
version = "0.5.5"
@@ -8229,10 +8446,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
[[package]]
-name = "wry"
-version = "0.50.5"
+name = "writeable"
+version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b19b78efae8b853c6c817e8752fc1dbf9cab8a8ffe9c30f399bd750ccf0f0730"
+checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb"
+
+[[package]]
+name = "wry"
+version = "0.52.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "12a714d9ba7075aae04a6e50229d6109e3d584774b99a6a8c60de1698ca111b9"
dependencies = [
"base64 0.22.1",
"block2 0.6.1",
@@ -8266,8 +8489,8 @@ dependencies = [
"webkit2gtk",
"webkit2gtk-sys",
"webview2-com",
- "windows 0.60.0",
- "windows-core 0.60.1",
+ "windows 0.61.3",
+ "windows-core 0.61.2",
"windows-version",
"x11-dl",
]
@@ -8302,7 +8525,7 @@ dependencies = [
"as-raw-xcb-connection",
"gethostname",
"libc",
- "libloading 0.8.6",
+ "libloading 0.8.8",
"once_cell",
"rustix 0.38.44",
"x11rb-protocol",
@@ -8316,9 +8539,9 @@ checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d"
[[package]]
name = "xcursor"
-version = "0.3.8"
+version = "0.3.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ef33da6b1660b4ddbfb3aef0ade110c8b8a781a3b6382fa5f2b5b040fd55f61"
+checksum = "bec9e4a500ca8864c5b47b8b482a73d62e4237670e5b5f1d6b9e3cae50f28f2b"
[[package]]
name = "xkbcommon-dl"
@@ -8326,7 +8549,7 @@ version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5"
dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
"dlib",
"log",
"once_cell",
@@ -8341,9 +8564,9 @@ checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56"
[[package]]
name = "xml-rs"
-version = "0.8.25"
+version = "0.8.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c5b940ebc25896e71dd073bad2dbaa2abfe97b0a391415e22ad1326d9c54e3c4"
+checksum = "a62ce76d9b56901b19a74f19431b0d8b3bc7ca4ad685a746dfd78ca8f4fc6bda"
[[package]]
name = "xmlwriter"
@@ -8365,9 +8588,9 @@ checksum = "e01738255b5a16e78bbb83e7fbba0a1e7dd506905cfc53f4622d89015a03fbb5"
[[package]]
name = "yoke"
-version = "0.7.5"
+version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40"
+checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc"
dependencies = [
"serde",
"stable_deref_trait",
@@ -8377,13 +8600,13 @@ dependencies = [
[[package]]
name = "yoke-derive"
-version = "0.7.5"
+version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154"
+checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.99",
+ "syn 2.0.104",
"synstructure",
]
@@ -8395,43 +8618,22 @@ checksum = "6df3dc4292935e51816d896edcd52aa30bc297907c26167fec31e2b0c6a32524"
[[package]]
name = "zerocopy"
-version = "0.7.35"
+version = "0.8.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
+checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f"
dependencies = [
- "byteorder",
- "zerocopy-derive 0.7.35",
-]
-
-[[package]]
-name = "zerocopy"
-version = "0.8.23"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fd97444d05a4328b90e75e503a34bad781f14e28a823ad3557f0750df1ebcbc6"
-dependencies = [
- "zerocopy-derive 0.8.23",
+ "zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
-version = "0.7.35"
+version = "0.8.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
+checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.99",
-]
-
-[[package]]
-name = "zerocopy-derive"
-version = "0.8.23"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6352c01d0edd5db859a63e2605f4ea3183ddbd15e2c4a9e7d32184df75e4f154"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.99",
+ "syn 2.0.104",
]
[[package]]
@@ -8451,7 +8653,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.99",
+ "syn 2.0.104",
"synstructure",
]
@@ -8462,10 +8664,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
[[package]]
-name = "zerovec"
-version = "0.10.4"
+name = "zerotrie"
+version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079"
+checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595"
+dependencies = [
+ "displaydoc",
+ "yoke",
+ "zerofrom",
+]
+
+[[package]]
+name = "zerovec"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428"
dependencies = [
"yoke",
"zerofrom",
@@ -8474,13 +8687,13 @@ dependencies = [
[[package]]
name = "zerovec-derive"
-version = "0.10.3"
+version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
+checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.99",
+ "syn 2.0.104",
]
[[package]]
@@ -8500,9 +8713,9 @@ dependencies = [
[[package]]
name = "zune-jpeg"
-version = "0.4.14"
+version = "0.4.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "99a5bab8d7dedf81405c4bb1f2b83ea057643d9cb28778cea9eecddeedd2e028"
+checksum = "7384255a918371b5af158218d131530f694de9ad3815ebdd0453a940485cb0fa"
dependencies = [
"zune-core",
]
diff --git a/editor/src/consts.rs b/editor/src/consts.rs
index 9adba6d908..58585e2dab 100644
--- a/editor/src/consts.rs
+++ b/editor/src/consts.rs
@@ -61,6 +61,7 @@ pub const SELECTION_DRAG_ANGLE: f64 = 90.;
pub const PIVOT_CROSSHAIR_THICKNESS: f64 = 1.;
pub const PIVOT_CROSSHAIR_LENGTH: f64 = 9.;
pub const PIVOT_DIAMETER: f64 = 5.;
+pub const DOWEL_PIN_RADIUS: f64 = 4.;
// COMPASS ROSE
pub const COMPASS_ROSE_RING_INNER_DIAMETER: f64 = 13.;
@@ -133,8 +134,8 @@ pub const SCALE_EFFECT: f64 = 0.5;
// COLORS
pub const COLOR_OVERLAY_BLUE: &str = "#00a8ff";
-pub const COLOR_OVERLAY_BLUE_50: &str = "rgba(0, 168, 255, 0.5)";
pub const COLOR_OVERLAY_YELLOW: &str = "#ffc848";
+pub const COLOR_OVERLAY_YELLOW_DULL: &str = "#d7ba8b";
pub const COLOR_OVERLAY_GREEN: &str = "#63ce63";
pub const COLOR_OVERLAY_RED: &str = "#ef5454";
pub const COLOR_OVERLAY_GRAY: &str = "#cccccc";
diff --git a/editor/src/dispatcher.rs b/editor/src/dispatcher.rs
index a8891033ee..9408d7d927 100644
--- a/editor/src/dispatcher.rs
+++ b/editor/src/dispatcher.rs
@@ -140,6 +140,7 @@ impl Dispatcher {
let graphene_std::renderer::RenderMetadata {
upstream_footprints: footprints,
local_transforms,
+ first_instance_source_id,
click_targets,
clip_targets,
} = render_metadata;
@@ -149,6 +150,7 @@ impl Dispatcher {
DocumentMessage::UpdateUpstreamTransforms {
upstream_footprints: footprints,
local_transforms,
+ first_instance_source_id,
},
DocumentMessage::UpdateClickTargets { click_targets },
DocumentMessage::UpdateClipTargets { clip_targets },
diff --git a/editor/src/lib.rs b/editor/src/lib.rs
index 80d80b5305..2c59945136 100644
--- a/editor/src/lib.rs
+++ b/editor/src/lib.rs
@@ -15,3 +15,4 @@ pub mod node_graph_executor;
#[cfg(test)]
pub mod test_utils;
pub mod utility_traits;
+pub mod utility_types;
diff --git a/editor/src/messages/animation/animation_message_handler.rs b/editor/src/messages/animation/animation_message_handler.rs
index eb7ceba2e0..211d22c87c 100644
--- a/editor/src/messages/animation/animation_message_handler.rs
+++ b/editor/src/messages/animation/animation_message_handler.rs
@@ -24,7 +24,7 @@ enum AnimationState {
},
}
-#[derive(Default, Debug, Clone, PartialEq)]
+#[derive(Default, Debug, Clone, PartialEq, ExtractField)]
pub struct AnimationMessageHandler {
/// Used to re-send the UI on the next frame after playback starts
live_preview_recently_zero: bool,
@@ -57,6 +57,7 @@ impl AnimationMessageHandler {
}
}
+#[message_handler_data]
impl MessageHandler for AnimationMessageHandler {
fn process_message(&mut self, message: AnimationMessage, responses: &mut VecDeque, _data: ()) {
match message {
diff --git a/editor/src/messages/broadcast/broadcast_message_handler.rs b/editor/src/messages/broadcast/broadcast_message_handler.rs
index 51d64b5852..489df47ab7 100644
--- a/editor/src/messages/broadcast/broadcast_message_handler.rs
+++ b/editor/src/messages/broadcast/broadcast_message_handler.rs
@@ -1,10 +1,11 @@
use crate::messages::prelude::*;
-#[derive(Debug, Clone, Default)]
+#[derive(Debug, Clone, Default, ExtractField)]
pub struct BroadcastMessageHandler {
listeners: HashMap>,
}
+#[message_handler_data]
impl MessageHandler for BroadcastMessageHandler {
fn process_message(&mut self, message: BroadcastMessage, responses: &mut VecDeque, _data: ()) {
match message {
diff --git a/editor/src/messages/debug/debug_message_handler.rs b/editor/src/messages/debug/debug_message_handler.rs
index 6044ce9108..064ad2510c 100644
--- a/editor/src/messages/debug/debug_message_handler.rs
+++ b/editor/src/messages/debug/debug_message_handler.rs
@@ -1,11 +1,12 @@
use super::utility_types::MessageLoggingVerbosity;
use crate::messages::prelude::*;
-#[derive(Debug, Default)]
+#[derive(Debug, Default, ExtractField)]
pub struct DebugMessageHandler {
pub message_logging_verbosity: MessageLoggingVerbosity,
}
+#[message_handler_data]
impl MessageHandler for DebugMessageHandler {
fn process_message(&mut self, message: DebugMessage, responses: &mut VecDeque, _data: ()) {
match message {
diff --git a/editor/src/messages/dialog/dialog_message_handler.rs b/editor/src/messages/dialog/dialog_message_handler.rs
index 3e9c80e46a..8e6bbde2f8 100644
--- a/editor/src/messages/dialog/dialog_message_handler.rs
+++ b/editor/src/messages/dialog/dialog_message_handler.rs
@@ -2,19 +2,21 @@ use super::simple_dialogs::{self, AboutGraphiteDialog, ComingSoonDialog, DemoArt
use crate::messages::layout::utility_types::widget_prelude::*;
use crate::messages::prelude::*;
+#[derive(ExtractField)]
pub struct DialogMessageData<'a> {
pub portfolio: &'a PortfolioMessageHandler,
pub preferences: &'a PreferencesMessageHandler,
}
/// Stores the dialogs which require state. These are the ones that have their own message handlers, and are not the ones defined in `simple_dialogs`.
-#[derive(Debug, Default, Clone)]
+#[derive(Debug, Default, Clone, ExtractField)]
pub struct DialogMessageHandler {
export_dialog: ExportDialogMessageHandler,
new_document_dialog: NewDocumentDialogMessageHandler,
preferences_dialog: PreferencesDialogMessageHandler,
}
+#[message_handler_data]
impl MessageHandler> for DialogMessageHandler {
fn process_message(&mut self, message: DialogMessage, responses: &mut VecDeque, data: DialogMessageData) {
let DialogMessageData { portfolio, preferences } = data;
diff --git a/editor/src/messages/dialog/export_dialog/export_dialog_message_handler.rs b/editor/src/messages/dialog/export_dialog/export_dialog_message_handler.rs
index 1bcf4b7003..179aab4f96 100644
--- a/editor/src/messages/dialog/export_dialog/export_dialog_message_handler.rs
+++ b/editor/src/messages/dialog/export_dialog/export_dialog_message_handler.rs
@@ -3,12 +3,13 @@ use crate::messages::layout::utility_types::widget_prelude::*;
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
use crate::messages::prelude::*;
+#[derive(ExtractField)]
pub struct ExportDialogMessageData<'a> {
pub portfolio: &'a PortfolioMessageHandler,
}
/// A dialog to allow users to customize their file export.
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, ExtractField)]
pub struct ExportDialogMessageHandler {
pub file_type: FileType,
pub scale_factor: f64,
@@ -31,6 +32,7 @@ impl Default for ExportDialogMessageHandler {
}
}
+#[message_handler_data]
impl MessageHandler> for ExportDialogMessageHandler {
fn process_message(&mut self, message: ExportDialogMessage, responses: &mut VecDeque, data: ExportDialogMessageData) {
let ExportDialogMessageData { portfolio } = data;
diff --git a/editor/src/messages/dialog/new_document_dialog/new_document_dialog_message_handler.rs b/editor/src/messages/dialog/new_document_dialog/new_document_dialog_message_handler.rs
index 2e94f876c7..539180117c 100644
--- a/editor/src/messages/dialog/new_document_dialog/new_document_dialog_message_handler.rs
+++ b/editor/src/messages/dialog/new_document_dialog/new_document_dialog_message_handler.rs
@@ -4,13 +4,14 @@ use glam::{IVec2, UVec2};
use graph_craft::document::NodeId;
/// A dialog to allow users to set some initial options about a new document.
-#[derive(Debug, Clone, Default)]
+#[derive(Debug, Clone, Default, ExtractField)]
pub struct NewDocumentDialogMessageHandler {
pub name: String,
pub infinite: bool,
pub dimensions: UVec2,
}
+#[message_handler_data]
impl MessageHandler for NewDocumentDialogMessageHandler {
fn process_message(&mut self, message: NewDocumentDialogMessage, responses: &mut VecDeque, _data: ()) {
match message {
diff --git a/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs b/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs
index 6e92d60bcf..882fc6db5c 100644
--- a/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs
+++ b/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs
@@ -4,14 +4,16 @@ use crate::messages::portfolio::document::utility_types::wires::GraphWireStyle;
use crate::messages::preferences::SelectionMode;
use crate::messages::prelude::*;
+#[derive(ExtractField)]
pub struct PreferencesDialogMessageData<'a> {
pub preferences: &'a PreferencesMessageHandler,
}
/// A dialog to allow users to customize Graphite editor options
-#[derive(Debug, Clone, Default)]
+#[derive(Debug, Clone, Default, ExtractField)]
pub struct PreferencesDialogMessageHandler {}
+#[message_handler_data]
impl MessageHandler> for PreferencesDialogMessageHandler {
fn process_message(&mut self, message: PreferencesDialogMessage, responses: &mut VecDeque, data: PreferencesDialogMessageData) {
let PreferencesDialogMessageData { preferences } = data;
diff --git a/editor/src/messages/globals/globals_message_handler.rs b/editor/src/messages/globals/globals_message_handler.rs
index 5651555f60..9a72ffa6dc 100644
--- a/editor/src/messages/globals/globals_message_handler.rs
+++ b/editor/src/messages/globals/globals_message_handler.rs
@@ -1,8 +1,9 @@
use crate::messages::prelude::*;
-#[derive(Debug, Default)]
+#[derive(Debug, Default, ExtractField)]
pub struct GlobalsMessageHandler {}
+#[message_handler_data]
impl MessageHandler for GlobalsMessageHandler {
fn process_message(&mut self, message: GlobalsMessage, _responses: &mut VecDeque, _data: ()) {
match message {
diff --git a/editor/src/messages/input_mapper/input_mapper_message_handler.rs b/editor/src/messages/input_mapper/input_mapper_message_handler.rs
index eba3867213..b26a1b4c40 100644
--- a/editor/src/messages/input_mapper/input_mapper_message_handler.rs
+++ b/editor/src/messages/input_mapper/input_mapper_message_handler.rs
@@ -6,16 +6,18 @@ use crate::messages::portfolio::utility_types::KeyboardPlatformLayout;
use crate::messages::prelude::*;
use std::fmt::Write;
+#[derive(ExtractField)]
pub struct InputMapperMessageData<'a> {
pub input: &'a InputPreprocessorMessageHandler,
pub actions: ActionList,
}
-#[derive(Debug, Default)]
+#[derive(Debug, Default, ExtractField)]
pub struct InputMapperMessageHandler {
mapping: Mapping,
}
+#[message_handler_data]
impl MessageHandler> for InputMapperMessageHandler {
fn process_message(&mut self, message: InputMapperMessage, responses: &mut VecDeque, data: InputMapperMessageData) {
let InputMapperMessageData { input, actions } = data;
diff --git a/editor/src/messages/input_mapper/key_mapping/key_mapping_message_handler.rs b/editor/src/messages/input_mapper/key_mapping/key_mapping_message_handler.rs
index 53c626bf54..81f249ec5e 100644
--- a/editor/src/messages/input_mapper/key_mapping/key_mapping_message_handler.rs
+++ b/editor/src/messages/input_mapper/key_mapping/key_mapping_message_handler.rs
@@ -2,16 +2,18 @@ use crate::messages::input_mapper::input_mapper_message_handler::InputMapperMess
use crate::messages::input_mapper::utility_types::input_keyboard::KeysGroup;
use crate::messages::prelude::*;
+#[derive(ExtractField)]
pub struct KeyMappingMessageData<'a> {
pub input: &'a InputPreprocessorMessageHandler,
pub actions: ActionList,
}
-#[derive(Debug, Default)]
+#[derive(Debug, Default, ExtractField)]
pub struct KeyMappingMessageHandler {
mapping_handler: InputMapperMessageHandler,
}
+#[message_handler_data]
impl MessageHandler> for KeyMappingMessageHandler {
fn process_message(&mut self, message: KeyMappingMessage, responses: &mut VecDeque, data: KeyMappingMessageData) {
let KeyMappingMessageData { input, actions } = data;
diff --git a/editor/src/messages/input_preprocessor/input_preprocessor_message_handler.rs b/editor/src/messages/input_preprocessor/input_preprocessor_message_handler.rs
index bf90e5881f..144652fdc5 100644
--- a/editor/src/messages/input_preprocessor/input_preprocessor_message_handler.rs
+++ b/editor/src/messages/input_preprocessor/input_preprocessor_message_handler.rs
@@ -6,11 +6,12 @@ use crate::messages::prelude::*;
use glam::DVec2;
use std::time::Duration;
+#[derive(ExtractField)]
pub struct InputPreprocessorMessageData {
pub keyboard_platform: KeyboardPlatformLayout,
}
-#[derive(Debug, Default)]
+#[derive(Debug, Default, ExtractField)]
pub struct InputPreprocessorMessageHandler {
pub frame_time: FrameTimeInfo,
pub time: u64,
@@ -19,6 +20,7 @@ pub struct InputPreprocessorMessageHandler {
pub viewport_bounds: ViewportBounds,
}
+#[message_handler_data]
impl MessageHandler for InputPreprocessorMessageHandler {
fn process_message(&mut self, message: InputPreprocessorMessage, responses: &mut VecDeque, data: InputPreprocessorMessageData) {
let InputPreprocessorMessageData { keyboard_platform } = data;
diff --git a/editor/src/messages/layout/layout_message_handler.rs b/editor/src/messages/layout/layout_message_handler.rs
index ee8e506ca8..7beec22fe9 100644
--- a/editor/src/messages/layout/layout_message_handler.rs
+++ b/editor/src/messages/layout/layout_message_handler.rs
@@ -6,7 +6,7 @@ use graphene_std::text::Font;
use graphene_std::vector::style::{FillChoice, GradientStops};
use serde_json::Value;
-#[derive(Debug, Clone, Default)]
+#[derive(Debug, Clone, Default, ExtractField)]
pub struct LayoutMessageHandler {
layouts: [Layout; LayoutTarget::LayoutTargetLength as usize],
}
@@ -342,6 +342,15 @@ impl LayoutMessageHandler {
}
}
+pub fn custom_data() -> MessageData {
+ // TODO: When is resolved and released,
+ // TODO: use to get
+ // TODO: the line number instead of hardcoding it to the magic number on the following line.
+ // TODO: Also, utilize the line number in the actual output, since it is currently unused.
+ MessageData::new(String::from("Function"), vec![(String::from("Fn(&MessageDiscriminant) -> Option"), 350)], file!())
+}
+
+#[message_handler_data(CustomData)]
impl Option> MessageHandler for LayoutMessageHandler {
fn process_message(&mut self, message: LayoutMessage, responses: &mut std::collections::VecDeque, action_input_mapping: F) {
match message {
diff --git a/editor/src/messages/layout/utility_types/widgets/input_widgets.rs b/editor/src/messages/layout/utility_types/widgets/input_widgets.rs
index b76f23a067..893b301cd8 100644
--- a/editor/src/messages/layout/utility_types/widgets/input_widgets.rs
+++ b/editor/src/messages/layout/utility_types/widgets/input_widgets.rs
@@ -471,6 +471,8 @@ pub struct ReferencePointInput {
pub disabled: bool,
+ pub tooltip: String,
+
// Callbacks
#[serde(skip)]
#[derivative(Debug = "ignore", PartialEq = "ignore")]
diff --git a/editor/src/messages/message.rs b/editor/src/messages/message.rs
index 80323d9309..fbe4170023 100644
--- a/editor/src/messages/message.rs
+++ b/editor/src/messages/message.rs
@@ -45,3 +45,86 @@ impl specta::Type for MessageDiscriminant {
specta::DataType::Any
}
}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+ use std::io::Write;
+
+ #[test]
+ fn generate_message_tree() {
+ let result = Message::build_message_tree();
+ let mut file = std::fs::File::create("../hierarchical_message_system_tree.txt").unwrap();
+ file.write_all(format!("{} `{}`\n", result.name(), result.path()).as_bytes()).unwrap();
+ if let Some(variants) = result.variants() {
+ for (i, variant) in variants.iter().enumerate() {
+ let is_last = i == variants.len() - 1;
+ print_tree_node(variant, "", is_last, &mut file);
+ }
+ }
+ }
+
+ fn print_tree_node(tree: &DebugMessageTree, prefix: &str, is_last: bool, file: &mut std::fs::File) {
+ // Print the current node
+ let (branch, child_prefix) = if tree.has_message_handler_data_fields() || tree.has_message_handler_fields() {
+ ("├── ", format!("{}│ ", prefix))
+ } else {
+ if is_last {
+ ("└── ", format!("{} ", prefix))
+ } else {
+ ("├── ", format!("{}│ ", prefix))
+ }
+ };
+
+ if tree.path().is_empty() {
+ file.write_all(format!("{}{}{}\n", prefix, branch, tree.name()).as_bytes()).unwrap();
+ } else {
+ file.write_all(format!("{}{}{} `{}`\n", prefix, branch, tree.name(), tree.path()).as_bytes()).unwrap();
+ }
+
+ // Print children if any
+ if let Some(variants) = tree.variants() {
+ let len = variants.len();
+ for (i, variant) in variants.iter().enumerate() {
+ let is_last_child = i == len - 1;
+ print_tree_node(variant, &child_prefix, is_last_child, file);
+ }
+ }
+
+ // Print handler field if any
+ if let Some(data) = tree.message_handler_fields() {
+ let len = data.fields().len();
+ let (branch, child_prefix) = if tree.has_message_handler_data_fields() {
+ ("├── ", format!("{}│ ", prefix))
+ } else {
+ ("└── ", format!("{} ", prefix))
+ };
+ if data.path().is_empty() {
+ file.write_all(format!("{}{}{}\n", prefix, branch, data.name()).as_bytes()).unwrap();
+ } else {
+ file.write_all(format!("{}{}{} `{}`\n", prefix, branch, data.name(), data.path()).as_bytes()).unwrap();
+ }
+ for (i, field) in data.fields().iter().enumerate() {
+ let is_last_field = i == len - 1;
+ let branch = if is_last_field { "└── " } else { "├── " };
+
+ file.write_all(format!("{}{}{}\n", child_prefix, branch, field.0).as_bytes()).unwrap();
+ }
+ }
+
+ // Print data field if any
+ if let Some(data) = tree.message_handler_data_fields() {
+ let len = data.fields().len();
+ if data.path().is_empty() {
+ file.write_all(format!("{}{}{}\n", prefix, "└── ", data.name()).as_bytes()).unwrap();
+ } else {
+ file.write_all(format!("{}{}{} `{}`\n", prefix, "└── ", data.name(), data.path()).as_bytes()).unwrap();
+ }
+ for (i, field) in data.fields().iter().enumerate() {
+ let is_last_field = i == len - 1;
+ let branch = if is_last_field { "└── " } else { "├── " };
+ file.write_all(format!("{}{}{}\n", format!("{} ", prefix), branch, field.0).as_bytes()).unwrap();
+ }
+ }
+ }
+}
diff --git a/editor/src/messages/portfolio/document/document_message.rs b/editor/src/messages/portfolio/document/document_message.rs
index 18ede64be8..ae3576d2a1 100644
--- a/editor/src/messages/portfolio/document/document_message.rs
+++ b/editor/src/messages/portfolio/document/document_message.rs
@@ -182,6 +182,7 @@ pub enum DocumentMessage {
UpdateUpstreamTransforms {
upstream_footprints: HashMap,
local_transforms: HashMap,
+ first_instance_source_id: HashMap>,
},
UpdateClickTargets {
click_targets: HashMap>,
diff --git a/editor/src/messages/portfolio/document/document_message_handler.rs b/editor/src/messages/portfolio/document/document_message_handler.rs
index 81f631dfe0..784c3ba3ef 100644
--- a/editor/src/messages/portfolio/document/document_message_handler.rs
+++ b/editor/src/messages/portfolio/document/document_message_handler.rs
@@ -38,6 +38,7 @@ use graphene_std::vector::click_target::{ClickTarget, ClickTargetType};
use graphene_std::vector::style::ViewMode;
use std::time::Duration;
+#[derive(ExtractField)]
pub struct DocumentMessageData<'a> {
pub document_id: DocumentId,
pub ipp: &'a InputPreprocessorMessageHandler,
@@ -48,7 +49,7 @@ pub struct DocumentMessageData<'a> {
pub device_pixel_ratio: f64,
}
-#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
+#[derive(Clone, Debug, serde::Serialize, serde::Deserialize, ExtractField)]
#[serde(default)]
pub struct DocumentMessageHandler {
// ======================
@@ -168,6 +169,7 @@ impl Default for DocumentMessageHandler {
}
}
+#[message_handler_data]
impl MessageHandler> for DocumentMessageHandler {
fn process_message(&mut self, message: DocumentMessage, responses: &mut VecDeque, data: DocumentMessageData) {
let DocumentMessageData {
@@ -750,6 +752,7 @@ impl MessageHandler> for DocumentMessag
// Nudge translation without resizing
if !resize {
let transform = DAffine2::from_translation(DVec2::from_angle(-self.document_ptz.tilt()).rotate(DVec2::new(delta_x, delta_y)));
+ responses.add(SelectToolMessage::ShiftSelectedNodes { offset: transform.translation });
for layer in self.network_interface.shallowest_unique_layers(&[]).filter(|layer| can_move(*layer)) {
responses.add(GraphOperationMessage::TransformChange {
@@ -1185,6 +1188,7 @@ impl MessageHandler> for DocumentMessag
OverlaysType::HoverOutline => visibility_settings.hover_outline = visible,
OverlaysType::SelectionOutline => visibility_settings.selection_outline = visible,
OverlaysType::Pivot => visibility_settings.pivot = visible,
+ OverlaysType::Origin => visibility_settings.origin = visible,
OverlaysType::Path => visibility_settings.path = visible,
OverlaysType::Anchors => {
visibility_settings.anchors = visible;
@@ -1305,8 +1309,10 @@ impl MessageHandler> for DocumentMessag
DocumentMessage::UpdateUpstreamTransforms {
upstream_footprints,
local_transforms,
+ first_instance_source_id,
} => {
self.network_interface.update_transforms(upstream_footprints, local_transforms);
+ self.network_interface.update_first_instance_source_id(first_instance_source_id);
}
DocumentMessage::UpdateClickTargets { click_targets } => {
// TODO: Allow non layer nodes to have click targets
@@ -1714,6 +1720,14 @@ impl DocumentMessageHandler {
.reduce(graphene_std::renderer::Quad::combine_bounds)
}
+ pub fn selected_visible_and_unlock_layers_bounding_box_document(&self) -> Option<[DVec2; 2]> {
+ self.network_interface
+ .selected_nodes()
+ .selected_visible_and_unlocked_layers(&self.network_interface)
+ .map(|layer| self.metadata().nonzero_bounding_box(layer))
+ .reduce(graphene_std::renderer::Quad::combine_bounds)
+ }
+
pub fn document_network(&self) -> &NodeNetwork {
self.network_interface.document_network()
}
@@ -2267,6 +2281,24 @@ impl DocumentMessageHandler {
]
},
},
+ LayoutGroup::Row {
+ widgets: {
+ let mut checkbox_id = CheckboxId::default();
+ vec![
+ CheckboxInput::new(self.overlays_visibility_settings.pivot)
+ .on_update(|optional_input: &CheckboxInput| {
+ DocumentMessage::SetOverlaysVisibility {
+ visible: optional_input.checked,
+ overlays_type: Some(OverlaysType::Origin),
+ }
+ .into()
+ })
+ .for_label(checkbox_id.clone())
+ .widget_holder(),
+ TextLabel::new("Transform Origin".to_string()).for_checkbox(&mut checkbox_id).widget_holder(),
+ ]
+ },
+ },
LayoutGroup::Row {
widgets: {
let mut checkbox_id = CheckboxId::default();
diff --git a/editor/src/messages/portfolio/document/graph_operation/graph_operation_message.rs b/editor/src/messages/portfolio/document/graph_operation/graph_operation_message.rs
index abb1aa8594..31ea831218 100644
--- a/editor/src/messages/portfolio/document/graph_operation/graph_operation_message.rs
+++ b/editor/src/messages/portfolio/document/graph_operation/graph_operation_message.rs
@@ -3,7 +3,7 @@ use crate::messages::portfolio::document::utility_types::document_metadata::Laye
use crate::messages::portfolio::document::utility_types::network_interface::NodeTemplate;
use crate::messages::prelude::*;
use bezier_rs::Subpath;
-use glam::{DAffine2, DVec2, IVec2};
+use glam::{DAffine2, IVec2};
use graph_craft::document::NodeId;
use graphene_std::Artboard;
use graphene_std::brush::brush_stroke::BrushStroke;
@@ -52,10 +52,6 @@ pub enum GraphOperationMessage {
transform_in: TransformIn,
skip_rerender: bool,
},
- TransformSetPivot {
- layer: LayerNodeIdentifier,
- pivot: DVec2,
- },
Vector {
layer: LayerNodeIdentifier,
modification_type: VectorModificationType,
diff --git a/editor/src/messages/portfolio/document/graph_operation/graph_operation_message_handler.rs b/editor/src/messages/portfolio/document/graph_operation/graph_operation_message_handler.rs
index 375ae5ef0f..931a15e3bf 100644
--- a/editor/src/messages/portfolio/document/graph_operation/graph_operation_message_handler.rs
+++ b/editor/src/messages/portfolio/document/graph_operation/graph_operation_message_handler.rs
@@ -21,17 +21,19 @@ struct ArtboardInfo {
merge_node: NodeId,
}
+#[derive(ExtractField)]
pub struct GraphOperationMessageData<'a> {
pub network_interface: &'a mut NodeNetworkInterface,
pub collapsed: &'a mut CollapsedLayers,
pub node_graph: &'a mut NodeGraphMessageHandler,
}
-#[derive(Debug, Clone, PartialEq, Default, serde::Serialize, serde::Deserialize)]
+#[derive(Debug, Clone, PartialEq, Default, serde::Serialize, serde::Deserialize, ExtractField)]
pub struct GraphOperationMessageHandler {}
// GraphOperationMessageHandler always modified the document network. This is so changes to the layers panel will only affect the document network.
// For changes to the selected network, use NodeGraphMessageHandler. No NodeGraphMessage's should be added here, since they will affect the selected nested network.
+#[message_handler_data]
impl MessageHandler> for GraphOperationMessageHandler {
fn process_message(&mut self, message: GraphOperationMessage, responses: &mut VecDeque, data: GraphOperationMessageData) {
let network_interface = data.network_interface;
@@ -89,15 +91,6 @@ impl MessageHandler> for Gr
modify_inputs.transform_set(transform, transform_in, skip_rerender);
}
}
- GraphOperationMessage::TransformSetPivot { layer, pivot } => {
- if layer == LayerNodeIdentifier::ROOT_PARENT {
- log::error!("Cannot run TransformSetPivot on ROOT_PARENT");
- return;
- }
- if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer, network_interface, responses) {
- modify_inputs.pivot_set(pivot);
- }
- }
GraphOperationMessage::Vector { layer, modification_type } => {
if layer == LayerNodeIdentifier::ROOT_PARENT {
log::error!("Cannot run Vector on ROOT_PARENT");
diff --git a/editor/src/messages/portfolio/document/graph_operation/utility_types.rs b/editor/src/messages/portfolio/document/graph_operation/utility_types.rs
index 216dc8bf27..23a878f044 100644
--- a/editor/src/messages/portfolio/document/graph_operation/utility_types.rs
+++ b/editor/src/messages/portfolio/document/graph_operation/utility_types.rs
@@ -4,7 +4,7 @@ use crate::messages::portfolio::document::utility_types::document_metadata::Laye
use crate::messages::portfolio::document::utility_types::network_interface::{self, InputConnector, NodeNetworkInterface, OutputConnector};
use crate::messages::prelude::*;
use bezier_rs::Subpath;
-use glam::{DAffine2, DVec2, IVec2};
+use glam::{DAffine2, IVec2};
use graph_craft::concrete;
use graph_craft::document::value::TaggedValue;
use graph_craft::document::{NodeId, NodeInput};
@@ -458,12 +458,6 @@ impl<'a> ModifyInputsContext<'a> {
}
}
- pub fn pivot_set(&mut self, new_pivot: DVec2) {
- let Some(transform_node_id) = self.existing_node_id("Transform", true) else { return };
-
- self.set_input_with_refresh(InputConnector::node(transform_node_id, 5), NodeInput::value(TaggedValue::DVec2(new_pivot), false), false);
- }
-
pub fn vector_modify(&mut self, modification_type: VectorModificationType) {
let Some(path_node_id) = self.existing_node_id("Path", true) else { return };
self.network_interface.vector_modify(&path_node_id, modification_type);
diff --git a/editor/src/messages/portfolio/document/navigation/navigation_message_handler.rs b/editor/src/messages/portfolio/document/navigation/navigation_message_handler.rs
index 929c850160..0d732edd04 100644
--- a/editor/src/messages/portfolio/document/navigation/navigation_message_handler.rs
+++ b/editor/src/messages/portfolio/document/navigation/navigation_message_handler.rs
@@ -13,6 +13,7 @@ use crate::messages::tool::utility_types::{HintData, HintGroup, HintInfo};
use glam::{DAffine2, DVec2};
use graph_craft::document::NodeId;
+#[derive(ExtractField)]
pub struct NavigationMessageData<'a> {
pub network_interface: &'a mut NodeNetworkInterface,
pub breadcrumb_network_path: &'a [NodeId],
@@ -23,7 +24,7 @@ pub struct NavigationMessageData<'a> {
pub preferences: &'a PreferencesMessageHandler,
}
-#[derive(Debug, Clone, PartialEq, Default)]
+#[derive(Debug, Clone, PartialEq, Default, ExtractField)]
pub struct NavigationMessageHandler {
navigation_operation: NavigationOperation,
mouse_position: ViewportPosition,
@@ -31,6 +32,7 @@ pub struct NavigationMessageHandler {
abortable_pan_start: Option,
}
+#[message_handler_data]
impl MessageHandler> for NavigationMessageHandler {
fn process_message(&mut self, message: NavigationMessage, responses: &mut VecDeque, data: NavigationMessageData) {
let NavigationMessageData {
diff --git a/editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs b/editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs
index 346969c5ea..3c85102098 100644
--- a/editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs
+++ b/editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs
@@ -21,6 +21,7 @@ use graphene_std::extract_xy::XY;
use graphene_std::raster::{CellularDistanceFunction, CellularReturnType, Color, DomainWarpType, FractalType, NoiseType, RedGreenBlueAlpha};
use graphene_std::raster_types::{CPU, RasterDataTable};
use graphene_std::text::{Font, TypesettingConfig};
+#[allow(unused_imports)]
use graphene_std::transform::Footprint;
use graphene_std::vector::VectorDataTable;
use graphene_std::*;
@@ -88,7 +89,7 @@ fn static_nodes() -> Vec {
category: "General",
node_template: NodeTemplate {
document_node: DocumentNode {
- implementation: DocumentNodeImplementation::proto("graphene_core::ops::IdentityNode"),
+ implementation: DocumentNodeImplementation::ProtoNode(ops::identity::IDENTIFIER),
inputs: vec![NodeInput::value(TaggedValue::None, true)],
..Default::default()
},
@@ -107,7 +108,7 @@ fn static_nodes() -> Vec {
category: "Debug",
node_template: NodeTemplate {
document_node: DocumentNode {
- implementation: DocumentNodeImplementation::proto("graphene_core::memo::MonitorNode"),
+ implementation: DocumentNodeImplementation::ProtoNode(memo::monitor::IDENTIFIER),
inputs: vec![NodeInput::value(TaggedValue::None, true)],
manual_composition: Some(generic!(T)),
skip_deduplication: true,
@@ -148,19 +149,19 @@ fn static_nodes() -> Vec {
nodes: [
DocumentNode {
inputs: vec![NodeInput::network(generic!(T), 0)],
- implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::memo::MemoNode")),
+ implementation: DocumentNodeImplementation::ProtoNode(memo::memo::IDENTIFIER),
manual_composition: Some(generic!(T)),
..Default::default()
},
DocumentNode {
inputs: vec![NodeInput::node(NodeId(0), 0)],
- implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::transform_nodes::FreezeRealTimeNode")),
+ implementation: DocumentNodeImplementation::ProtoNode(transform_nodes::freeze_real_time::IDENTIFIER),
manual_composition: Some(generic!(T)),
..Default::default()
},
DocumentNode {
inputs: vec![NodeInput::node(NodeId(1), 0)],
- implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::transform_nodes::BoundlessFootprintNode")),
+ implementation: DocumentNodeImplementation::ProtoNode(transform_nodes::boundless_footprint::IDENTIFIER),
manual_composition: Some(generic!(T)),
..Default::default()
},
@@ -230,21 +231,21 @@ fn static_nodes() -> Vec {
// Secondary (left) input type coercion
DocumentNode {
inputs: vec![NodeInput::network(generic!(T), 1)],
- implementation: DocumentNodeImplementation::proto("graphene_core::graphic_element::ToElementNode"),
+ implementation: DocumentNodeImplementation::ProtoNode(graphic_element::to_element::IDENTIFIER),
manual_composition: Some(concrete!(Context)),
..Default::default()
},
// Primary (bottom) input type coercion
DocumentNode {
inputs: vec![NodeInput::network(generic!(T), 0)],
- implementation: DocumentNodeImplementation::proto("graphene_core::graphic_element::ToGroupNode"),
+ implementation: DocumentNodeImplementation::ProtoNode(graphic_element::to_group::IDENTIFIER),
manual_composition: Some(concrete!(Context)),
..Default::default()
},
// The monitor node is used to display a thumbnail in the UI
DocumentNode {
inputs: vec![NodeInput::node(NodeId(0), 0)],
- implementation: DocumentNodeImplementation::proto("graphene_core::memo::MonitorNode"),
+ implementation: DocumentNodeImplementation::ProtoNode(memo::monitor::IDENTIFIER),
manual_composition: Some(concrete!(Context)),
skip_deduplication: true,
..Default::default()
@@ -256,7 +257,7 @@ fn static_nodes() -> Vec {
NodeInput::node(NodeId(2), 0),
NodeInput::Reflection(graph_craft::document::DocumentNodeMetadata::DocumentNodePath),
],
- implementation: DocumentNodeImplementation::proto("graphene_core::graphic_element::LayerNode"),
+ implementation: DocumentNodeImplementation::ProtoNode(graphic_element::layer::IDENTIFIER),
..Default::default()
},
]
@@ -337,7 +338,7 @@ fn static_nodes() -> Vec {
// Ensure this ID is kept in sync with the ID in set_alias so that the name input is kept in sync with the alias
DocumentNode {
manual_composition: Some(generic!(T)),
- implementation: DocumentNodeImplementation::proto("graphene_core::graphic_element::ToArtboardNode"),
+ implementation: DocumentNodeImplementation::ProtoNode(graphic_element::to_artboard::IDENTIFIER),
inputs: vec![
NodeInput::network(concrete!(TaggedValue), 1),
NodeInput::value(TaggedValue::String(String::from("Artboard")), false),
@@ -352,7 +353,7 @@ fn static_nodes() -> Vec {
// TODO: Check if thumbnail is reversed
DocumentNode {
inputs: vec![NodeInput::node(NodeId(0), 0)],
- implementation: DocumentNodeImplementation::proto("graphene_core::memo::MonitorNode"),
+ implementation: DocumentNodeImplementation::ProtoNode(memo::monitor::IDENTIFIER),
manual_composition: Some(generic!(T)),
skip_deduplication: true,
..Default::default()
@@ -364,7 +365,7 @@ fn static_nodes() -> Vec {
NodeInput::node(NodeId(1), 0),
NodeInput::Reflection(graph_craft::document::DocumentNodeMetadata::DocumentNodePath),
],
- implementation: DocumentNodeImplementation::proto("graphene_core::graphic_element::AppendArtboardNode"),
+ implementation: DocumentNodeImplementation::ProtoNode(graphic_element::append_artboard::IDENTIFIER),
..Default::default()
},
]
@@ -466,13 +467,13 @@ fn static_nodes() -> Vec {
DocumentNode {
inputs: vec![NodeInput::value(TaggedValue::None, false), NodeInput::scope("editor-api"), NodeInput::network(concrete!(String), 1)],
manual_composition: Some(concrete!(Context)),
- implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_std::wasm_application_io::LoadResourceNode")),
+ implementation: DocumentNodeImplementation::ProtoNode(wasm_application_io::load_resource::IDENTIFIER),
..Default::default()
},
DocumentNode {
inputs: vec![NodeInput::node(NodeId(0), 0)],
manual_composition: Some(concrete!(Context)),
- implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_std::wasm_application_io::DecodeImageNode")),
+ implementation: DocumentNodeImplementation::ProtoNode(wasm_application_io::decode_image::IDENTIFIER),
..Default::default()
},
]
@@ -522,6 +523,7 @@ fn static_nodes() -> Vec {
description: Cow::Borrowed("Loads an image from a given URL"),
properties: None,
},
+ #[cfg(feature = "gpu")]
DocumentNodeDefinition {
identifier: "Create Canvas",
category: "Debug: GPU",
@@ -532,14 +534,14 @@ fn static_nodes() -> Vec {
nodes: [
DocumentNode {
inputs: vec![NodeInput::scope("editor-api")],
- implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_std::wasm_application_io::CreateSurfaceNode")),
+ implementation: DocumentNodeImplementation::ProtoNode(wasm_application_io::create_surface::IDENTIFIER),
skip_deduplication: true,
..Default::default()
},
DocumentNode {
manual_composition: Some(concrete!(Context)),
inputs: vec![NodeInput::node(NodeId(0), 0)],
- implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::memo::MemoNode")),
+ implementation: DocumentNodeImplementation::ProtoNode(memo::memo::IDENTIFIER),
..Default::default()
},
]
@@ -587,99 +589,7 @@ fn static_nodes() -> Vec {
description: Cow::Borrowed("Creates a new canvas object."),
properties: None,
},
- DocumentNodeDefinition {
- identifier: "Draw Canvas",
- category: "Debug: GPU",
- node_template: NodeTemplate {
- document_node: DocumentNode {
- implementation: DocumentNodeImplementation::Network(NodeNetwork {
- exports: vec![NodeInput::node(NodeId(3), 0)],
- nodes: [
- DocumentNode {
- inputs: vec![NodeInput::network(concrete!(RasterDataTable), 0)],
- implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::ops::IntoNode<_, RasterDataTable>")),
- ..Default::default()
- },
- DocumentNode {
- inputs: vec![NodeInput::scope("editor-api")],
- implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_std::wasm_application_io::CreateSurfaceNode")),
- skip_deduplication: true,
- ..Default::default()
- },
- DocumentNode {
- manual_composition: Some(concrete!(Context)),
- inputs: vec![NodeInput::node(NodeId(1), 0)],
- implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::memo::MemoNode")),
- ..Default::default()
- },
- DocumentNode {
- inputs: vec![NodeInput::node(NodeId(0), 0), NodeInput::node(NodeId(2), 0)],
- implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_std::wasm_application_io::DrawImageFrameNode")),
- ..Default::default()
- },
- ]
- .into_iter()
- .enumerate()
- .map(|(id, node)| (NodeId(id as u64), node))
- .collect(),
- ..Default::default()
- }),
- inputs: vec![NodeInput::value(TaggedValue::RasterData(RasterDataTable::default()), true)],
- ..Default::default()
- },
- persistent_node_metadata: DocumentNodePersistentMetadata {
- input_metadata: vec![("In", "TODO").into()],
- output_names: vec!["Canvas".to_string()],
- network_metadata: Some(NodeNetworkMetadata {
- persistent_metadata: NodeNetworkPersistentMetadata {
- node_metadata: [
- DocumentNodeMetadata {
- persistent_metadata: DocumentNodePersistentMetadata {
- display_name: "Into".to_string(),
- node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 0)),
- ..Default::default()
- },
- ..Default::default()
- },
- DocumentNodeMetadata {
- persistent_metadata: DocumentNodePersistentMetadata {
- display_name: "Create Canvas".to_string(),
- node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 2)),
- ..Default::default()
- },
- ..Default::default()
- },
- DocumentNodeMetadata {
- persistent_metadata: DocumentNodePersistentMetadata {
- display_name: "Cache".to_string(),
- node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(7, 2)),
- ..Default::default()
- },
- ..Default::default()
- },
- DocumentNodeMetadata {
- persistent_metadata: DocumentNodePersistentMetadata {
- display_name: "Draw Canvas".to_string(),
- node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(14, 0)),
- ..Default::default()
- },
- ..Default::default()
- },
- ]
- .into_iter()
- .enumerate()
- .map(|(id, node)| (NodeId(id as u64), node))
- .collect(),
- ..Default::default()
- },
- ..Default::default()
- }),
- ..Default::default()
- },
- },
- description: Cow::Borrowed("Draws raster data to a canvas element."),
- properties: None,
- },
+ #[cfg(all(feature = "gpu", target_arch = "wasm32"))]
DocumentNodeDefinition {
identifier: "Rasterize",
category: "Raster",
@@ -690,20 +600,20 @@ fn static_nodes() -> Vec {
nodes: [
DocumentNode {
inputs: vec![NodeInput::scope("editor-api")],
- implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_std::wasm_application_io::CreateSurfaceNode")),
+ implementation: DocumentNodeImplementation::ProtoNode(wasm_application_io::create_surface::IDENTIFIER),
manual_composition: Some(concrete!(Context)),
skip_deduplication: true,
..Default::default()
},
DocumentNode {
inputs: vec![NodeInput::node(NodeId(0), 0)],
- implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::memo::MemoNode")),
+ implementation: DocumentNodeImplementation::ProtoNode(memo::memo::IDENTIFIER),
manual_composition: Some(concrete!(Context)),
..Default::default()
},
DocumentNode {
inputs: vec![NodeInput::network(generic!(T), 0), NodeInput::network(concrete!(Footprint), 1), NodeInput::node(NodeId(1), 0)],
- implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_std::wasm_application_io::RasterizeNode")),
+ implementation: DocumentNodeImplementation::ProtoNode(wasm_application_io::rasterize::IDENTIFIER),
manual_composition: Some(concrete!(Context)),
..Default::default()
},
@@ -778,7 +688,7 @@ fn static_nodes() -> Vec {
node_template: NodeTemplate {
document_node: DocumentNode {
manual_composition: Some(concrete!(Context)),
- implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_raster_nodes::std_nodes::NoisePatternNode")),
+ implementation: DocumentNodeImplementation::ProtoNode(raster_nodes::std_nodes::noise_pattern::IDENTIFIER),
inputs: vec![
NodeInput::value(TaggedValue::None, false),
NodeInput::value(TaggedValue::Bool(true), false),
@@ -843,7 +753,7 @@ fn static_nodes() -> Vec {
NodeInput::network(concrete!(RasterDataTable), 0),
NodeInput::value(TaggedValue::RedGreenBlueAlpha(RedGreenBlueAlpha::Red), false),
],
- implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::raster::adjustments::ExtractChannelNode")),
+ implementation: DocumentNodeImplementation::ProtoNode(raster_nodes::adjustments::extract_channel::IDENTIFIER),
manual_composition: Some(generic!(T)),
..Default::default()
},
@@ -852,7 +762,7 @@ fn static_nodes() -> Vec {
NodeInput::network(concrete!(RasterDataTable), 0),
NodeInput::value(TaggedValue::RedGreenBlueAlpha(RedGreenBlueAlpha::Green), false),
],
- implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::raster::adjustments::ExtractChannelNode")),
+ implementation: DocumentNodeImplementation::ProtoNode(raster_nodes::adjustments::extract_channel::IDENTIFIER),
manual_composition: Some(generic!(T)),
..Default::default()
},
@@ -861,7 +771,7 @@ fn static_nodes() -> Vec {
NodeInput::network(concrete!(RasterDataTable), 0),
NodeInput::value(TaggedValue::RedGreenBlueAlpha(RedGreenBlueAlpha::Blue), false),
],
- implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::raster::adjustments::ExtractChannelNode")),
+ implementation: DocumentNodeImplementation::ProtoNode(raster_nodes::adjustments::extract_channel::IDENTIFIER),
manual_composition: Some(generic!(T)),
..Default::default()
},
@@ -870,7 +780,7 @@ fn static_nodes() -> Vec {
NodeInput::network(concrete!(RasterDataTable), 0),
NodeInput::value(TaggedValue::RedGreenBlueAlpha(RedGreenBlueAlpha::Alpha), false),
],
- implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::raster::adjustments::ExtractChannelNode")),
+ implementation: DocumentNodeImplementation::ProtoNode(raster_nodes::adjustments::extract_channel::IDENTIFIER),
manual_composition: Some(generic!(T)),
..Default::default()
},
@@ -948,13 +858,13 @@ fn static_nodes() -> Vec {
nodes: [
DocumentNode {
inputs: vec![NodeInput::network(concrete!(RasterDataTable), 0), NodeInput::value(TaggedValue::XY(XY::X), false)],
- implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::extract_xy::ExtractXyNode")),
+ implementation: DocumentNodeImplementation::ProtoNode(extract_xy::extract_xy::IDENTIFIER),
manual_composition: Some(generic!(T)),
..Default::default()
},
DocumentNode {
inputs: vec![NodeInput::network(concrete!(RasterDataTable), 0), NodeInput::value(TaggedValue::XY(XY::Y), false)],
- implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::extract_xy::ExtractXyNode")),
+ implementation: DocumentNodeImplementation::ProtoNode(extract_xy::extract_xy::IDENTIFIER),
manual_composition: Some(generic!(T)),
..Default::default()
},
@@ -1024,7 +934,7 @@ fn static_nodes() -> Vec {
NodeInput::network(concrete!(BrushCache), 2),
],
manual_composition: Some(concrete!(Context)),
- implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_brush::brush::BrushNode")),
+ implementation: DocumentNodeImplementation::ProtoNode(brush::brush::brush::IDENTIFIER),
..Default::default()
}]
.into_iter()
@@ -1036,7 +946,7 @@ fn static_nodes() -> Vec {
inputs: vec![
NodeInput::value(TaggedValue::RasterData(RasterDataTable::default()), true),
NodeInput::value(TaggedValue::BrushStrokes(Vec::new()), false),
- NodeInput::value(TaggedValue::BrushCache(BrushCache::new_proto()), false),
+ NodeInput::value(TaggedValue::BrushCache(BrushCache::default()), false),
],
..Default::default()
},
@@ -1072,7 +982,7 @@ fn static_nodes() -> Vec {
category: "Debug",
node_template: NodeTemplate {
document_node: DocumentNode {
- implementation: DocumentNodeImplementation::proto("graphene_core::memo::MemoNode"),
+ implementation: DocumentNodeImplementation::ProtoNode(memo::memo::IDENTIFIER),
inputs: vec![NodeInput::value(TaggedValue::RasterData(RasterDataTable::default()), true)],
manual_composition: Some(concrete!(Context)),
..Default::default()
@@ -1091,7 +1001,7 @@ fn static_nodes() -> Vec {
category: "Debug",
node_template: NodeTemplate {
document_node: DocumentNode {
- implementation: DocumentNodeImplementation::proto("graphene_core::memo::ImpureMemoNode"),
+ implementation: DocumentNodeImplementation::ProtoNode(memo::impure_memo::IDENTIFIER),
inputs: vec![NodeInput::value(TaggedValue::RasterData(RasterDataTable::default()), true)],
manual_composition: Some(concrete!(Context)),
..Default::default()
@@ -1105,164 +1015,6 @@ fn static_nodes() -> Vec {
description: Cow::Borrowed("TODO"),
properties: None,
},
- DocumentNodeDefinition {
- identifier: "Storage",
- category: "Debug: GPU",
- node_template: NodeTemplate {
- document_node: DocumentNode {
- implementation: DocumentNodeImplementation::Network(NodeNetwork {
- exports: vec![NodeInput::node(NodeId(2), 0)],
- nodes: [
- DocumentNode {
- inputs: vec![NodeInput::scope("editor-api")],
- implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::ops::IntoNode")),
- ..Default::default()
- },
- DocumentNode {
- inputs: vec![NodeInput::network(concrete!(Vec), 0), NodeInput::node(NodeId(0), 0)],
- implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("wgpu_executor::StorageNode")),
- ..Default::default()
- },
- DocumentNode {
- manual_composition: Some(concrete!(Context)),
- inputs: vec![NodeInput::node(NodeId(1), 0)],
- implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::memo::MemoNode")),
- ..Default::default()
- },
- ]
- .into_iter()
- .enumerate()
- .map(|(id, node)| (NodeId(id as u64), node))
- .collect(),
- ..Default::default()
- }),
- inputs: vec![NodeInput::value(TaggedValue::None, true)],
- ..Default::default()
- },
- persistent_node_metadata: DocumentNodePersistentMetadata {
- input_metadata: vec![("In", "TODO").into()],
- output_names: vec!["Storage".to_string()],
- network_metadata: Some(NodeNetworkMetadata {
- persistent_metadata: NodeNetworkPersistentMetadata {
- node_metadata: [
- DocumentNodeMetadata {
- persistent_metadata: DocumentNodePersistentMetadata {
- display_name: "Extract Executor".to_string(),
- node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 0)),
- ..Default::default()
- },
- ..Default::default()
- },
- DocumentNodeMetadata {
- persistent_metadata: DocumentNodePersistentMetadata {
- display_name: "Create Storage".to_string(),
- node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(7, 0)),
- ..Default::default()
- },
- ..Default::default()
- },
- DocumentNodeMetadata {
- persistent_metadata: DocumentNodePersistentMetadata {
- display_name: "Cache".to_string(),
- node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(14, 0)),
- ..Default::default()
- },
- ..Default::default()
- },
- ]
- .into_iter()
- .enumerate()
- .map(|(id, node)| (NodeId(id as u64), node))
- .collect(),
- ..Default::default()
- },
- ..Default::default()
- }),
- ..Default::default()
- },
- },
- description: Cow::Borrowed("TODO"),
- properties: None,
- },
- DocumentNodeDefinition {
- identifier: "Create Output Buffer",
- category: "Debug: GPU",
- node_template: NodeTemplate {
- document_node: DocumentNode {
- implementation: DocumentNodeImplementation::Network(NodeNetwork {
- exports: vec![NodeInput::node(NodeId(2), 0)],
- nodes: [
- DocumentNode {
- inputs: vec![NodeInput::scope("editor-api")],
- implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::ops::IntoNode")),
- ..Default::default()
- },
- DocumentNode {
- inputs: vec![NodeInput::network(concrete!(usize), 0), NodeInput::node(NodeId(0), 0), NodeInput::network(concrete!(Type), 1)],
- implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("wgpu_executor::CreateOutputBufferNode")),
- ..Default::default()
- },
- DocumentNode {
- manual_composition: Some(concrete!(Context)),
- inputs: vec![NodeInput::node(NodeId(1), 0)],
- implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::memo::MemoNode")),
- ..Default::default()
- },
- ]
- .into_iter()
- .enumerate()
- .map(|(id, node)| (NodeId(id as u64), node))
- .collect(),
- ..Default::default()
- }),
- inputs: vec![NodeInput::value(TaggedValue::None, true), NodeInput::value(TaggedValue::None, true)],
- ..Default::default()
- },
- persistent_node_metadata: DocumentNodePersistentMetadata {
- input_metadata: vec![("In", "TODO").into(), ("In", "TODO").into()],
- output_names: vec!["Output Buffer".to_string()],
- network_metadata: Some(NodeNetworkMetadata {
- persistent_metadata: NodeNetworkPersistentMetadata {
- node_metadata: [
- DocumentNodeMetadata {
- persistent_metadata: DocumentNodePersistentMetadata {
- display_name: "Extract Executor".to_string(),
- node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 0)),
- ..Default::default()
- },
- ..Default::default()
- },
- DocumentNodeMetadata {
- persistent_metadata: DocumentNodePersistentMetadata {
- display_name: "Create Output Buffer".to_string(),
- node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(7, 0)),
- ..Default::default()
- },
- ..Default::default()
- },
- DocumentNodeMetadata {
- persistent_metadata: DocumentNodePersistentMetadata {
- display_name: "Cache".to_string(),
- node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(14, 0)),
- ..Default::default()
- },
- ..Default::default()
- },
- ]
- .into_iter()
- .enumerate()
- .map(|(id, node)| (NodeId(id as u64), node))
- .collect(),
- ..Default::default()
- },
- ..Default::default()
- }),
- ..Default::default()
- },
- },
- description: Cow::Borrowed("TODO"),
- properties: None,
- },
#[cfg(feature = "gpu")]
DocumentNodeDefinition {
identifier: "Create GPU Surface",
@@ -1275,13 +1027,13 @@ fn static_nodes() -> Vec {
DocumentNode {
manual_composition: Some(concrete!(Context)),
inputs: vec![NodeInput::scope("editor-api")],
- implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("wgpu_executor::CreateGpuSurfaceNode")),
+ implementation: DocumentNodeImplementation::ProtoNode(wgpu_executor::create_gpu_surface::IDENTIFIER),
..Default::default()
},
DocumentNode {
manual_composition: Some(concrete!(Context)),
inputs: vec![NodeInput::node(NodeId(0), 0)],
- implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::memo::ImpureMemoNode")),
+ implementation: DocumentNodeImplementation::ProtoNode(memo::impure_memo::IDENTIFIER),
..Default::default()
},
]
@@ -1329,87 +1081,6 @@ fn static_nodes() -> Vec {
description: Cow::Borrowed("TODO"),
properties: None,
},
- #[cfg(feature = "gpu")]
- DocumentNodeDefinition {
- identifier: "Upload Texture",
- category: "Debug: GPU",
- node_template: NodeTemplate {
- document_node: DocumentNode {
- implementation: DocumentNodeImplementation::Network(NodeNetwork {
- exports: vec![NodeInput::node(NodeId(2), 0)],
- nodes: [
- DocumentNode {
- inputs: vec![NodeInput::scope("editor-api")],
- implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::ops::IntoNode<&WgpuExecutor>")),
- ..Default::default()
- },
- DocumentNode {
- inputs: vec![NodeInput::network(concrete!(RasterDataTable), 0), NodeInput::node(NodeId(0), 0)],
- manual_composition: Some(generic!(T)),
- implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("wgpu_executor::UploadTextureNode")),
- ..Default::default()
- },
- DocumentNode {
- manual_composition: Some(generic!(T)),
- inputs: vec![NodeInput::node(NodeId(1), 0)],
- implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::memo::ImpureMemoNode")),
- ..Default::default()
- },
- ]
- .into_iter()
- .enumerate()
- .map(|(id, node)| (NodeId(id as u64), node))
- .collect(),
- ..Default::default()
- }),
- inputs: vec![NodeInput::value(TaggedValue::RasterData(RasterDataTable::default()), true)],
- ..Default::default()
- },
- persistent_node_metadata: DocumentNodePersistentMetadata {
- input_metadata: vec![("In", "TODO").into()],
- output_names: vec!["Texture".to_string()],
- network_metadata: Some(NodeNetworkMetadata {
- persistent_metadata: NodeNetworkPersistentMetadata {
- node_metadata: [
- DocumentNodeMetadata {
- persistent_metadata: DocumentNodePersistentMetadata {
- display_name: "Extract Executor".to_string(),
- node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 0)),
- ..Default::default()
- },
- ..Default::default()
- },
- DocumentNodeMetadata {
- persistent_metadata: DocumentNodePersistentMetadata {
- display_name: "Upload Texture".to_string(),
- node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(7, 0)),
- ..Default::default()
- },
- ..Default::default()
- },
- DocumentNodeMetadata {
- persistent_metadata: DocumentNodePersistentMetadata {
- display_name: "Cache".to_string(),
- node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(14, 0)),
- ..Default::default()
- },
- ..Default::default()
- },
- ]
- .into_iter()
- .enumerate()
- .map(|(id, node)| (NodeId(id as u64), node))
- .collect(),
- ..Default::default()
- },
- ..Default::default()
- }),
- ..Default::default()
- },
- },
- description: Cow::Borrowed("TODO"),
- properties: None,
- },
DocumentNodeDefinition {
identifier: "Extract",
category: "Debug",
@@ -1466,15 +1137,19 @@ fn static_nodes() -> Vec {
nodes: vec![
DocumentNode {
inputs: vec![NodeInput::network(concrete!(VectorDataTable), 0)],
- implementation: DocumentNodeImplementation::proto("graphene_core::memo::MonitorNode"),
+ implementation: DocumentNodeImplementation::ProtoNode(memo::monitor::IDENTIFIER),
manual_composition: Some(generic!(T)),
skip_deduplication: true,
..Default::default()
},
DocumentNode {
- inputs: vec![NodeInput::node(NodeId(0), 0), NodeInput::network(concrete!(graphene_std::vector::VectorModification), 1)],
+ inputs: vec![
+ NodeInput::node(NodeId(0), 0),
+ NodeInput::network(concrete!(graphene_std::vector::VectorModification), 1),
+ NodeInput::Reflection(graph_craft::document::DocumentNodeMetadata::DocumentNodePath),
+ ],
manual_composition: Some(generic!(T)),
- implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::vector::vector_data::modification::PathModifyNode")),
+ implementation: DocumentNodeImplementation::ProtoNode(vector::path_modify::IDENTIFIER),
..Default::default()
},
]
@@ -1532,7 +1207,7 @@ fn static_nodes() -> Vec {
category: "Text",
node_template: NodeTemplate {
document_node: DocumentNode {
- implementation: DocumentNodeImplementation::proto("graphene_std::text::TextNode"),
+ implementation: DocumentNodeImplementation::ProtoNode(text::text::IDENTIFIER),
manual_composition: Some(concrete!(Context)),
inputs: vec![
NodeInput::scope("editor-api"),
@@ -1633,14 +1308,13 @@ fn static_nodes() -> Vec {
NodeInput::value(TaggedValue::F64(0.), false),
NodeInput::value(TaggedValue::DVec2(DVec2::ONE), false),
NodeInput::value(TaggedValue::DVec2(DVec2::ZERO), false),
- NodeInput::value(TaggedValue::DVec2(DVec2::splat(0.5)), false),
],
implementation: DocumentNodeImplementation::Network(NodeNetwork {
exports: vec![NodeInput::node(NodeId(1), 0)],
nodes: [
DocumentNode {
inputs: vec![NodeInput::network(concrete!(VectorDataTable), 0)],
- implementation: DocumentNodeImplementation::proto("graphene_core::memo::MonitorNode"),
+ implementation: DocumentNodeImplementation::ProtoNode(memo::monitor::IDENTIFIER),
manual_composition: Some(generic!(T)),
skip_deduplication: true,
..Default::default()
@@ -1652,10 +1326,9 @@ fn static_nodes() -> Vec {
NodeInput::network(concrete!(f64), 2),
NodeInput::network(concrete!(DVec2), 3),
NodeInput::network(concrete!(DVec2), 4),
- NodeInput::network(concrete!(DVec2), 5),
],
manual_composition: Some(concrete!(Context)),
- implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::transform_nodes::TransformNode")),
+ implementation: DocumentNodeImplementation::ProtoNode(transform_nodes::transform::IDENTIFIER),
..Default::default()
},
]
@@ -1720,7 +1393,6 @@ fn static_nodes() -> Vec {
}),
),
InputMetadata::with_name_description_override("Skew", "TODO", WidgetOverride::Custom("transform_skew".to_string())),
- InputMetadata::with_name_description_override("Pivot", "TODO", WidgetOverride::Hidden),
],
output_names: vec!["Data".to_string()],
..Default::default()
@@ -1739,25 +1411,25 @@ fn static_nodes() -> Vec {
nodes: vec![
DocumentNode {
inputs: vec![NodeInput::network(concrete!(VectorDataTable), 0), NodeInput::network(concrete!(vector::style::Fill), 1)],
- implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_path_bool::BooleanOperationNode")),
+ implementation: DocumentNodeImplementation::ProtoNode(path_bool::boolean_operation::IDENTIFIER),
manual_composition: Some(generic!(T)),
..Default::default()
},
DocumentNode {
inputs: vec![NodeInput::node(NodeId(0), 0)],
- implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::memo::MemoNode")),
+ implementation: DocumentNodeImplementation::ProtoNode(memo::memo::IDENTIFIER),
manual_composition: Some(generic!(T)),
..Default::default()
},
DocumentNode {
inputs: vec![NodeInput::node(NodeId(1), 0)],
- implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::transform_nodes::FreezeRealTimeNode")),
+ implementation: DocumentNodeImplementation::ProtoNode(transform_nodes::freeze_real_time::IDENTIFIER),
manual_composition: Some(generic!(T)),
..Default::default()
},
DocumentNode {
inputs: vec![NodeInput::node(NodeId(2), 0)],
- implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::transform_nodes::BoundlessFootprintNode")),
+ implementation: DocumentNodeImplementation::ProtoNode(transform_nodes::boundless_footprint::IDENTIFIER),
manual_composition: Some(generic!(T)),
..Default::default()
},
@@ -1837,7 +1509,7 @@ fn static_nodes() -> Vec {
nodes: [
DocumentNode {
inputs: vec![NodeInput::network(concrete!(graphene_std::vector::VectorDataTable), 0)],
- implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::vector::SubpathSegmentLengthsNode")),
+ implementation: DocumentNodeImplementation::ProtoNode(vector::subpath_segment_lengths::IDENTIFIER),
manual_composition: Some(generic!(T)),
..Default::default()
},
@@ -1852,25 +1524,25 @@ fn static_nodes() -> Vec {
NodeInput::network(concrete!(bool), 6),
NodeInput::node(NodeId(0), 0),
],
- implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::vector::SamplePolylineNode")),
+ implementation: DocumentNodeImplementation::ProtoNode(vector::sample_polyline::IDENTIFIER),
manual_composition: Some(generic!(T)),
..Default::default()
},
DocumentNode {
inputs: vec![NodeInput::node(NodeId(1), 0)],
- implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::memo::MemoNode")),
+ implementation: DocumentNodeImplementation::ProtoNode(memo::memo::IDENTIFIER),
manual_composition: Some(generic!(T)),
..Default::default()
},
DocumentNode {
inputs: vec![NodeInput::node(NodeId(2), 0)],
- implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::transform_nodes::FreezeRealTimeNode")),
+ implementation: DocumentNodeImplementation::ProtoNode(transform_nodes::freeze_real_time::IDENTIFIER),
manual_composition: Some(generic!(T)),
..Default::default()
},
DocumentNode {
inputs: vec![NodeInput::node(NodeId(3), 0)],
- implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::transform_nodes::BoundlessFootprintNode")),
+ implementation: DocumentNodeImplementation::ProtoNode(transform_nodes::boundless_footprint::IDENTIFIER),
manual_composition: Some(generic!(T)),
..Default::default()
},
@@ -2008,24 +1680,24 @@ fn static_nodes() -> Vec {
NodeInput::network(concrete!(u32), 2),
],
manual_composition: Some(generic!(T)),
- implementation: DocumentNodeImplementation::proto("graphene_core::vector::PoissonDiskPointsNode"),
+ implementation: DocumentNodeImplementation::ProtoNode(vector::poisson_disk_points::IDENTIFIER),
..Default::default()
},
DocumentNode {
inputs: vec![NodeInput::node(NodeId(0), 0)],
- implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::memo::MemoNode")),
+ implementation: DocumentNodeImplementation::ProtoNode(memo::memo::IDENTIFIER),
manual_composition: Some(generic!(T)),
..Default::default()
},
DocumentNode {
inputs: vec![NodeInput::node(NodeId(1), 0)],
- implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::transform_nodes::FreezeRealTimeNode")),
+ implementation: DocumentNodeImplementation::ProtoNode(transform_nodes::freeze_real_time::IDENTIFIER),
manual_composition: Some(generic!(T)),
..Default::default()
},
DocumentNode {
inputs: vec![NodeInput::node(NodeId(2), 0)],
- implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::transform_nodes::BoundlessFootprintNode")),
+ implementation: DocumentNodeImplementation::ProtoNode(transform_nodes::boundless_footprint::IDENTIFIER),
manual_composition: Some(generic!(T)),
..Default::default()
},
@@ -2645,11 +2317,11 @@ pub fn resolve_document_node_type(identifier: &str) -> Option<&DocumentNodeDefin
pub fn collect_node_types() -> Vec {
// Create a mapping from registry ID to document node identifier
- let id_to_identifier_map: HashMap = DOCUMENT_NODE_TYPES
+ let id_to_identifier_map: HashMap = DOCUMENT_NODE_TYPES
.iter()
.filter_map(|definition| {
- if let DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier { name }) = &definition.node_template.document_node.implementation {
- Some((name.to_string(), definition.identifier))
+ if let DocumentNodeImplementation::ProtoNode(name) = &definition.node_template.document_node.implementation {
+ Some((name.clone(), definition.identifier))
} else {
None
}
@@ -2657,28 +2329,28 @@ pub fn collect_node_types() -> Vec {
.collect();
let mut extracted_node_types = Vec::new();
- let node_registry = graphene_std::registry::NODE_REGISTRY.lock().unwrap();
- let node_metadata = graphene_std::registry::NODE_METADATA.lock().unwrap();
+ let node_registry = registry::NODE_REGISTRY.lock().unwrap();
+ let node_metadata = registry::NODE_METADATA.lock().unwrap();
for (id, metadata) in node_metadata.iter() {
if let Some(implementations) = node_registry.get(id) {
let identifier = match id_to_identifier_map.get(id) {
- Some(&id) => id.to_string(),
+ Some(&id) => id,
None => continue,
};
// Extract category from metadata (already creates an owned String)
- let category = metadata.category.unwrap_or_default().to_string();
+ let category = metadata.category.unwrap_or_default();
// Extract input types (already creates owned Strings)
let input_types = implementations
.iter()
- .flat_map(|(_, node_io)| node_io.inputs.iter().map(|ty| ty.nested_type().to_string()))
- .collect::>()
+ .flat_map(|(_, node_io)| node_io.inputs.iter().map(|ty| ty.nested_type().to_cow_string()))
+ .collect::>>()
.into_iter()
- .collect::>();
+ .collect::>>();
// Create a FrontendNodeType
- let node_type = FrontendNodeType::with_owned_strings_and_input_types(identifier, category, input_types);
+ let node_type = FrontendNodeType::with_input_types(identifier, category, input_types);
// Store the created node_type
extracted_node_types.push(node_type);
@@ -2694,8 +2366,8 @@ pub fn collect_node_types() -> Vec {
.document_node
.inputs
.iter()
- .filter_map(|node_input| node_input.as_value().map(|node_value| node_value.ty().nested_type().to_string()))
- .collect::>();
+ .filter_map(|node_input| node_input.as_value().map(|node_value| node_value.ty().nested_type().to_cow_string()))
+ .collect::>>();
FrontendNodeType::with_input_types(definition.identifier, definition.category, input_types)
})
diff --git a/editor/src/messages/portfolio/document/node_graph/document_node_definitions/document_node_derive.rs b/editor/src/messages/portfolio/document/node_graph/document_node_definitions/document_node_derive.rs
index 8fcec559a7..85ce4b5162 100644
--- a/editor/src/messages/portfolio/document/node_graph/document_node_definitions/document_node_derive.rs
+++ b/editor/src/messages/portfolio/document/node_graph/document_node_definitions/document_node_derive.rs
@@ -21,7 +21,7 @@ pub(super) fn post_process_nodes(mut custom: Vec) -> Vec
};
}
- let node_registry = graphene_core::registry::NODE_REGISTRY.lock().unwrap();
+ let node_registry = NODE_REGISTRY.lock().unwrap();
'outer: for (id, metadata) in NODE_METADATA.lock().unwrap().iter() {
for node in custom.iter() {
let DocumentNodeDefinition {
@@ -32,7 +32,7 @@ pub(super) fn post_process_nodes(mut custom: Vec) -> Vec
..
} = node;
match implementation {
- DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier { name }) if name == id => continue 'outer,
+ DocumentNodeImplementation::ProtoNode(name) if name == id => continue 'outer,
_ => (),
}
}
diff --git a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs
index b3f1596cd2..828fb4a8ae 100644
--- a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs
+++ b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs
@@ -27,7 +27,7 @@ use graphene_std::*;
use renderer::Quad;
use std::cmp::Ordering;
-#[derive(Debug)]
+#[derive(Debug, ExtractField)]
pub struct NodeGraphHandlerData<'a> {
pub network_interface: &'a mut NodeNetworkInterface,
pub selection_network_path: &'a [NodeId],
@@ -41,7 +41,7 @@ pub struct NodeGraphHandlerData<'a> {
pub preferences: &'a PreferencesMessageHandler,
}
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, ExtractField)]
pub struct NodeGraphMessageHandler {
// TODO: Remove network and move to NodeNetworkInterface
pub network: Vec,
@@ -92,6 +92,7 @@ pub struct NodeGraphMessageHandler {
}
/// NodeGraphMessageHandler always modifies the network which the selected nodes are in. No GraphOperationMessages should be added here, since those messages will always affect the document network.
+#[message_handler_data]
impl<'a> MessageHandler> for NodeGraphMessageHandler {
fn process_message(&mut self, message: NodeGraphMessage, responses: &mut VecDeque, data: NodeGraphHandlerData<'a>) {
let NodeGraphHandlerData {
diff --git a/editor/src/messages/portfolio/document/node_graph/node_properties.rs b/editor/src/messages/portfolio/document/node_graph/node_properties.rs
index bc40dd36e4..9551ed2094 100644
--- a/editor/src/messages/portfolio/document/node_graph/node_properties.rs
+++ b/editor/src/messages/portfolio/document/node_graph/node_properties.rs
@@ -1274,6 +1274,7 @@ pub(crate) fn rectangle_properties(node_id: NodeId, context: &mut NodeProperties
let mut corner_radius_row_2 = vec![Separator::new(SeparatorType::Unrelated).widget_holder()];
corner_radius_row_2.push(TextLabel::new("").widget_holder());
+ add_blank_assist(&mut corner_radius_row_2);
let document_node = match get_document_node(node_id, context) {
Ok(document_node) => document_node,
@@ -1381,8 +1382,6 @@ pub(crate) fn rectangle_properties(node_id: NodeId, context: &mut NodeProperties
// Size Y
let size_y = number_widget(ParameterWidgetsInfo::new(node_id, HeightInput::INDEX, true, context), NumberInput::default());
- add_blank_assist(&mut corner_radius_row_2);
-
// Clamped
let clamped = bool_widget(ParameterWidgetsInfo::new(node_id, ClampedInput::INDEX, true, context), CheckboxInput::default());
@@ -1436,7 +1435,7 @@ pub(crate) fn generate_node_properties(node_id: NodeId, context: &mut NodeProper
if let Some(field) = graphene_std::registry::NODE_METADATA
.lock()
.unwrap()
- .get(&proto_node_identifier.name.clone().into_owned())
+ .get(proto_node_identifier)
.and_then(|metadata| metadata.fields.get(input_index))
{
number_options = (field.number_min, field.number_max, field.number_mode_range);
diff --git a/editor/src/messages/portfolio/document/node_graph/utility_types.rs b/editor/src/messages/portfolio/document/node_graph/utility_types.rs
index b743cb1fc6..e752c9d7ce 100644
--- a/editor/src/messages/portfolio/document/node_graph/utility_types.rs
+++ b/editor/src/messages/portfolio/document/node_graph/utility_types.rs
@@ -2,6 +2,7 @@ use crate::messages::portfolio::document::utility_types::network_interface::{Inp
use graph_craft::document::NodeId;
use graph_craft::document::value::TaggedValue;
use graphene_std::Type;
+use std::borrow::Cow;
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize, specta::Type)]
pub enum FrontendGraphDataType {
@@ -98,33 +99,25 @@ pub struct FrontendNode {
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)]
pub struct FrontendNodeType {
- pub name: String,
- pub category: String,
+ pub name: Cow<'static, str>,
+ pub category: Cow<'static, str>,
#[serde(rename = "inputTypes")]
- pub input_types: Option>,
+ pub input_types: Option>>,
}
impl FrontendNodeType {
- pub fn new(name: &'static str, category: &'static str) -> Self {
+ pub fn new(name: impl Into>, category: impl Into>) -> Self {
Self {
- name: name.to_string(),
- category: category.to_string(),
+ name: name.into(),
+ category: category.into(),
input_types: None,
}
}
- pub fn with_input_types(name: &'static str, category: &'static str, input_types: Vec) -> Self {
+ pub fn with_input_types(name: impl Into>, category: impl Into>, input_types: Vec>) -> Self {
Self {
- name: name.to_string(),
- category: category.to_string(),
- input_types: Some(input_types),
- }
- }
-
- pub fn with_owned_strings_and_input_types(name: String, category: String, input_types: Vec) -> Self {
- Self {
- name,
- category,
+ name: name.into(),
+ category: category.into(),
input_types: Some(input_types),
}
}
@@ -198,7 +191,7 @@ pub struct FrontendClickTargets {
pub modify_import_export: Vec,
}
-#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)]
+#[derive(Clone, Copy, Debug, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)]
pub enum Direction {
Up,
Down,
diff --git a/editor/src/messages/portfolio/document/overlays/overlays_message_handler.rs b/editor/src/messages/portfolio/document/overlays/overlays_message_handler.rs
index 0db542da75..d4bb518e68 100644
--- a/editor/src/messages/portfolio/document/overlays/overlays_message_handler.rs
+++ b/editor/src/messages/portfolio/document/overlays/overlays_message_handler.rs
@@ -1,13 +1,14 @@
use super::utility_types::{OverlayProvider, OverlaysVisibilitySettings};
use crate::messages::prelude::*;
+#[derive(ExtractField)]
pub struct OverlaysMessageData<'a> {
pub visibility_settings: OverlaysVisibilitySettings,
pub ipp: &'a InputPreprocessorMessageHandler,
pub device_pixel_ratio: f64,
}
-#[derive(Debug, Clone, Default)]
+#[derive(Debug, Clone, Default, ExtractField)]
pub struct OverlaysMessageHandler {
pub overlay_providers: HashSet,
#[cfg(target_arch = "wasm32")]
@@ -16,6 +17,7 @@ pub struct OverlaysMessageHandler {
context: Option,
}
+#[message_handler_data]
impl MessageHandler> for OverlaysMessageHandler {
fn process_message(&mut self, message: OverlaysMessage, responses: &mut VecDeque, data: OverlaysMessageData) {
let OverlaysMessageData { visibility_settings, ipp, .. } = data;
diff --git a/editor/src/messages/portfolio/document/overlays/utility_functions.rs b/editor/src/messages/portfolio/document/overlays/utility_functions.rs
index 1e012b867a..463971c65c 100644
--- a/editor/src/messages/portfolio/document/overlays/utility_functions.rs
+++ b/editor/src/messages/portfolio/document/overlays/utility_functions.rs
@@ -119,7 +119,7 @@ pub fn path_overlays(document: &DocumentMessageHandler, draw_handles: DrawHandle
for layer in document.network_interface.selected_nodes().selected_layers(document.metadata()) {
let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else { continue };
- let transform = document.metadata().transform_to_viewport(layer);
+ let transform = document.metadata().transform_to_viewport_if_feeds(layer, &document.network_interface);
if display_path {
overlay_context.outline_vector(&vector_data, transform);
}
@@ -196,7 +196,7 @@ pub fn path_endpoint_overlays(document: &DocumentMessageHandler, shape_editor: &
continue;
};
//let document_to_viewport = document.navigation_handler.calculate_offset_transform(overlay_context.size / 2., &document.document_ptz);
- let transform = document.metadata().transform_to_viewport(layer);
+ let transform = document.metadata().transform_to_viewport_if_feeds(layer, &document.network_interface);
let selected = shape_editor.selected_shape_state.get(&layer);
let is_selected = |selected: Option<&SelectedLayerState>, point: ManipulatorPointId| selected.is_some_and(|selected| selected.is_point_selected(point));
diff --git a/editor/src/messages/portfolio/document/overlays/utility_types.rs b/editor/src/messages/portfolio/document/overlays/utility_types.rs
index a17d711a38..3d12ba4961 100644
--- a/editor/src/messages/portfolio/document/overlays/utility_types.rs
+++ b/editor/src/messages/portfolio/document/overlays/utility_types.rs
@@ -1,12 +1,12 @@
use super::utility_functions::overlay_canvas_context;
use crate::consts::{
- COLOR_OVERLAY_BLUE, COLOR_OVERLAY_BLUE_50, COLOR_OVERLAY_GREEN, COLOR_OVERLAY_RED, COLOR_OVERLAY_WHITE, COLOR_OVERLAY_YELLOW, COMPASS_ROSE_ARROW_SIZE, COMPASS_ROSE_HOVER_RING_DIAMETER,
- COMPASS_ROSE_MAIN_RING_DIAMETER, COMPASS_ROSE_RING_INNER_DIAMETER, MANIPULATOR_GROUP_MARKER_SIZE, PIVOT_CROSSHAIR_LENGTH, PIVOT_CROSSHAIR_THICKNESS, PIVOT_DIAMETER,
+ COLOR_OVERLAY_BLUE, COLOR_OVERLAY_GREEN, COLOR_OVERLAY_RED, COLOR_OVERLAY_WHITE, COLOR_OVERLAY_YELLOW, COLOR_OVERLAY_YELLOW_DULL, COMPASS_ROSE_ARROW_SIZE, COMPASS_ROSE_HOVER_RING_DIAMETER,
+ COMPASS_ROSE_MAIN_RING_DIAMETER, COMPASS_ROSE_RING_INNER_DIAMETER, DOWEL_PIN_RADIUS, MANIPULATOR_GROUP_MARKER_SIZE, PIVOT_CROSSHAIR_LENGTH, PIVOT_CROSSHAIR_THICKNESS, PIVOT_DIAMETER,
};
use crate::messages::prelude::Message;
use bezier_rs::{Bezier, Subpath};
use core::borrow::Borrow;
-use core::f64::consts::{FRAC_PI_2, TAU};
+use core::f64::consts::{FRAC_PI_2, PI, TAU};
use glam::{DAffine2, DVec2};
use graphene_std::Color;
use graphene_std::math::quad::Quad;
@@ -33,12 +33,14 @@ pub enum OverlaysType {
HoverOutline,
SelectionOutline,
Pivot,
+ Origin,
Path,
Anchors,
Handles,
}
#[derive(PartialEq, Copy, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)]
+#[serde(default)]
pub struct OverlaysVisibilitySettings {
pub all: bool,
pub artboard_name: bool,
@@ -49,6 +51,7 @@ pub struct OverlaysVisibilitySettings {
pub hover_outline: bool,
pub selection_outline: bool,
pub pivot: bool,
+ pub origin: bool,
pub path: bool,
pub anchors: bool,
pub handles: bool,
@@ -66,6 +69,7 @@ impl Default for OverlaysVisibilitySettings {
hover_outline: true,
selection_outline: true,
pivot: true,
+ origin: true,
path: true,
anchors: true,
handles: true,
@@ -110,6 +114,10 @@ impl OverlaysVisibilitySettings {
self.all && self.pivot
}
+ pub fn origin(&self) -> bool {
+ self.all && self.origin
+ }
+
pub fn path(&self) -> bool {
self.all && self.path
}
@@ -423,10 +431,7 @@ impl OverlayContext {
pub fn draw_scale(&mut self, start: DVec2, scale: f64, radius: f64, text: &str) {
let sign = scale.signum();
- let mut fill_color = graphene_std::Color::from_rgb_str(crate::consts::COLOR_OVERLAY_WHITE.strip_prefix('#').unwrap())
- .unwrap()
- .with_alpha(0.05)
- .to_rgba_hex_srgb();
+ let mut fill_color = Color::from_rgb_str(COLOR_OVERLAY_WHITE.strip_prefix('#').unwrap()).unwrap().with_alpha(0.05).to_rgba_hex_srgb();
fill_color.insert(0, '#');
let fill_color = Some(fill_color.as_str());
self.line(start + DVec2::X * radius * sign, start + DVec2::X * (radius * scale), None, None);
@@ -463,10 +468,7 @@ impl OverlayContext {
// Hover ring
if show_hover_ring {
- let mut fill_color = graphene_std::Color::from_rgb_str(COLOR_OVERLAY_BLUE.strip_prefix('#').unwrap())
- .unwrap()
- .with_alpha(0.5)
- .to_rgba_hex_srgb();
+ let mut fill_color = Color::from_rgb_str(COLOR_OVERLAY_BLUE.strip_prefix('#').unwrap()).unwrap().with_alpha(0.5).to_rgba_hex_srgb();
fill_color.insert(0, '#');
self.render_context.set_line_width(HOVER_RING_STROKE_WIDTH);
@@ -550,6 +552,36 @@ impl OverlayContext {
self.end_dpi_aware_transform();
}
+ pub fn dowel_pin(&mut self, position: DVec2, angle: f64, color: Option<&str>) {
+ let (x, y) = (position.round() - DVec2::splat(0.5)).into();
+ let color = color.unwrap_or(COLOR_OVERLAY_YELLOW_DULL);
+
+ self.start_dpi_aware_transform();
+
+ // Draw the background circle with a white fill and blue outline
+ self.render_context.begin_path();
+ self.render_context.arc(x, y, DOWEL_PIN_RADIUS, 0., TAU).expect("Failed to draw the circle");
+ self.render_context.set_fill_style_str(COLOR_OVERLAY_WHITE);
+ self.render_context.fill();
+ self.render_context.set_stroke_style_str(color);
+ self.render_context.stroke();
+
+ // Draw the two blue filled sectors
+ self.render_context.begin_path();
+ // Top-left sector
+ self.render_context.move_to(x, y);
+ self.render_context.arc(x, y, DOWEL_PIN_RADIUS, FRAC_PI_2 + angle, PI + angle).expect("Failed to draw arc");
+ self.render_context.close_path();
+ // Bottom-right sector
+ self.render_context.move_to(x, y);
+ self.render_context.arc(x, y, DOWEL_PIN_RADIUS, PI + FRAC_PI_2 + angle, TAU + angle).expect("Failed to draw arc");
+ self.render_context.close_path();
+ self.render_context.set_fill_style_str(color);
+ self.render_context.fill();
+
+ self.end_dpi_aware_transform();
+ }
+
/// Used by the Pen and Path tools to outline the path of the shape.
pub fn outline_vector(&mut self, vector_data: &VectorData, transform: DAffine2) {
self.start_dpi_aware_transform();
@@ -599,9 +631,11 @@ impl OverlayContext {
pub fn outline_overlay_bezier(&mut self, bezier: Bezier, transform: DAffine2) {
self.start_dpi_aware_transform();
+ let color = Color::from_rgb_str(COLOR_OVERLAY_BLUE.strip_prefix('#').unwrap()).unwrap().with_alpha(0.05).to_rgba_hex_srgb();
+
self.render_context.begin_path();
self.bezier_command(bezier, transform, true);
- self.render_context.set_stroke_style_str(COLOR_OVERLAY_BLUE_50);
+ self.render_context.set_stroke_style_str(&color);
self.render_context.set_line_width(4.);
self.render_context.stroke();
@@ -731,11 +765,11 @@ impl OverlayContext {
// └──┴──┴──┴──┘
let pixels = [(0, 0), (2, 2)];
for &(x, y) in &pixels {
- let index = (x + y * PATTERN_WIDTH as usize) * 4;
+ let index = (x + y * PATTERN_WIDTH) * 4;
data[index..index + 4].copy_from_slice(&color.to_rgba8_srgb());
}
- let image_data = web_sys::ImageData::new_with_u8_clamped_array_and_sh(wasm_bindgen::Clamped(&mut data), PATTERN_WIDTH as u32, PATTERN_HEIGHT as u32).unwrap();
+ let image_data = web_sys::ImageData::new_with_u8_clamped_array_and_sh(wasm_bindgen::Clamped(&data), PATTERN_WIDTH as u32, PATTERN_HEIGHT as u32).unwrap();
pattern_context.put_image_data(&image_data, 0., 0.).unwrap();
let pattern = self.render_context.create_pattern_with_offscreen_canvas(&pattern_canvas, "repeat").unwrap().unwrap();
@@ -780,6 +814,36 @@ impl OverlayContext {
self.render_context.fill_text(text, 0., 0.).expect("Failed to draw the text at the calculated position");
self.render_context.reset_transform().expect("Failed to reset the render context transform");
}
+
+ pub fn translation_box(&mut self, translation: DVec2, quad: Quad, typed_string: Option) {
+ if translation.x.abs() > 1e-3 {
+ self.dashed_line(quad.top_left(), quad.top_right(), None, None, Some(2.), Some(2.), Some(0.5));
+
+ let width = match typed_string {
+ Some(ref typed_string) => typed_string,
+ None => &format!("{:.2}", translation.x).trim_end_matches('0').trim_end_matches('.').to_string(),
+ };
+ let x_transform = DAffine2::from_translation((quad.top_left() + quad.top_right()) / 2.);
+ self.text(width, COLOR_OVERLAY_BLUE, None, x_transform, 4., [Pivot::Middle, Pivot::End]);
+ }
+
+ if translation.y.abs() > 1e-3 {
+ self.dashed_line(quad.top_left(), quad.bottom_left(), None, None, Some(2.), Some(2.), Some(0.5));
+
+ let height = match typed_string {
+ Some(ref typed_string) => typed_string,
+ None => &format!("{:.2}", translation.y).trim_end_matches('0').trim_end_matches('.').to_string(),
+ };
+ let y_transform = DAffine2::from_translation((quad.top_left() + quad.bottom_left()) / 2.);
+ let height_pivot = if translation.x > -1e-3 { Pivot::Start } else { Pivot::End };
+ self.text(height, COLOR_OVERLAY_BLUE, None, y_transform, 3., [height_pivot, Pivot::Middle]);
+ }
+
+ if translation.x.abs() > 1e-3 && translation.y.abs() > 1e-3 {
+ self.line(quad.top_right(), quad.bottom_right(), None, None);
+ self.line(quad.bottom_left(), quad.bottom_right(), None, None);
+ }
+ }
}
pub enum Pivot {
diff --git a/editor/src/messages/portfolio/document/properties_panel/properties_panel_message_handler.rs b/editor/src/messages/portfolio/document/properties_panel/properties_panel_message_handler.rs
index a783b24aae..3ca9f350f3 100644
--- a/editor/src/messages/portfolio/document/properties_panel/properties_panel_message_handler.rs
+++ b/editor/src/messages/portfolio/document/properties_panel/properties_panel_message_handler.rs
@@ -4,9 +4,10 @@ use crate::messages::portfolio::document::node_graph::document_node_definitions:
use crate::messages::portfolio::utility_types::PersistentData;
use crate::messages::prelude::*;
-#[derive(Debug, Clone, Default)]
+#[derive(Debug, Clone, Default, ExtractField)]
pub struct PropertiesPanelMessageHandler {}
+#[message_handler_data]
impl MessageHandler)> for PropertiesPanelMessageHandler {
fn process_message(&mut self, message: PropertiesPanelMessage, responses: &mut VecDeque, (persistent_data, data): (&PersistentData, PropertiesPanelMessageHandlerData)) {
let PropertiesPanelMessageHandlerData {
diff --git a/editor/src/messages/portfolio/document/utility_types/document_metadata.rs b/editor/src/messages/portfolio/document/utility_types/document_metadata.rs
index 23887db3e5..0b6f65bc87 100644
--- a/editor/src/messages/portfolio/document/utility_types/document_metadata.rs
+++ b/editor/src/messages/portfolio/document/utility_types/document_metadata.rs
@@ -1,6 +1,8 @@
use super::network_interface::NodeNetworkInterface;
use crate::messages::portfolio::document::graph_operation::transform_utils;
use crate::messages::portfolio::document::graph_operation::utility_types::ModifyInputsContext;
+use crate::messages::portfolio::document::utility_types::network_interface::FlowType;
+use crate::messages::tool::common_functionality::graph_modification_utils;
use glam::{DAffine2, DVec2};
use graph_craft::document::NodeId;
use graphene_std::math::quad::Quad;
@@ -16,10 +18,11 @@ use std::num::NonZeroU64;
// TODO: To avoid storing a stateful snapshot of some other system's state (which is easily to accidentally get out of sync),
// TODO: it might be better to have a system that can query the state of the node network on demand.
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, Default)]
pub struct DocumentMetadata {
pub upstream_footprints: HashMap,
pub local_transforms: HashMap,
+ pub first_instance_source_ids: HashMap>,
pub structure: HashMap,
pub click_targets: HashMap>,
pub clip_targets: HashSet,
@@ -28,20 +31,6 @@ pub struct DocumentMetadata {
pub document_to_viewport: DAffine2,
}
-impl Default for DocumentMetadata {
- fn default() -> Self {
- Self {
- upstream_footprints: HashMap::new(),
- local_transforms: HashMap::new(),
- structure: HashMap::new(),
- vector_modify: HashMap::new(),
- click_targets: HashMap::new(),
- clip_targets: HashSet::new(),
- document_to_viewport: DAffine2::IDENTITY,
- }
- }
-}
-
// =================================
// DocumentMetadata: Layer iterators
// =================================
@@ -91,6 +80,36 @@ impl DocumentMetadata {
footprint * local_transform
}
+ pub fn transform_to_viewport_if_feeds(&self, layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> DAffine2 {
+ // We're not allowed to convert the root parent to a node id
+ if layer == LayerNodeIdentifier::ROOT_PARENT {
+ return self.document_to_viewport;
+ }
+
+ let footprint = self.upstream_footprints.get(&layer.to_node()).map(|footprint| footprint.transform).unwrap_or(self.document_to_viewport);
+
+ let mut use_local = true;
+ let graph_layer = graph_modification_utils::NodeGraphLayer::new(layer, network_interface);
+ if let Some(path_node) = graph_layer.upstream_node_id_from_name("Path") {
+ if let Some(&source) = self.first_instance_source_ids.get(&layer.to_node()) {
+ if !network_interface
+ .upstream_flow_back_from_nodes(vec![path_node], &[], FlowType::HorizontalFlow)
+ .any(|upstream| Some(upstream) == source)
+ {
+ use_local = false;
+ info!("Local transform is invalid — using the identity for the local transform instead")
+ }
+ }
+ }
+ let local_transform = use_local.then(|| self.local_transforms.get(&layer.to_node()).copied()).flatten().unwrap_or_default();
+
+ footprint * local_transform
+ }
+
+ pub fn transform_to_document_if_feeds(&self, layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> DAffine2 {
+ self.document_to_viewport.inverse() * self.transform_to_viewport_if_feeds(layer, network_interface)
+ }
+
pub fn transform_to_viewport_with_first_transform_node_if_group(&self, layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> DAffine2 {
let footprint = self.upstream_footprints.get(&layer.to_node()).map(|footprint| footprint.transform).unwrap_or(self.document_to_viewport);
let local_transform = self.local_transforms.get(&layer.to_node()).copied();
diff --git a/editor/src/messages/portfolio/document/utility_types/network_interface.rs b/editor/src/messages/portfolio/document/utility_types/network_interface.rs
index c4255120af..404d3486a0 100644
--- a/editor/src/messages/portfolio/document/utility_types/network_interface.rs
+++ b/editor/src/messages/portfolio/document/utility_types/network_interface.rs
@@ -60,6 +60,27 @@ impl PartialEq for NodeNetworkInterface {
}
}
+impl NodeNetworkInterface {
+ /// Add DocumentNodePath input to the PathModifyNode protonode
+ pub fn migrate_path_modify_node(&mut self) {
+ fix_network(&mut self.network);
+ fn fix_network(network: &mut NodeNetwork) {
+ for node in network.nodes.values_mut() {
+ if let Some(network) = node.implementation.get_network_mut() {
+ fix_network(network);
+ }
+ if let DocumentNodeImplementation::ProtoNode(protonode) = &node.implementation {
+ if protonode.name.contains("PathModifyNode") {
+ if node.inputs.len() < 3 {
+ node.inputs.push(NodeInput::Reflection(graph_craft::document::DocumentNodeMetadata::DocumentNodePath));
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
// Public immutable getters for the network interface
impl NodeNetworkInterface {
// TODO: Make private and use .field_name getter methods
@@ -653,7 +674,7 @@ impl NodeNetworkInterface {
let input_type = self.input_type(&InputConnector::node(*node_id, iterator_index), network_path).0;
// Value inputs are stored as concrete, so they are compared to the nested type. Node inputs are stored as fn, so they are compared to the entire type.
// For example a node input of (Footprint) -> VectorData would not be compatible with () -> VectorData
- node_io.inputs[iterator_index].clone().nested_type() == &input_type || node_io.inputs[iterator_index] == input_type
+ node_io.inputs.get(iterator_index).map(|ty| ty.nested_type().clone()).as_ref() == Some(&input_type) || node_io.inputs.get(iterator_index) == Some(&input_type)
});
if valid_implementation { node_io.inputs.get(*input_index).cloned() } else { None }
})
@@ -3513,6 +3534,11 @@ impl NodeNetworkInterface {
self.document_metadata.local_transforms = local_transforms;
}
+ /// Update the cached first instance source id of the layers
+ pub fn update_first_instance_source_id(&mut self, new: HashMap>) {
+ self.document_metadata.first_instance_source_ids = new;
+ }
+
/// Update the cached click targets of the layers
pub fn update_click_targets(&mut self, new_click_targets: HashMap>) {
self.document_metadata.click_targets = new_click_targets;
diff --git a/editor/src/messages/portfolio/document/utility_types/nodes.rs b/editor/src/messages/portfolio/document/utility_types/nodes.rs
index d81f1693d7..66369026b3 100644
--- a/editor/src/messages/portfolio/document/utility_types/nodes.rs
+++ b/editor/src/messages/portfolio/document/utility_types/nodes.rs
@@ -1,5 +1,7 @@
use super::document_metadata::{DocumentMetadata, LayerNodeIdentifier};
use super::network_interface::NodeNetworkInterface;
+use crate::messages::tool::common_functionality::graph_modification_utils;
+use glam::DVec2;
use graph_craft::document::{NodeId, NodeNetwork};
use serde::ser::SerializeStruct;
@@ -98,6 +100,22 @@ impl SelectedNodes {
.filter(move |&layer| self.layer_visible(layer, network_interface) && !self.layer_locked(layer, network_interface))
}
+ pub fn selected_visible_and_unlocked_layers_mean_average_origin<'a>(&'a self, network_interface: &'a NodeNetworkInterface) -> DVec2 {
+ let (sum, count) = self
+ .selected_visible_and_unlocked_layers(network_interface)
+ .map(|layer| graph_modification_utils::get_viewport_origin(layer, network_interface))
+ .fold((glam::DVec2::ZERO, 0), |(sum, count), item| (sum + item, count + 1));
+ if count == 0 { DVec2::ZERO } else { sum / count as f64 }
+ }
+
+ pub fn selected_visible_and_unlocked_median_points<'a>(&'a self, network_interface: &'a NodeNetworkInterface) -> DVec2 {
+ let (sum, count) = self
+ .selected_visible_and_unlocked_layers(network_interface)
+ .map(|layer| graph_modification_utils::get_viewport_center(layer, network_interface))
+ .fold((glam::DVec2::ZERO, 0), |(sum, count), item| (sum + item, count + 1));
+ if count == 0 { DVec2::ZERO } else { sum / count as f64 }
+ }
+
pub fn selected_layers<'a>(&'a self, metadata: &'a DocumentMetadata) -> impl Iterator- + 'a {
metadata.all_layers().filter(|layer| self.0.contains(&layer.to_node()))
}
diff --git a/editor/src/messages/portfolio/document/utility_types/transformation.rs b/editor/src/messages/portfolio/document/utility_types/transformation.rs
index e0149939a5..cefcb61418 100644
--- a/editor/src/messages/portfolio/document/utility_types/transformation.rs
+++ b/editor/src/messages/portfolio/document/utility_types/transformation.rs
@@ -4,7 +4,6 @@ use crate::messages::portfolio::document::graph_operation::transform_utils;
use crate::messages::portfolio::document::graph_operation::utility_types::{ModifyInputsContext, TransformIn};
use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier};
use crate::messages::prelude::*;
-use crate::messages::tool::common_functionality::graph_modification_utils;
use crate::messages::tool::common_functionality::shape_editor::ShapeState;
use crate::messages::tool::utility_types::ToolType;
use glam::{DAffine2, DMat2, DVec2};
@@ -537,17 +536,6 @@ impl<'a> Selected<'a> {
}
}
- pub fn mean_average_of_pivots(&mut self) -> DVec2 {
- let xy_summation = self
- .selected
- .iter()
- .map(|&layer| graph_modification_utils::get_viewport_pivot(layer, self.network_interface))
- .reduce(|a, b| a + b)
- .unwrap_or_default();
-
- xy_summation / self.selected.len() as f64
- }
-
pub fn center_of_aabb(&mut self) -> DVec2 {
let [min, max] = self
.selected
diff --git a/editor/src/messages/portfolio/document_migration.rs b/editor/src/messages/portfolio/document_migration.rs
index 20ce8ea8e0..e4db26d2ec 100644
--- a/editor/src/messages/portfolio/document_migration.rs
+++ b/editor/src/messages/portfolio/document_migration.rs
@@ -7,6 +7,7 @@ use crate::messages::portfolio::document::utility_types::network_interface::{Inp
use crate::messages::prelude::DocumentMessageHandler;
use bezier_rs::Subpath;
use glam::IVec2;
+use graph_craft::document::DocumentNode;
use graph_craft::document::{DocumentNodeImplementation, NodeInput, value::TaggedValue};
use graphene_std::text::TypesettingConfig;
use graphene_std::uuid::NodeId;
@@ -190,6 +191,8 @@ pub fn document_migration_reset_node_definition(document_serialized_content: &st
}
pub fn document_migration_upgrades(document: &mut DocumentMessageHandler, reset_node_definitions_on_open: bool) {
+ document.network_interface.migrate_path_modify_node();
+
let network = document.network_interface.document_network().clone();
// Apply string replacements to each node
@@ -215,468 +218,476 @@ pub fn document_migration_upgrades(document: &mut DocumentMessageHandler, reset_
.map(|(node_id, node, path)| (*node_id, node.clone(), path))
.collect::)>>();
for (node_id, node, network_path) in &nodes {
- if reset_node_definitions_on_open {
- if let Some(Some(reference)) = document.network_interface.reference(node_id, network_path) {
- let Some(node_definition) = resolve_document_node_type(reference) else { continue };
- document.network_interface.replace_implementation(node_id, network_path, &mut node_definition.default_node_template());
- }
+ migrate_node(node_id, node, network_path, document, reset_node_definitions_on_open);
+ }
+}
+
+fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId], document: &mut DocumentMessageHandler, reset_node_definitions_on_open: bool) -> Option<()> {
+ if reset_node_definitions_on_open {
+ if let Some(Some(reference)) = document.network_interface.reference(node_id, network_path) {
+ let node_definition = resolve_document_node_type(reference)?;
+ document.network_interface.replace_implementation(node_id, network_path, &mut node_definition.default_node_template());
+ }
+ }
+
+ // Upgrade old nodes to use `Context` instead of `()` or `Footprint` for manual composition
+ if node.manual_composition == Some(graph_craft::concrete!(())) || node.manual_composition == Some(graph_craft::concrete!(graphene_std::transform::Footprint)) {
+ document
+ .network_interface
+ .set_manual_compostion(node_id, network_path, graph_craft::concrete!(graphene_std::Context).into());
+ }
+
+ // Only nodes that have not been modified and still refer to a definition can be updated
+ let reference = document.network_interface.reference(node_id, network_path).cloned().flatten()?;
+ let reference = &reference;
+
+ let inputs_count = node.inputs.len();
+
+ // Upgrade Stroke node to reorder parameters and add "Align" and "Paint Order" (#2644)
+ if reference == "Stroke" && inputs_count == 8 {
+ let mut node_template = resolve_document_node_type(reference)?.default_node_template();
+ let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?;
+
+ let align_input = NodeInput::value(TaggedValue::StrokeAlign(StrokeAlign::Center), false);
+ let paint_order_input = NodeInput::value(TaggedValue::PaintOrder(PaintOrder::StrokeAbove), false);
+
+ document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path);
+ document.network_interface.set_input(&InputConnector::node(*node_id, 1), old_inputs[1].clone(), network_path);
+ document.network_interface.set_input(&InputConnector::node(*node_id, 2), old_inputs[2].clone(), network_path);
+ document.network_interface.set_input(&InputConnector::node(*node_id, 3), align_input, network_path);
+ document.network_interface.set_input(&InputConnector::node(*node_id, 4), old_inputs[5].clone(), network_path);
+ document.network_interface.set_input(&InputConnector::node(*node_id, 5), old_inputs[6].clone(), network_path);
+ document.network_interface.set_input(&InputConnector::node(*node_id, 6), old_inputs[7].clone(), network_path);
+ document.network_interface.set_input(&InputConnector::node(*node_id, 7), paint_order_input, network_path);
+ document.network_interface.set_input(&InputConnector::node(*node_id, 8), old_inputs[3].clone(), network_path);
+ document.network_interface.set_input(&InputConnector::node(*node_id, 9), old_inputs[4].clone(), network_path);
+ }
+
+ // Rename the old "Splines from Points" node to "Spline" and upgrade it to the new "Spline" node
+ if reference == "Splines from Points" {
+ document.network_interface.set_reference(node_id, network_path, Some("Spline".to_string()));
+ }
+
+ // Upgrade the old "Spline" node to the new "Spline" node
+ if reference == "Spline" {
+ // Retrieve the proto node identifier and verify it is the old "Spline" node, otherwise skip it if this is the new "Spline" node
+ let identifier = document
+ .network_interface
+ .implementation(node_id, network_path)
+ .and_then(|implementation| implementation.get_proto_node());
+ if identifier.map(|identifier| &identifier.name) != Some(&"graphene_core::vector::generator_nodes::SplineNode".into()) {
+ return None;
}
- // Upgrade old nodes to use `Context` instead of `()` or `Footprint` for manual composition
- if node.manual_composition == Some(graph_craft::concrete!(())) || node.manual_composition == Some(graph_craft::concrete!(graphene_std::transform::Footprint)) {
- document
- .network_interface
- .set_manual_compostion(node_id, network_path, graph_craft::concrete!(graphene_std::Context).into());
- }
-
- let Some(Some(reference)) = document.network_interface.reference(node_id, network_path).cloned() else {
- // Only nodes that have not been modified and still refer to a definition can be updated
- continue;
+ // Obtain the document node for the given node ID, extract the vector points, and create vector data from the list of points
+ let node = document.network_interface.document_node(node_id, network_path)?;
+ let Some(TaggedValue::VecDVec2(points)) = node.inputs.get(1).and_then(|tagged_value| tagged_value.as_value()) else {
+ log::error!("The old Spline node's input at index 1 is not a TaggedValue::VecDVec2");
+ return None;
};
- let reference = &reference;
+ let vector_data = VectorData::from_subpath(Subpath::from_anchors_linear(points.to_vec(), false));
- let inputs_count = node.inputs.len();
+ // Retrieve the output connectors linked to the "Spline" node's output port
+ let Some(spline_outputs) = document.network_interface.outward_wires(network_path)?.get(&OutputConnector::node(*node_id, 0)).cloned() else {
+ log::error!("Vec of InputConnector Spline node is connected to its output port 0.");
+ return None;
+ };
- // Upgrade Stroke node to reorder parameters and add "Align" and "Paint Order" (#2644)
- if reference == "Stroke" && inputs_count == 8 {
- let mut node_template = resolve_document_node_type(reference).unwrap().default_node_template();
- let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template).unwrap();
+ // Get the node's current position in the graph
+ let Some(node_position) = document.network_interface.position(node_id, network_path) else {
+ log::error!("Could not get position of spline node.");
+ return None;
+ };
- let align_input = NodeInput::value(TaggedValue::StrokeAlign(StrokeAlign::Center), false);
- let paint_order_input = NodeInput::value(TaggedValue::PaintOrder(PaintOrder::StrokeAbove), false);
+ // Get the "Path" node definition and fill it in with the vector data and default vector modification
+ let Some(path_node_type) = resolve_document_node_type("Path") else {
+ log::error!("Path node does not exist.");
+ return None;
+ };
+ let path_node = path_node_type.node_template_input_override([
+ Some(NodeInput::value(TaggedValue::VectorData(VectorDataTable::new(vector_data)), true)),
+ Some(NodeInput::value(TaggedValue::VectorModification(Default::default()), false)),
+ ]);
- document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path);
- document.network_interface.set_input(&InputConnector::node(*node_id, 1), old_inputs[1].clone(), network_path);
- document.network_interface.set_input(&InputConnector::node(*node_id, 2), old_inputs[2].clone(), network_path);
- document.network_interface.set_input(&InputConnector::node(*node_id, 3), align_input, network_path);
- document.network_interface.set_input(&InputConnector::node(*node_id, 4), old_inputs[5].clone(), network_path);
- document.network_interface.set_input(&InputConnector::node(*node_id, 5), old_inputs[6].clone(), network_path);
- document.network_interface.set_input(&InputConnector::node(*node_id, 6), old_inputs[7].clone(), network_path);
- document.network_interface.set_input(&InputConnector::node(*node_id, 7), paint_order_input, network_path);
- document.network_interface.set_input(&InputConnector::node(*node_id, 8), old_inputs[3].clone(), network_path);
- document.network_interface.set_input(&InputConnector::node(*node_id, 9), old_inputs[4].clone(), network_path);
+ // Get the "Spline" node definition and wire it up with the "Path" node as input
+ let Some(spline_node_type) = resolve_document_node_type("Spline") else {
+ log::error!("Spline node does not exist.");
+ return None;
+ };
+ let spline_node = spline_node_type.node_template_input_override([Some(NodeInput::node(NodeId(1), 0))]);
+
+ // Create a new node group with the "Path" and "Spline" nodes and generate new node IDs for them
+ let nodes = vec![(NodeId(1), path_node), (NodeId(0), spline_node)];
+ let new_ids = nodes.iter().map(|(id, _)| (*id, NodeId::new())).collect::>();
+ let new_spline_id = *new_ids.get(&NodeId(0))?;
+ let new_path_id = *new_ids.get(&NodeId(1))?;
+
+ // Remove the old "Spline" node from the document
+ document.network_interface.delete_nodes(vec![*node_id], false, network_path);
+
+ // Insert the new "Path" and "Spline" nodes into the network interface with generated IDs
+ document.network_interface.insert_node_group(nodes.clone(), new_ids, network_path);
+
+ // Reposition the new "Spline" node to match the original "Spline" node's position
+ document.network_interface.shift_node(&new_spline_id, node_position, network_path);
+
+ // Reposition the new "Path" node with an offset relative to the original "Spline" node's position
+ document.network_interface.shift_node(&new_path_id, node_position + IVec2::new(-7, 0), network_path);
+
+ // Redirect each output connection from the old node to the new "Spline" node's output port
+ for input_connector in spline_outputs {
+ document.network_interface.set_input(&input_connector, NodeInput::node(new_spline_id, 0), network_path);
}
+ }
- // Rename the old "Splines from Points" node to "Spline" and upgrade it to the new "Spline" node
- if reference == "Splines from Points" {
- document.network_interface.set_reference(node_id, network_path, Some("Spline".to_string()));
+ // Upgrade Text node to include line height and character spacing, which were previously hardcoded to 1, from https://github.com/GraphiteEditor/Graphite/pull/2016
+ if reference == "Text" && inputs_count != 9 {
+ let mut template = resolve_document_node_type(reference)?.default_node_template();
+ document.network_interface.replace_implementation(node_id, network_path, &mut template);
+ let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut template)?;
+
+ document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path);
+ document.network_interface.set_input(&InputConnector::node(*node_id, 1), old_inputs[1].clone(), network_path);
+ document.network_interface.set_input(&InputConnector::node(*node_id, 2), old_inputs[2].clone(), network_path);
+ document.network_interface.set_input(&InputConnector::node(*node_id, 3), old_inputs[3].clone(), network_path);
+ document.network_interface.set_input(
+ &InputConnector::node(*node_id, 4),
+ if inputs_count == 6 {
+ old_inputs[4].clone()
+ } else {
+ NodeInput::value(TaggedValue::F64(TypesettingConfig::default().line_height_ratio), false)
+ },
+ network_path,
+ );
+ document.network_interface.set_input(
+ &InputConnector::node(*node_id, 5),
+ if inputs_count == 6 {
+ old_inputs[5].clone()
+ } else {
+ NodeInput::value(TaggedValue::F64(TypesettingConfig::default().character_spacing), false)
+ },
+ network_path,
+ );
+ document.network_interface.set_input(
+ &InputConnector::node(*node_id, 6),
+ if inputs_count >= 7 {
+ old_inputs[6].clone()
+ } else {
+ NodeInput::value(TaggedValue::OptionalF64(TypesettingConfig::default().max_width), false)
+ },
+ network_path,
+ );
+ document.network_interface.set_input(
+ &InputConnector::node(*node_id, 7),
+ if inputs_count >= 8 {
+ old_inputs[7].clone()
+ } else {
+ NodeInput::value(TaggedValue::OptionalF64(TypesettingConfig::default().max_height), false)
+ },
+ network_path,
+ );
+ document.network_interface.set_input(
+ &InputConnector::node(*node_id, 8),
+ if inputs_count >= 9 {
+ old_inputs[8].clone()
+ } else {
+ NodeInput::value(TaggedValue::F64(TypesettingConfig::default().tilt), false)
+ },
+ network_path,
+ );
+ }
+
+ // Upgrade Sine, Cosine, and Tangent nodes to include a boolean input for whether the output should be in radians, which was previously the only option but is now not the default
+ if (reference == "Sine" || reference == "Cosine" || reference == "Tangent") && inputs_count == 1 {
+ let mut node_template = resolve_document_node_type(reference)?.default_node_template();
+ document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
+
+ let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?;
+
+ document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path);
+ document
+ .network_interface
+ .set_input(&InputConnector::node(*node_id, 1), NodeInput::value(TaggedValue::Bool(true), false), network_path);
+ }
+
+ // Upgrade the Modulo node to include a boolean input for whether the output should be always positive, which was previously not an option
+ if reference == "Modulo" && inputs_count == 2 {
+ let mut node_template = resolve_document_node_type(reference)?.default_node_template();
+ document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
+
+ let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?;
+
+ document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path);
+ document.network_interface.set_input(&InputConnector::node(*node_id, 1), old_inputs[1].clone(), network_path);
+ document
+ .network_interface
+ .set_input(&InputConnector::node(*node_id, 2), NodeInput::value(TaggedValue::Bool(false), false), network_path);
+ }
+
+ // Upgrade the Mirror node to add the `keep_original` boolean input
+ if reference == "Mirror" && inputs_count == 3 {
+ let mut node_template = resolve_document_node_type(reference)?.default_node_template();
+ document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
+
+ let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?;
+
+ document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path);
+ document.network_interface.set_input(&InputConnector::node(*node_id, 1), old_inputs[1].clone(), network_path);
+ document.network_interface.set_input(&InputConnector::node(*node_id, 2), old_inputs[2].clone(), network_path);
+ document
+ .network_interface
+ .set_input(&InputConnector::node(*node_id, 3), NodeInput::value(TaggedValue::Bool(true), false), network_path);
+ }
+
+ // Upgrade the Mirror node to add the `reference_point` input and change `offset` from `DVec2` to `f64`
+ if reference == "Mirror" && inputs_count == 4 {
+ let mut node_template = resolve_document_node_type(reference)?.default_node_template();
+ document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
+
+ let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?;
+
+ let Some(&TaggedValue::DVec2(old_offset)) = old_inputs[1].as_value() else { return None };
+ let old_offset = if old_offset.x.abs() > old_offset.y.abs() { old_offset.x } else { old_offset.y };
+
+ document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path);
+ document.network_interface.set_input(
+ &InputConnector::node(*node_id, 1),
+ NodeInput::value(TaggedValue::ReferencePoint(graphene_std::transform::ReferencePoint::Center), false),
+ network_path,
+ );
+ document
+ .network_interface
+ .set_input(&InputConnector::node(*node_id, 2), NodeInput::value(TaggedValue::F64(old_offset), false), network_path);
+ document.network_interface.set_input(&InputConnector::node(*node_id, 3), old_inputs[2].clone(), network_path);
+ document.network_interface.set_input(&InputConnector::node(*node_id, 4), old_inputs[3].clone(), network_path);
+ }
+
+ // Upgrade artboard name being passed as hidden value input to "To Artboard"
+ if reference == "Artboard" && reset_node_definitions_on_open {
+ let label = document.network_interface.display_name(node_id, network_path);
+ document
+ .network_interface
+ .set_input(&InputConnector::node(NodeId(0), 1), NodeInput::value(TaggedValue::String(label), false), &[*node_id]);
+ }
+
+ if reference == "Image" && inputs_count == 1 {
+ let mut node_template = resolve_document_node_type(reference)?.default_node_template();
+ document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
+
+ // Insert a new empty input for the image
+ document.network_interface.add_import(TaggedValue::None, false, 0, "Empty", "", &[*node_id]);
+ document.network_interface.set_reference(node_id, network_path, Some("Image".to_string()));
+ }
+
+ if reference == "Noise Pattern" && inputs_count == 15 {
+ let mut node_template = resolve_document_node_type(reference)?.default_node_template();
+ document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
+
+ let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?;
+
+ document
+ .network_interface
+ .set_input(&InputConnector::node(*node_id, 0), NodeInput::value(TaggedValue::None, false), network_path);
+ for (i, input) in old_inputs.iter().enumerate() {
+ document.network_interface.set_input(&InputConnector::node(*node_id, i + 1), input.clone(), network_path);
}
+ }
- // Upgrade the old "Spline" node to the new "Spline" node
- if reference == "Spline" {
- // Retrieve the proto node identifier and verify it is the old "Spline" node, otherwise skip it if this is the new "Spline" node
- let identifier = document
- .network_interface
- .implementation(node_id, network_path)
- .and_then(|implementation| implementation.get_proto_node());
- if identifier.map(|identifier| &identifier.name) != Some(&"graphene_core::vector::generator_nodes::SplineNode".into()) {
- continue;
- }
-
- // Obtain the document node for the given node ID, extract the vector points, and create vector data from the list of points
- let node = document.network_interface.document_node(node_id, network_path).unwrap();
- let Some(TaggedValue::VecDVec2(points)) = node.inputs.get(1).and_then(|tagged_value| tagged_value.as_value()) else {
- log::error!("The old Spline node's input at index 1 is not a TaggedValue::VecDVec2");
- continue;
- };
- let vector_data = VectorData::from_subpath(Subpath::from_anchors_linear(points.to_vec(), false));
-
- // Retrieve the output connectors linked to the "Spline" node's output port
- let spline_outputs = document
- .network_interface
- .outward_wires(network_path)
- .unwrap()
- .get(&OutputConnector::node(*node_id, 0))
- .expect("Vec of InputConnector Spline node is connected to its output port 0.")
- .clone();
-
- // Get the node's current position in the graph
- let Some(node_position) = document.network_interface.position(node_id, network_path) else {
- log::error!("Could not get position of spline node.");
- continue;
- };
-
- // Get the "Path" node definition and fill it in with the vector data and default vector modification
- let path_node_type = resolve_document_node_type("Path").expect("Path node does not exist.");
- let path_node = path_node_type.node_template_input_override([
- Some(NodeInput::value(TaggedValue::VectorData(VectorDataTable::new(vector_data)), true)),
- Some(NodeInput::value(TaggedValue::VectorModification(Default::default()), false)),
- ]);
-
- // Get the "Spline" node definition and wire it up with the "Path" node as input
- let spline_node_type = resolve_document_node_type("Spline").expect("Spline node does not exist.");
- let spline_node = spline_node_type.node_template_input_override([Some(NodeInput::node(NodeId(1), 0))]);
-
- // Create a new node group with the "Path" and "Spline" nodes and generate new node IDs for them
- let nodes = vec![(NodeId(1), path_node), (NodeId(0), spline_node)];
- let new_ids = nodes.iter().map(|(id, _)| (*id, NodeId::new())).collect::>();
- let new_spline_id = *new_ids.get(&NodeId(0)).unwrap();
- let new_path_id = *new_ids.get(&NodeId(1)).unwrap();
-
- // Remove the old "Spline" node from the document
- document.network_interface.delete_nodes(vec![*node_id], false, network_path);
-
- // Insert the new "Path" and "Spline" nodes into the network interface with generated IDs
- document.network_interface.insert_node_group(nodes.clone(), new_ids, network_path);
-
- // Reposition the new "Spline" node to match the original "Spline" node's position
- document.network_interface.shift_node(&new_spline_id, node_position, network_path);
-
- // Reposition the new "Path" node with an offset relative to the original "Spline" node's position
- document.network_interface.shift_node(&new_path_id, node_position + IVec2::new(-7, 0), network_path);
-
- // Redirect each output connection from the old node to the new "Spline" node's output port
- for input_connector in spline_outputs {
- document.network_interface.set_input(&input_connector, NodeInput::node(new_spline_id, 0), network_path);
- }
- }
-
- // Upgrade Text node to include line height and character spacing, which were previously hardcoded to 1, from https://github.com/GraphiteEditor/Graphite/pull/2016
- if reference == "Text" && inputs_count != 9 {
- let mut template = resolve_document_node_type(reference).unwrap().default_node_template();
- document.network_interface.replace_implementation(node_id, network_path, &mut template);
- let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut template).unwrap();
-
- document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path);
- document.network_interface.set_input(&InputConnector::node(*node_id, 1), old_inputs[1].clone(), network_path);
- document.network_interface.set_input(&InputConnector::node(*node_id, 2), old_inputs[2].clone(), network_path);
- document.network_interface.set_input(&InputConnector::node(*node_id, 3), old_inputs[3].clone(), network_path);
- document.network_interface.set_input(
- &InputConnector::node(*node_id, 4),
- if inputs_count == 6 {
- old_inputs[4].clone()
- } else {
- NodeInput::value(TaggedValue::F64(TypesettingConfig::default().line_height_ratio), false)
- },
- network_path,
- );
- document.network_interface.set_input(
- &InputConnector::node(*node_id, 5),
- if inputs_count == 6 {
- old_inputs[5].clone()
- } else {
- NodeInput::value(TaggedValue::F64(TypesettingConfig::default().character_spacing), false)
- },
- network_path,
- );
- document.network_interface.set_input(
- &InputConnector::node(*node_id, 6),
- if inputs_count >= 7 {
- old_inputs[6].clone()
- } else {
- NodeInput::value(TaggedValue::OptionalF64(TypesettingConfig::default().max_width), false)
- },
- network_path,
- );
- document.network_interface.set_input(
- &InputConnector::node(*node_id, 7),
- if inputs_count >= 8 {
- old_inputs[7].clone()
- } else {
- NodeInput::value(TaggedValue::OptionalF64(TypesettingConfig::default().max_height), false)
- },
- network_path,
- );
- document.network_interface.set_input(
- &InputConnector::node(*node_id, 8),
- if inputs_count >= 9 {
- old_inputs[8].clone()
- } else {
- NodeInput::value(TaggedValue::F64(TypesettingConfig::default().tilt), false)
- },
- network_path,
- );
- }
-
- // Upgrade Sine, Cosine, and Tangent nodes to include a boolean input for whether the output should be in radians, which was previously the only option but is now not the default
- if (reference == "Sine" || reference == "Cosine" || reference == "Tangent") && inputs_count == 1 {
- let mut node_template = resolve_document_node_type(reference).unwrap().default_node_template();
- document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
-
- let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template).unwrap();
-
- document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path);
- document
- .network_interface
- .set_input(&InputConnector::node(*node_id, 1), NodeInput::value(TaggedValue::Bool(true), false), network_path);
- }
-
- // Upgrade the Modulo node to include a boolean input for whether the output should be always positive, which was previously not an option
- if reference == "Modulo" && inputs_count == 2 {
- let mut node_template = resolve_document_node_type(reference).unwrap().default_node_template();
- document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
-
- let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template).unwrap();
-
- document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path);
- document.network_interface.set_input(&InputConnector::node(*node_id, 1), old_inputs[1].clone(), network_path);
- document
- .network_interface
- .set_input(&InputConnector::node(*node_id, 2), NodeInput::value(TaggedValue::Bool(false), false), network_path);
- }
-
- // Upgrade the Mirror node to add the `keep_original` boolean input
- if reference == "Mirror" && inputs_count == 3 {
- let mut node_template = resolve_document_node_type(reference).unwrap().default_node_template();
- document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
-
- let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template).unwrap();
-
- document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path);
- document.network_interface.set_input(&InputConnector::node(*node_id, 1), old_inputs[1].clone(), network_path);
- document.network_interface.set_input(&InputConnector::node(*node_id, 2), old_inputs[2].clone(), network_path);
- document
- .network_interface
- .set_input(&InputConnector::node(*node_id, 3), NodeInput::value(TaggedValue::Bool(true), false), network_path);
- }
-
- // Upgrade the Mirror node to add the `reference_point` input and change `offset` from `DVec2` to `f64`
- if reference == "Mirror" && inputs_count == 4 {
- let mut node_template = resolve_document_node_type(reference).unwrap().default_node_template();
- document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
-
- let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template).unwrap();
-
- let Some(&TaggedValue::DVec2(old_offset)) = old_inputs[1].as_value() else { return };
- let old_offset = if old_offset.x.abs() > old_offset.y.abs() { old_offset.x } else { old_offset.y };
-
- document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path);
- document.network_interface.set_input(
- &InputConnector::node(*node_id, 1),
- NodeInput::value(TaggedValue::ReferencePoint(graphene_std::transform::ReferencePoint::Center), false),
- network_path,
- );
- document
- .network_interface
- .set_input(&InputConnector::node(*node_id, 2), NodeInput::value(TaggedValue::F64(old_offset), false), network_path);
- document.network_interface.set_input(&InputConnector::node(*node_id, 3), old_inputs[2].clone(), network_path);
- document.network_interface.set_input(&InputConnector::node(*node_id, 4), old_inputs[3].clone(), network_path);
- }
-
- // Upgrade artboard name being passed as hidden value input to "To Artboard"
- if reference == "Artboard" && reset_node_definitions_on_open {
- let label = document.network_interface.display_name(node_id, network_path);
- document
- .network_interface
- .set_input(&InputConnector::node(NodeId(0), 1), NodeInput::value(TaggedValue::String(label), false), &[*node_id]);
- }
-
- if reference == "Image" && inputs_count == 1 {
- let mut node_template = resolve_document_node_type(reference).unwrap().default_node_template();
- document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
-
- // Insert a new empty input for the image
- document.network_interface.add_import(TaggedValue::None, false, 0, "Empty", "", &[*node_id]);
- document.network_interface.set_reference(node_id, network_path, Some("Image".to_string()));
- }
-
- if reference == "Noise Pattern" && inputs_count == 15 {
- let mut node_template = resolve_document_node_type(reference).unwrap().default_node_template();
- document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
-
- let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template).unwrap();
-
- document
- .network_interface
- .set_input(&InputConnector::node(*node_id, 0), NodeInput::value(TaggedValue::None, false), network_path);
- for (i, input) in old_inputs.iter().enumerate() {
- document.network_interface.set_input(&InputConnector::node(*node_id, i + 1), input.clone(), network_path);
- }
- }
-
- if reference == "Instance on Points" && inputs_count == 2 {
- let mut node_template = resolve_document_node_type(reference).unwrap().default_node_template();
- document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
-
- let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template).unwrap();
-
- document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path);
- document.network_interface.set_input(&InputConnector::node(*node_id, 1), old_inputs[1].clone(), network_path);
- }
-
- if reference == "Morph" && inputs_count == 4 {
- let mut node_template = resolve_document_node_type(reference).unwrap().default_node_template();
- document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
-
- let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template).unwrap();
-
- document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path);
- document.network_interface.set_input(&InputConnector::node(*node_id, 1), old_inputs[1].clone(), network_path);
- document.network_interface.set_input(&InputConnector::node(*node_id, 2), old_inputs[2].clone(), network_path);
- // We have removed the last input, so we don't add index 3
- }
-
- if reference == "Brush" && inputs_count == 4 {
- let mut node_template = resolve_document_node_type(reference).unwrap().default_node_template();
- document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
-
- let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template).unwrap();
-
- document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path);
- // We have removed the second input ("bounds"), so we don't add index 1 and we shift the rest of the inputs down by one
- document.network_interface.set_input(&InputConnector::node(*node_id, 1), old_inputs[2].clone(), network_path);
- document.network_interface.set_input(&InputConnector::node(*node_id, 2), old_inputs[3].clone(), network_path);
- }
-
- if reference == "Flatten Vector Elements" {
- let mut node_template = resolve_document_node_type(reference).unwrap().default_node_template();
- document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
-
- let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template).unwrap();
-
- document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path);
-
- document.network_interface.replace_reference_name(node_id, network_path, "Flatten Path".to_string());
- }
-
- if reference == "Remove Handles" {
- let mut node_template = resolve_document_node_type(reference).unwrap().default_node_template();
- document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
-
- let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template).unwrap();
-
- document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path);
- document
- .network_interface
- .set_input(&InputConnector::node(*node_id, 1), NodeInput::value(TaggedValue::F64(0.), false), network_path);
- document
- .network_interface
- .set_input(&InputConnector::node(*node_id, 2), NodeInput::value(TaggedValue::Bool(false), false), network_path);
-
- document.network_interface.replace_reference_name(node_id, network_path, "Auto-Tangents".to_string());
- }
-
- if reference == "Generate Handles" {
- let mut node_template = resolve_document_node_type("Auto-Tangents").unwrap().default_node_template();
- document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
-
- let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template).unwrap();
-
- document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path);
- document.network_interface.set_input(&InputConnector::node(*node_id, 1), old_inputs[1].clone(), network_path);
- document
- .network_interface
- .set_input(&InputConnector::node(*node_id, 2), NodeInput::value(TaggedValue::Bool(true), false), network_path);
-
- document.network_interface.replace_reference_name(node_id, network_path, "Auto-Tangents".to_string());
- }
-
- if reference == "Merge by Distance" && inputs_count == 2 {
- let mut node_template = resolve_document_node_type(reference).unwrap().default_node_template();
- document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
-
- let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template).unwrap();
-
- document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path);
- document.network_interface.set_input(&InputConnector::node(*node_id, 1), old_inputs[1].clone(), network_path);
- document.network_interface.set_input(
- &InputConnector::node(*node_id, 2),
- NodeInput::value(TaggedValue::MergeByDistanceAlgorithm(graphene_std::vector::misc::MergeByDistanceAlgorithm::Topological), false),
- network_path,
- );
- }
-
- if reference == "Spatial Merge by Distance" {
- let mut node_template = resolve_document_node_type("Merge by Distance").unwrap().default_node_template();
- document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
-
- let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template).unwrap();
-
- document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path);
- document.network_interface.set_input(&InputConnector::node(*node_id, 1), old_inputs[1].clone(), network_path);
- document.network_interface.set_input(
- &InputConnector::node(*node_id, 2),
- NodeInput::value(TaggedValue::MergeByDistanceAlgorithm(graphene_std::vector::misc::MergeByDistanceAlgorithm::Spatial), false),
- network_path,
- );
-
- document.network_interface.replace_reference_name(node_id, network_path, "Merge by Distance".to_string());
- }
-
- if reference == "Sample Points" && inputs_count == 5 {
- let mut node_template = resolve_document_node_type("Sample Polyline").unwrap().default_node_template();
- document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
-
- let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template).unwrap();
- let new_spacing_value = NodeInput::value(TaggedValue::PointSpacingType(graphene_std::vector::misc::PointSpacingType::Separation), false);
- let new_quantity_value = NodeInput::value(TaggedValue::U32(100), false);
-
- document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path);
- document.network_interface.set_input(&InputConnector::node(*node_id, 1), new_spacing_value, network_path);
- document.network_interface.set_input(&InputConnector::node(*node_id, 2), old_inputs[1].clone(), network_path);
- document.network_interface.set_input(&InputConnector::node(*node_id, 3), new_quantity_value, network_path);
- document.network_interface.set_input(&InputConnector::node(*node_id, 4), old_inputs[2].clone(), network_path);
- document.network_interface.set_input(&InputConnector::node(*node_id, 5), old_inputs[3].clone(), network_path);
- document.network_interface.set_input(&InputConnector::node(*node_id, 6), old_inputs[4].clone(), network_path);
-
- document.network_interface.replace_reference_name(node_id, network_path, "Sample Polyline".to_string());
- }
-
- // Make the "Quantity" parameter a u32 instead of f64
- if reference == "Sample Polyline" {
- // Get the inputs, obtain the quantity value, and put the inputs back
- let quantity_value = document
- .network_interface
- .input_from_connector(&InputConnector::Node { node_id: *node_id, input_index: 3 }, network_path)
- .unwrap();
-
- if let NodeInput::Value { tagged_value, exposed } = quantity_value {
- if let TaggedValue::F64(value) = **tagged_value {
- let new_quantity_value = NodeInput::value(TaggedValue::U32(value as u32), *exposed);
- document.network_interface.set_input(&InputConnector::node(*node_id, 3), new_quantity_value, network_path);
- }
- }
- }
-
- // Make the "Grid" node, if its input of index 3 is a DVec2 for "angles" instead of a u32 for the "columns" input that now succeeds "angles", move the angle to index 5 (after "columns" and "rows")
- if reference == "Grid" && inputs_count == 6 {
- let node_definition = resolve_document_node_type(reference).unwrap();
- let mut new_node_template = node_definition.default_node_template();
-
- let mut current_node_template = document.network_interface.create_node_template(node_id, network_path).unwrap();
- let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut new_node_template).unwrap();
- let index_3_value = old_inputs.get(3).cloned();
-
- if let Some(NodeInput::Value { tagged_value, exposed: _ }) = index_3_value {
- if matches!(*tagged_value, TaggedValue::DVec2(_)) {
- // Move index 3 to the end
- document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path);
- document.network_interface.set_input(&InputConnector::node(*node_id, 1), old_inputs[1].clone(), network_path);
- document.network_interface.set_input(&InputConnector::node(*node_id, 2), old_inputs[2].clone(), network_path);
- document.network_interface.set_input(&InputConnector::node(*node_id, 3), old_inputs[4].clone(), network_path);
- document.network_interface.set_input(&InputConnector::node(*node_id, 4), old_inputs[5].clone(), network_path);
- document.network_interface.set_input(&InputConnector::node(*node_id, 5), old_inputs[3].clone(), network_path);
- } else {
- // Swap it back if we're not changing anything
- let _ = document.network_interface.replace_inputs(node_id, network_path, &mut current_node_template);
- }
- }
- }
-
- // Ensure layers are positioned as stacks if they are upstream siblings of another layer
- document.network_interface.load_structure();
- let all_layers = LayerNodeIdentifier::ROOT_PARENT.descendants(document.network_interface.document_metadata()).collect::>();
- for layer in all_layers {
- let Some((downstream_node, input_index)) = document
- .network_interface
- .outward_wires(&[])
- .and_then(|outward_wires| outward_wires.get(&OutputConnector::node(layer.to_node(), 0)))
- .and_then(|outward_wires| outward_wires.first())
- .and_then(|input_connector| input_connector.node_id().map(|node_id| (node_id, input_connector.input_index())))
- else {
- continue;
- };
- // If the downstream node is a layer and the input is the first input and the current layer is not in a stack
- if input_index == 0 && document.network_interface.is_layer(&downstream_node, &[]) && !document.network_interface.is_stack(&layer.to_node(), &[]) {
- // Ensure the layer is horizontally aligned with the downstream layer to prevent changing the layout of old files
- let (Some(layer_position), Some(downstream_position)) = (document.network_interface.position(&layer.to_node(), &[]), document.network_interface.position(&downstream_node, &[])) else {
- log::error!("Could not get position for layer {:?} or downstream node {} when opening file", layer.to_node(), downstream_node);
- continue;
- };
- if layer_position.x == downstream_position.x {
- document.network_interface.set_stack_position_calculated_offset(&layer.to_node(), &downstream_node, &[]);
- }
+ if reference == "Instance on Points" && inputs_count == 2 {
+ let mut node_template = resolve_document_node_type(reference)?.default_node_template();
+ document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
+
+ let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?;
+
+ document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path);
+ document.network_interface.set_input(&InputConnector::node(*node_id, 1), old_inputs[1].clone(), network_path);
+ }
+
+ if reference == "Morph" && inputs_count == 4 {
+ let mut node_template = resolve_document_node_type(reference)?.default_node_template();
+ document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
+
+ let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?;
+
+ document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path);
+ document.network_interface.set_input(&InputConnector::node(*node_id, 1), old_inputs[1].clone(), network_path);
+ document.network_interface.set_input(&InputConnector::node(*node_id, 2), old_inputs[2].clone(), network_path);
+ // We have removed the last input, so we don't add index 3
+ }
+
+ if reference == "Brush" && inputs_count == 4 {
+ let mut node_template = resolve_document_node_type(reference)?.default_node_template();
+ document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
+
+ let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?;
+
+ document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path);
+ // We have removed the second input ("bounds"), so we don't add index 1 and we shift the rest of the inputs down by one
+ document.network_interface.set_input(&InputConnector::node(*node_id, 1), old_inputs[2].clone(), network_path);
+ document.network_interface.set_input(&InputConnector::node(*node_id, 2), old_inputs[3].clone(), network_path);
+ }
+
+ if reference == "Flatten Vector Elements" {
+ let mut node_template = resolve_document_node_type(reference)?.default_node_template();
+ document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
+
+ let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?;
+
+ document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path);
+
+ document.network_interface.replace_reference_name(node_id, network_path, "Flatten Path".to_string());
+ }
+
+ if reference == "Remove Handles" {
+ let mut node_template = resolve_document_node_type(reference)?.default_node_template();
+ document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
+
+ let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?;
+
+ document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path);
+ document
+ .network_interface
+ .set_input(&InputConnector::node(*node_id, 1), NodeInput::value(TaggedValue::F64(0.), false), network_path);
+ document
+ .network_interface
+ .set_input(&InputConnector::node(*node_id, 2), NodeInput::value(TaggedValue::Bool(false), false), network_path);
+
+ document.network_interface.replace_reference_name(node_id, network_path, "Auto-Tangents".to_string());
+ }
+
+ if reference == "Generate Handles" {
+ let mut node_template = resolve_document_node_type("Auto-Tangents")?.default_node_template();
+ document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
+
+ let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?;
+
+ document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path);
+ document.network_interface.set_input(&InputConnector::node(*node_id, 1), old_inputs[1].clone(), network_path);
+ document
+ .network_interface
+ .set_input(&InputConnector::node(*node_id, 2), NodeInput::value(TaggedValue::Bool(true), false), network_path);
+
+ document.network_interface.replace_reference_name(node_id, network_path, "Auto-Tangents".to_string());
+ }
+
+ if reference == "Merge by Distance" && inputs_count == 2 {
+ let mut node_template = resolve_document_node_type(reference)?.default_node_template();
+ document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
+
+ let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?;
+
+ document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path);
+ document.network_interface.set_input(&InputConnector::node(*node_id, 1), old_inputs[1].clone(), network_path);
+ document.network_interface.set_input(
+ &InputConnector::node(*node_id, 2),
+ NodeInput::value(TaggedValue::MergeByDistanceAlgorithm(graphene_std::vector::misc::MergeByDistanceAlgorithm::Topological), false),
+ network_path,
+ );
+ }
+
+ if reference == "Spatial Merge by Distance" {
+ let mut node_template = resolve_document_node_type("Merge by Distance")?.default_node_template();
+ document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
+
+ let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?;
+
+ document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path);
+ document.network_interface.set_input(&InputConnector::node(*node_id, 1), old_inputs[1].clone(), network_path);
+ document.network_interface.set_input(
+ &InputConnector::node(*node_id, 2),
+ NodeInput::value(TaggedValue::MergeByDistanceAlgorithm(graphene_std::vector::misc::MergeByDistanceAlgorithm::Spatial), false),
+ network_path,
+ );
+
+ document.network_interface.replace_reference_name(node_id, network_path, "Merge by Distance".to_string());
+ }
+
+ if reference == "Sample Points" && inputs_count == 5 {
+ let mut node_template = resolve_document_node_type("Sample Polyline")?.default_node_template();
+ document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
+
+ let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?;
+ let new_spacing_value = NodeInput::value(TaggedValue::PointSpacingType(graphene_std::vector::misc::PointSpacingType::Separation), false);
+ let new_quantity_value = NodeInput::value(TaggedValue::U32(100), false);
+
+ document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path);
+ document.network_interface.set_input(&InputConnector::node(*node_id, 1), new_spacing_value, network_path);
+ document.network_interface.set_input(&InputConnector::node(*node_id, 2), old_inputs[1].clone(), network_path);
+ document.network_interface.set_input(&InputConnector::node(*node_id, 3), new_quantity_value, network_path);
+ document.network_interface.set_input(&InputConnector::node(*node_id, 4), old_inputs[2].clone(), network_path);
+ document.network_interface.set_input(&InputConnector::node(*node_id, 5), old_inputs[3].clone(), network_path);
+ document.network_interface.set_input(&InputConnector::node(*node_id, 6), old_inputs[4].clone(), network_path);
+
+ document.network_interface.replace_reference_name(node_id, network_path, "Sample Polyline".to_string());
+ }
+
+ // Make the "Quantity" parameter a u32 instead of f64
+ if reference == "Sample Polyline" {
+ // Get the inputs, obtain the quantity value, and put the inputs back
+ let quantity_value = document
+ .network_interface
+ .input_from_connector(&InputConnector::Node { node_id: *node_id, input_index: 3 }, network_path)?;
+
+ if let NodeInput::Value { tagged_value, exposed } = quantity_value {
+ if let TaggedValue::F64(value) = **tagged_value {
+ let new_quantity_value = NodeInput::value(TaggedValue::U32(value as u32), *exposed);
+ document.network_interface.set_input(&InputConnector::node(*node_id, 3), new_quantity_value, network_path);
}
}
}
+
+ // Make the "Grid" node, if its input of index 3 is a DVec2 for "angles" instead of a u32 for the "columns" input that now succeeds "angles", move the angle to index 5 (after "columns" and "rows")
+ if reference == "Grid" && inputs_count == 6 {
+ let node_definition = resolve_document_node_type(reference)?;
+ let mut new_node_template = node_definition.default_node_template();
+
+ let mut current_node_template = document.network_interface.create_node_template(node_id, network_path)?;
+ let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut new_node_template)?;
+ let index_3_value = old_inputs.get(3).cloned();
+
+ let mut upgraded = false;
+
+ if let Some(NodeInput::Value { tagged_value, exposed: _ }) = index_3_value {
+ if matches!(*tagged_value, TaggedValue::DVec2(_)) {
+ // Move index 3 to the end
+ document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path);
+ document.network_interface.set_input(&InputConnector::node(*node_id, 1), old_inputs[1].clone(), network_path);
+ document.network_interface.set_input(&InputConnector::node(*node_id, 2), old_inputs[2].clone(), network_path);
+ document.network_interface.set_input(&InputConnector::node(*node_id, 3), old_inputs[4].clone(), network_path);
+ document.network_interface.set_input(&InputConnector::node(*node_id, 4), old_inputs[5].clone(), network_path);
+ document.network_interface.set_input(&InputConnector::node(*node_id, 5), old_inputs[3].clone(), network_path);
+
+ upgraded = true;
+ }
+ }
+
+ if !upgraded {
+ let _ = document.network_interface.replace_inputs(node_id, network_path, &mut current_node_template);
+ }
+ }
+
+ // Ensure layers are positioned as stacks if they are upstream siblings of another layer
+ document.network_interface.load_structure();
+ let all_layers = LayerNodeIdentifier::ROOT_PARENT.descendants(document.network_interface.document_metadata()).collect::>();
+ for layer in all_layers {
+ let (downstream_node, input_index) = document
+ .network_interface
+ .outward_wires(&[])
+ .and_then(|outward_wires| outward_wires.get(&OutputConnector::node(layer.to_node(), 0)))
+ .and_then(|outward_wires| outward_wires.first())
+ .and_then(|input_connector| input_connector.node_id().map(|node_id| (node_id, input_connector.input_index())))?;
+ // If the downstream node is a layer and the input is the first input and the current layer is not in a stack
+ if input_index == 0 && document.network_interface.is_layer(&downstream_node, &[]) && !document.network_interface.is_stack(&layer.to_node(), &[]) {
+ // Ensure the layer is horizontally aligned with the downstream layer to prevent changing the layout of old files
+ let (Some(layer_position), Some(downstream_position)) = (document.network_interface.position(&layer.to_node(), &[]), document.network_interface.position(&downstream_node, &[])) else {
+ log::error!("Could not get position for layer {:?} or downstream node {} when opening file", layer.to_node(), downstream_node);
+ return None;
+ };
+ if layer_position.x == downstream_position.x {
+ document.network_interface.set_stack_position_calculated_offset(&layer.to_node(), &downstream_node, &[]);
+ }
+ }
+ }
+
+ Some(())
}
diff --git a/editor/src/messages/portfolio/menu_bar/menu_bar_message_handler.rs b/editor/src/messages/portfolio/menu_bar/menu_bar_message_handler.rs
index 50cfa632ac..26a9a739f3 100644
--- a/editor/src/messages/portfolio/menu_bar/menu_bar_message_handler.rs
+++ b/editor/src/messages/portfolio/menu_bar/menu_bar_message_handler.rs
@@ -6,7 +6,7 @@ use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate,
use crate::messages::prelude::*;
use graphene_std::path_bool::BooleanOperation;
-#[derive(Debug, Clone, Default)]
+#[derive(Debug, Clone, Default, ExtractField)]
pub struct MenuBarMessageHandler {
pub has_active_document: bool,
pub canvas_tilted: bool,
@@ -21,6 +21,7 @@ pub struct MenuBarMessageHandler {
pub reset_node_definitions_on_open: bool,
}
+#[message_handler_data]
impl MessageHandler for MenuBarMessageHandler {
fn process_message(&mut self, message: MenuBarMessage, responses: &mut VecDeque, _data: ()) {
match message {
diff --git a/editor/src/messages/portfolio/portfolio_message_handler.rs b/editor/src/messages/portfolio/portfolio_message_handler.rs
index a6d9da338e..195768bd4b 100644
--- a/editor/src/messages/portfolio/portfolio_message_handler.rs
+++ b/editor/src/messages/portfolio/portfolio_message_handler.rs
@@ -25,6 +25,7 @@ use graphene_std::renderer::Quad;
use graphene_std::text::Font;
use std::vec;
+#[derive(ExtractField)]
pub struct PortfolioMessageData<'a> {
pub ipp: &'a InputPreprocessorMessageHandler,
pub preferences: &'a PreferencesMessageHandler,
@@ -35,7 +36,7 @@ pub struct PortfolioMessageData<'a> {
pub animation: &'a AnimationMessageHandler,
}
-#[derive(Debug, Default)]
+#[derive(Debug, Default, ExtractField)]
pub struct PortfolioMessageHandler {
menu_bar_message_handler: MenuBarMessageHandler,
pub documents: HashMap,
@@ -52,6 +53,7 @@ pub struct PortfolioMessageHandler {
pub reset_node_definitions_on_open: bool,
}
+#[message_handler_data]
impl MessageHandler> for PortfolioMessageHandler {
fn process_message(&mut self, message: PortfolioMessage, responses: &mut VecDeque, data: PortfolioMessageData) {
let PortfolioMessageData {
diff --git a/editor/src/messages/portfolio/spreadsheet/spreadsheet_message_handler.rs b/editor/src/messages/portfolio/spreadsheet/spreadsheet_message_handler.rs
index 5e28d514b1..684b7d1d76 100644
--- a/editor/src/messages/portfolio/spreadsheet/spreadsheet_message_handler.rs
+++ b/editor/src/messages/portfolio/spreadsheet/spreadsheet_message_handler.rs
@@ -15,7 +15,7 @@ use std::any::Any;
use std::sync::Arc;
/// The spreadsheet UI allows for instance data to be previewed.
-#[derive(Default, Debug, Clone)]
+#[derive(Default, Debug, Clone, ExtractField)]
pub struct SpreadsheetMessageHandler {
/// Sets whether or not the spreadsheet is drawn.
pub spreadsheet_view_open: bool,
@@ -25,6 +25,7 @@ pub struct SpreadsheetMessageHandler {
viewing_vector_data_domain: VectorDataDomain,
}
+#[message_handler_data]
impl MessageHandler for SpreadsheetMessageHandler {
fn process_message(&mut self, message: SpreadsheetMessage, responses: &mut VecDeque, _data: ()) {
match message {
diff --git a/editor/src/messages/preferences/preferences_message_handler.rs b/editor/src/messages/preferences/preferences_message_handler.rs
index b52e4e49a8..1e52233fe3 100644
--- a/editor/src/messages/preferences/preferences_message_handler.rs
+++ b/editor/src/messages/preferences/preferences_message_handler.rs
@@ -5,7 +5,7 @@ use crate::messages::preferences::SelectionMode;
use crate::messages::prelude::*;
use graph_craft::wasm_application_io::EditorPreferences;
-#[derive(Debug, PartialEq, Clone, serde::Serialize, serde::Deserialize, specta::Type)]
+#[derive(Debug, PartialEq, Clone, serde::Serialize, serde::Deserialize, specta::Type, ExtractField)]
pub struct PreferencesMessageHandler {
pub selection_mode: SelectionMode,
pub zoom_with_scroll: bool,
@@ -44,6 +44,7 @@ impl Default for PreferencesMessageHandler {
}
}
+#[message_handler_data]
impl MessageHandler for PreferencesMessageHandler {
fn process_message(&mut self, message: PreferencesMessage, responses: &mut VecDeque, _data: ()) {
match message {
diff --git a/editor/src/messages/prelude.rs b/editor/src/messages/prelude.rs
index d33b7c235c..7517c80f48 100644
--- a/editor/src/messages/prelude.rs
+++ b/editor/src/messages/prelude.rs
@@ -1,6 +1,6 @@
// Root
-pub use crate::utility_traits::{ActionList, AsMessage, MessageHandler, ToDiscriminant, TransitiveChild};
-
+pub use crate::utility_traits::{ActionList, AsMessage, HierarchicalTree, MessageHandler, ToDiscriminant, TransitiveChild};
+pub use crate::utility_types::{DebugMessageTree, MessageData};
// Message, MessageData, MessageDiscriminant, MessageHandler
pub use crate::messages::animation::{AnimationMessage, AnimationMessageDiscriminant, AnimationMessageHandler};
pub use crate::messages::broadcast::{BroadcastMessage, BroadcastMessageDiscriminant, BroadcastMessageHandler};
diff --git a/editor/src/messages/tool/common_functionality/compass_rose.rs b/editor/src/messages/tool/common_functionality/compass_rose.rs
index 8a7a2f6b2a..bedc1ca230 100644
--- a/editor/src/messages/tool/common_functionality/compass_rose.rs
+++ b/editor/src/messages/tool/common_functionality/compass_rose.rs
@@ -1,5 +1,4 @@
use crate::consts::{COMPASS_ROSE_ARROW_CLICK_TARGET_ANGLE, COMPASS_ROSE_HOVER_RING_DIAMETER, COMPASS_ROSE_RING_INNER_DIAMETER};
-use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
use crate::messages::prelude::DocumentMessageHandler;
use glam::{DAffine2, DVec2};
use std::f64::consts::FRAC_PI_2;
@@ -10,25 +9,32 @@ pub struct CompassRose {
}
impl CompassRose {
- fn get_layer_pivot_transform(layer: LayerNodeIdentifier, document: &DocumentMessageHandler) -> DAffine2 {
- let [min, max] = document.metadata().nonzero_bounding_box(layer);
-
- let bounds_transform = DAffine2::from_translation(min) * DAffine2::from_scale(max - min);
- let layer_transform = document.metadata().transform_to_viewport(layer);
- layer_transform * bounds_transform
- }
pub fn refresh_position(&mut self, document: &DocumentMessageHandler) {
- let selected_nodes = document.network_interface.selected_nodes();
- let mut layers = selected_nodes.selected_visible_and_unlocked_layers(&document.network_interface);
+ let selected = document.network_interface.selected_nodes();
- let Some(first) = layers.next() else { return };
- let count = layers.count() + 1;
- let transform = if count == 1 {
- Self::get_layer_pivot_transform(first, document)
- } else {
- let [min, max] = document.selected_visible_and_unlock_layers_bounding_box_viewport().unwrap_or([DVec2::ZERO, DVec2::ONE]);
- DAffine2::from_translation(min) * DAffine2::from_scale(max - min)
- };
+ if !selected.has_selected_nodes() {
+ return;
+ }
+
+ let transform = selected
+ .selected_visible_and_unlocked_layers(&document.network_interface)
+ .find(|layer| !document.network_interface.is_artboard(&layer.to_node(), &[]))
+ .map(|layer| document.metadata().transform_to_viewport_with_first_transform_node_if_group(layer, &document.network_interface))
+ .unwrap_or_default();
+
+ let bounds = document
+ .network_interface
+ .selected_nodes()
+ .selected_visible_and_unlocked_layers(&document.network_interface)
+ .filter_map(|layer| {
+ document
+ .metadata()
+ .bounding_box_with_transform(layer, transform.inverse() * document.metadata().transform_to_viewport(layer))
+ })
+ .reduce(graphene_std::renderer::Quad::combine_bounds);
+
+ let [min, max] = bounds.unwrap_or([DVec2::ZERO, DVec2::ONE]);
+ let transform = transform * DAffine2::from_translation(min) * DAffine2::from_scale(max - min);
self.compass_center = transform.transform_point2(DVec2::splat(0.5));
}
diff --git a/editor/src/messages/tool/common_functionality/graph_modification_utils.rs b/editor/src/messages/tool/common_functionality/graph_modification_utils.rs
index 765bfc1eac..33c19d0c0d 100644
--- a/editor/src/messages/tool/common_functionality/graph_modification_utils.rs
+++ b/editor/src/messages/tool/common_functionality/graph_modification_utils.rs
@@ -5,9 +5,9 @@ use crate::messages::portfolio::document::utility_types::network_interface::{Flo
use crate::messages::prelude::*;
use bezier_rs::Subpath;
use glam::DVec2;
-use graph_craft::concrete;
use graph_craft::document::value::TaggedValue;
use graph_craft::document::{NodeId, NodeInput};
+use graph_craft::{ProtoNodeIdentifier, concrete};
use graphene_std::Color;
use graphene_std::NodeInputDecleration;
use graphene_std::raster::BlendMode;
@@ -243,20 +243,26 @@ pub fn new_custom(id: NodeId, nodes: Vec<(NodeId, NodeTemplate)>, parent: LayerN
LayerNodeIdentifier::new_unchecked(id)
}
-/// Locate the final pivot from the transform (TODO: decide how the pivot should actually work)
-pub fn get_pivot(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option {
- let pivot_node_input_index = 5;
- if let TaggedValue::DVec2(pivot) = NodeGraphLayer::new(layer, network_interface).find_input("Transform", pivot_node_input_index)? {
- Some(*pivot)
+/// Locate the origin of the transform node
+pub fn get_origin(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option {
+ use graphene_std::transform_nodes::transform::TranslateInput;
+
+ if let TaggedValue::DVec2(origin) = NodeGraphLayer::new(layer, network_interface).find_input("Transform", TranslateInput::INDEX)? {
+ Some(*origin)
} else {
None
}
}
-pub fn get_viewport_pivot(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> DVec2 {
+pub fn get_viewport_origin(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> DVec2 {
+ let origin = get_origin(layer, network_interface).unwrap_or_default();
+ network_interface.document_metadata().document_to_viewport.transform_point2(origin)
+}
+
+pub fn get_viewport_center(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> DVec2 {
let [min, max] = network_interface.document_metadata().nonzero_bounding_box(layer);
- let pivot = get_pivot(layer, network_interface).unwrap_or(DVec2::splat(0.5));
- network_interface.document_metadata().transform_to_viewport(layer).transform_point2(min + (max - min) * pivot)
+ let center = DVec2::splat(0.5);
+ network_interface.document_metadata().transform_to_viewport(layer).transform_point2(min + (max - min) * center)
}
/// Get the current gradient of a layer from the closest "Fill" node.
@@ -416,14 +422,14 @@ impl<'a> NodeGraphLayer<'a> {
}
/// Node id of a protonode if it exists in the layer's primary flow
- pub fn upstream_node_id_from_protonode(&self, protonode_identifier: &'static str) -> Option {
+ pub fn upstream_node_id_from_protonode(&self, protonode_identifier: ProtoNodeIdentifier) -> Option {
self.horizontal_layer_flow()
// Take until a different layer is reached
.take_while(|&node_id| node_id == self.layer_node || !self.network_interface.is_layer(&node_id, &[]))
- .find(move |node_id| {
+ .find(|node_id| {
self.network_interface
.implementation(node_id, &[])
- .is_some_and(move |implementation| *implementation == graph_craft::document::DocumentNodeImplementation::proto(protonode_identifier))
+ .is_some_and(|implementation| *implementation == graph_craft::document::DocumentNodeImplementation::ProtoNode(protonode_identifier.clone()))
})
}
diff --git a/editor/src/messages/tool/common_functionality/pivot.rs b/editor/src/messages/tool/common_functionality/pivot.rs
index 67ce7f5dc5..10ea38371c 100644
--- a/editor/src/messages/tool/common_functionality/pivot.rs
+++ b/editor/src/messages/tool/common_functionality/pivot.rs
@@ -1,26 +1,184 @@
-//! Handler for the pivot overlay visible on the selected layer(s) whilst using the Select tool which controls the center of rotation/scale and origin of the layer.
+//! Handler for the pivot overlay visible on the selected layer(s) whilst using the Select tool which controls the center of rotation/scale.
-use super::graph_modification_utils;
use crate::consts::PIVOT_DIAMETER;
-use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
use crate::messages::prelude::*;
+use crate::messages::tool::common_functionality::graph_modification_utils;
+use crate::messages::tool::tool_messages::path_tool::PathOptionsUpdate;
+use crate::messages::tool::tool_messages::select_tool::SelectOptionsUpdate;
+use crate::messages::tool::tool_messages::tool_prelude::*;
use glam::{DAffine2, DVec2};
-use graphene_std::transform::ReferencePoint;
-use std::collections::VecDeque;
+use graphene_std::{transform::ReferencePoint, vector::ManipulatorPointId};
+use std::fmt;
-#[derive(Clone, Debug)]
+pub fn pin_pivot_widget(active: bool, enabled: bool, source: PivotToolSource) -> WidgetHolder {
+ IconButton::new(if active { "PinActive" } else { "PinInactive" }, 24)
+ .tooltip(String::from(if active { "Unpin Custom Pivot" } else { "Pin Custom Pivot" }) + "\n\nUnless pinned, the pivot will return to its prior reference point when a new selection is made.")
+ .disabled(!enabled)
+ .on_update(move |_| match source {
+ PivotToolSource::Select => SelectToolMessage::SelectOptions(SelectOptionsUpdate::TogglePivotPinned).into(),
+ PivotToolSource::Path => PathToolMessage::UpdateOptions(PathOptionsUpdate::TogglePivotPinned).into(),
+ })
+ .widget_holder()
+}
+
+pub fn pivot_reference_point_widget(disabled: bool, reference_point: ReferencePoint, source: PivotToolSource) -> WidgetHolder {
+ ReferencePointInput::new(reference_point)
+ .tooltip("Custom Pivot Reference Point\n\nPlaces the pivot at a corner, edge, or center of the selection bounds, unless it is dragged elsewhere.")
+ .disabled(disabled)
+ .on_update(move |pivot_input: &ReferencePointInput| match source {
+ PivotToolSource::Select => SelectToolMessage::SetPivot { position: pivot_input.value }.into(),
+ PivotToolSource::Path => PathToolMessage::SetPivot { position: pivot_input.value }.into(),
+ })
+ .widget_holder()
+}
+
+pub fn pivot_gizmo_type_widget(state: PivotGizmoState, source: PivotToolSource) -> Vec {
+ let gizmo_type_entries = [PivotGizmoType::Pivot, PivotGizmoType::Average, PivotGizmoType::Active]
+ .iter()
+ .map(|gizmo_type| {
+ MenuListEntry::new(format!("{gizmo_type:?}")).label(gizmo_type.to_string()).on_commit({
+ let value = source.clone();
+ move |_| match value {
+ PivotToolSource::Select => SelectToolMessage::SelectOptions(SelectOptionsUpdate::PivotGizmoType(*gizmo_type)).into(),
+ PivotToolSource::Path => PathToolMessage::UpdateOptions(PathOptionsUpdate::PivotGizmoType(*gizmo_type)).into(),
+ }
+ })
+ })
+ .collect();
+
+ vec![
+ CheckboxInput::new(!state.disabled)
+ .tooltip(
+ "Pivot Gizmo\n\
+ \n\
+ Enabled: the chosen gizmo type is shown and used to control rotation and scaling.\n\
+ Disabled: rotation and scaling occurs about the center of the selection bounds.",
+ )
+ .on_update(move |optional_input: &CheckboxInput| match source {
+ PivotToolSource::Select => SelectToolMessage::SelectOptions(SelectOptionsUpdate::TogglePivotGizmoType(optional_input.checked)).into(),
+ PivotToolSource::Path => PathToolMessage::UpdateOptions(PathOptionsUpdate::TogglePivotGizmoType(optional_input.checked)).into(),
+ })
+ .widget_holder(),
+ Separator::new(SeparatorType::Related).widget_holder(),
+ DropdownInput::new(vec![gizmo_type_entries])
+ .selected_index(Some(match state.gizmo_type {
+ PivotGizmoType::Pivot => 0,
+ PivotGizmoType::Average => 1,
+ PivotGizmoType::Active => 2,
+ }))
+ .tooltip(
+ "Pivot Gizmo Type\n\
+ \n\
+ Selects which gizmo type is shown and used as the center of rotation/scaling transformations.\n\
+ \n\
+ Custom Pivot: rotates and scales relative to the selection bounds, or elsewhere if dragged.\n\
+ Origin (Average Point): rotates and scales about the average point of all selected layer origins.\n\
+ Origin (Active Object): rotates and scales about the origin of the most recently selected layer.",
+ )
+ .disabled(state.disabled)
+ .widget_holder(),
+ ]
+}
+
+#[derive(PartialEq, Clone, Debug, Default, serde::Serialize, serde::Deserialize)]
+pub enum PivotToolSource {
+ Path,
+ #[default]
+ Select,
+}
+
+#[derive(PartialEq, Clone, Debug, Default, serde::Serialize, serde::Deserialize)]
+pub struct PivotGizmo {
+ pub pivot: Pivot,
+ pub state: PivotGizmoState,
+ pub layer: Option,
+ pub point: Option,
+}
+
+impl PivotGizmo {
+ pub fn position(&self, document: &DocumentMessageHandler) -> DVec2 {
+ let network = &document.network_interface;
+ (!self.state.disabled)
+ .then_some({
+ match self.state.gizmo_type {
+ PivotGizmoType::Average => Some(network.selected_nodes().selected_visible_and_unlocked_layers_mean_average_origin(network)),
+ PivotGizmoType::Pivot => self.pivot.pivot,
+ PivotGizmoType::Active => self.layer.map(|layer| graph_modification_utils::get_viewport_origin(layer, network)),
+ }
+ })
+ .flatten()
+ .unwrap_or_else(|| self.pivot.transform_from_normalized.transform_point2(DVec2::splat(0.5)))
+ }
+
+ pub fn recalculate_transform(&mut self, document: &DocumentMessageHandler) -> DAffine2 {
+ self.pivot.recalculate_pivot(document);
+ self.pivot.transform_from_normalized
+ }
+
+ pub fn pin_active(&self) -> bool {
+ self.pivot.pinned && self.state.is_pivot_type()
+ }
+
+ pub fn pivot_disconnected(&self) -> bool {
+ self.pivot.old_pivot_position == ReferencePoint::None
+ }
+}
+
+#[derive(Default, PartialEq, Eq, Clone, Copy, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)]
+pub enum PivotGizmoType {
+ // Pivot
+ #[default]
+ Pivot,
+ // Origin
+ Average,
+ Active,
+ // TODO: Add "Individual"
+}
+
+#[derive(PartialEq, Eq, Clone, Copy, Default, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)]
+pub struct PivotGizmoState {
+ pub disabled: bool,
+ pub gizmo_type: PivotGizmoType,
+}
+
+impl PivotGizmoState {
+ pub fn is_pivot_type(&self) -> bool {
+ self.gizmo_type == PivotGizmoType::Pivot || self.disabled
+ }
+
+ pub fn is_pivot(&self) -> bool {
+ self.gizmo_type == PivotGizmoType::Pivot && !self.disabled
+ }
+}
+
+impl fmt::Display for PivotGizmoType {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ PivotGizmoType::Pivot => write!(f, "Custom Pivot"),
+ PivotGizmoType::Average => write!(f, "Origin (Average Point)"),
+ PivotGizmoType::Active => write!(f, "Origin (Active Object)"),
+ // TODO: Add "Origin (Individual)"
+ }
+ }
+}
+
+#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
pub struct Pivot {
/// Pivot between (0,0) and (1,1)
normalized_pivot: DVec2,
/// Transform to get from normalized pivot to viewspace
- transform_from_normalized: DAffine2,
- /// The viewspace pivot position (if applicable)
- pivot: Option,
+ pub transform_from_normalized: DAffine2,
+ /// The viewspace pivot position
+ pub pivot: Option,
/// The old pivot position in the GUI, used to reduce refreshes of the document bar
- old_pivot_position: ReferencePoint,
+ pub old_pivot_position: ReferencePoint,
+ /// The last ReferencePoint which wasn't none
+ pub last_non_none_reference_point: ReferencePoint,
/// Used to enable and disable the pivot
- active: bool,
+ pub pinned: bool,
+ /// Had selected_visible_and_unlocked_layers
+ pub empty: bool,
}
impl Default for Pivot {
@@ -30,84 +188,62 @@ impl Default for Pivot {
transform_from_normalized: Default::default(),
pivot: Default::default(),
old_pivot_position: ReferencePoint::Center,
- active: true,
+ last_non_none_reference_point: ReferencePoint::Center,
+ pinned: false,
+ empty: true,
}
}
}
impl Pivot {
- /// Calculates the transform that gets from normalized pivot to viewspace.
- fn get_layer_pivot_transform(layer: LayerNodeIdentifier, document: &DocumentMessageHandler) -> DAffine2 {
- let [min, max] = document.metadata().nonzero_bounding_box(layer);
-
- let bounds_transform = DAffine2::from_translation(min) * DAffine2::from_scale(max - min);
- let layer_transform = document.metadata().transform_to_viewport(layer);
- layer_transform * bounds_transform
- }
-
/// Recomputes the pivot position and transform.
- fn recalculate_pivot(&mut self, document: &DocumentMessageHandler) {
- if !self.active {
+ pub fn recalculate_pivot(&mut self, document: &DocumentMessageHandler) {
+ let selected = document.network_interface.selected_nodes();
+ self.empty = !selected.has_selected_nodes();
+ if !selected.has_selected_nodes() {
return;
}
- let selected_nodes = document.network_interface.selected_nodes();
- let mut layers = selected_nodes.selected_visible_and_unlocked_layers(&document.network_interface);
- let Some(first) = layers.next() else {
- // If no layers are selected then we revert things back to default
+ let transform = selected
+ .selected_visible_and_unlocked_layers(&document.network_interface)
+ .find(|layer| !document.network_interface.is_artboard(&layer.to_node(), &[]))
+ .map(|layer| document.metadata().transform_to_viewport_with_first_transform_node_if_group(layer, &document.network_interface))
+ .unwrap_or_default();
+
+ let bounds = document
+ .network_interface
+ .selected_nodes()
+ .selected_visible_and_unlocked_layers(&document.network_interface)
+ .filter_map(|layer| {
+ document
+ .metadata()
+ .bounding_box_with_transform(layer, transform.inverse() * document.metadata().transform_to_viewport(layer))
+ })
+ .reduce(graphene_std::renderer::Quad::combine_bounds);
+
+ let [min, max] = bounds.unwrap_or([DVec2::ZERO, DVec2::ONE]);
+ self.transform_from_normalized = transform * DAffine2::from_translation(min) * DAffine2::from_scale(max - min);
+
+ if self.old_pivot_position != ReferencePoint::None {
+ self.pivot = Some(self.transform_from_normalized.transform_point2(self.normalized_pivot));
+ }
+ }
+
+ pub fn recalculate_pivot_for_layer(&mut self, document: &DocumentMessageHandler, bounds: Option<[DVec2; 2]>) {
+ let selected = document.network_interface.selected_nodes();
+ if !selected.has_selected_nodes() {
self.normalized_pivot = DVec2::splat(0.5);
self.pivot = None;
return;
};
- // Add one because the first item is consumed above.
- let selected_layers_count = layers.count() + 1;
-
- // If just one layer is selected we can use its inner transform (as it accounts for rotation)
- if selected_layers_count == 1 {
- let normalized_pivot = graph_modification_utils::get_pivot(first, &document.network_interface).unwrap_or(DVec2::splat(0.5));
- self.normalized_pivot = normalized_pivot;
- self.transform_from_normalized = Self::get_layer_pivot_transform(first, document);
- self.pivot = Some(self.transform_from_normalized.transform_point2(normalized_pivot));
- } else {
- // If more than one layer is selected we use the AABB with the mean of the pivots
- let xy_summation = document
- .network_interface
- .selected_nodes()
- .selected_visible_and_unlocked_layers(&document.network_interface)
- .map(|layer| graph_modification_utils::get_viewport_pivot(layer, &document.network_interface))
- .reduce(|a, b| a + b)
- .unwrap_or_default();
-
- let pivot = xy_summation / selected_layers_count as f64;
- self.pivot = Some(pivot);
- let [min, max] = document.selected_visible_and_unlock_layers_bounding_box_viewport().unwrap_or([DVec2::ZERO, DVec2::ONE]);
- self.normalized_pivot = (pivot - min) / (max - min);
-
- self.transform_from_normalized = DAffine2::from_translation(min) * DAffine2::from_scale(max - min);
- }
- }
-
- pub fn update_pivot(&mut self, document: &DocumentMessageHandler, overlay_context: &mut OverlayContext, draw_data: Option<(f64,)>) {
- if !overlay_context.visibility_settings.pivot() {
- self.active = false;
- return;
- } else {
- self.active = true;
- }
-
- self.recalculate_pivot(document);
- if let (Some(pivot), Some(data)) = (self.pivot, draw_data) {
- overlay_context.pivot(pivot, data.0);
- }
+ let [min, max] = bounds.unwrap_or([DVec2::ZERO, DVec2::ONE]);
+ self.transform_from_normalized = DAffine2::from_translation(min) * DAffine2::from_scale(max - min);
+ self.pivot = Some(self.transform_from_normalized.transform_point2(self.normalized_pivot));
}
/// Answers if the pivot widget has changed (so we should refresh the tool bar at the top of the canvas).
pub fn should_refresh_pivot_position(&mut self) -> bool {
- if !self.active {
- return false;
- }
-
let new = self.to_pivot_position();
let should_refresh = new != self.old_pivot_position;
self.old_pivot_position = new;
@@ -118,37 +254,24 @@ impl Pivot {
self.normalized_pivot.into()
}
- /// Sets the viewport position of the pivot for all selected layers.
- pub fn set_viewport_position(&self, position: DVec2, document: &DocumentMessageHandler, responses: &mut VecDeque) {
- if !self.active {
+ /// Sets the viewport position of the pivot.
+ pub fn set_viewport_position(&mut self, position: DVec2) {
+ if self.transform_from_normalized.matrix2.determinant().abs() <= f64::EPSILON {
return;
- }
+ };
- for layer in document.network_interface.selected_nodes().selected_visible_and_unlocked_layers(&document.network_interface) {
- let transform = Self::get_layer_pivot_transform(layer, document);
- // Only update the pivot when computed position is finite.
- if transform.matrix2.determinant().abs() <= f64::EPSILON {
- return;
- };
- let pivot = transform.inverse().transform_point2(position);
- responses.add(GraphOperationMessage::TransformSetPivot { layer, pivot });
- }
+ self.normalized_pivot = self.transform_from_normalized.inverse().transform_point2(position);
+ self.pivot = Some(position);
}
- /// Set the pivot using the normalized transform that is set above.
- pub fn set_normalized_position(&self, position: DVec2, document: &DocumentMessageHandler, responses: &mut VecDeque) {
- if !self.active {
- return;
- }
-
- self.set_viewport_position(self.transform_from_normalized.transform_point2(position), document, responses);
+ /// Set the pivot using a normalized position.
+ pub fn set_normalized_position(&mut self, position: DVec2) {
+ self.normalized_pivot = position;
+ self.pivot = Some(self.transform_from_normalized.transform_point2(position));
}
/// Answers if the pointer is currently positioned over the pivot.
pub fn is_over(&self, mouse: DVec2) -> bool {
- if !self.active {
- return false;
- }
self.pivot.filter(|&pivot| mouse.distance_squared(pivot) < (PIVOT_DIAMETER / 2.).powi(2)).is_some()
}
}
diff --git a/editor/src/messages/tool/common_functionality/shape_editor.rs b/editor/src/messages/tool/common_functionality/shape_editor.rs
index 14ae8898a3..f98e50f079 100644
--- a/editor/src/messages/tool/common_functionality/shape_editor.rs
+++ b/editor/src/messages/tool/common_functionality/shape_editor.rs
@@ -212,15 +212,15 @@ impl ClosestSegment {
self.bezier_point_to_viewport
}
- pub fn closest_point(&self, document_metadata: &DocumentMetadata) -> DVec2 {
- let transform = document_metadata.transform_to_viewport(self.layer);
+ pub fn closest_point(&self, document_metadata: &DocumentMetadata, network_interface: &NodeNetworkInterface) -> DVec2 {
+ let transform = document_metadata.transform_to_viewport_if_feeds(self.layer, network_interface);
let bezier_point = self.bezier.evaluate(TValue::Parametric(self.t));
transform.transform_point2(bezier_point)
}
/// Updates this [`ClosestSegment`] with the viewport-space location of the closest point on the segment to the given mouse position.
- pub fn update_closest_point(&mut self, document_metadata: &DocumentMetadata, mouse_position: DVec2) {
- let transform = document_metadata.transform_to_viewport(self.layer);
+ pub fn update_closest_point(&mut self, document_metadata: &DocumentMetadata, network_interface: &NodeNetworkInterface, mouse_position: DVec2) {
+ let transform = document_metadata.transform_to_viewport_if_feeds(self.layer, network_interface);
let layer_mouse_pos = transform.inverse().transform_point2(mouse_position);
let t = self.bezier.project(layer_mouse_pos).clamp(0., 1.);
@@ -239,9 +239,9 @@ impl ClosestSegment {
tolerance.powi(2) < self.distance_squared(mouse_position)
}
- pub fn handle_positions(&self, document_metadata: &DocumentMetadata) -> (Option, Option) {
+ pub fn handle_positions(&self, document_metadata: &DocumentMetadata, network_interface: &NodeNetworkInterface) -> (Option, Option) {
// Transform to viewport space
- let transform = document_metadata.transform_to_viewport(self.layer);
+ let transform = document_metadata.transform_to_viewport_if_feeds(self.layer, network_interface);
// Split the Bezier at the parameter `t`
let [first, second] = self.bezier.split(TValue::Parametric(self.t));
@@ -307,7 +307,7 @@ impl ClosestSegment {
}
pub fn calculate_perp(&self, document: &DocumentMessageHandler) -> DVec2 {
- let tangent = if let (Some(handle1), Some(handle2)) = self.handle_positions(document.metadata()) {
+ let tangent = if let (Some(handle1), Some(handle2)) = self.handle_positions(document.metadata(), &document.network_interface) {
(handle1 - handle2).try_normalize()
} else {
let [first_point, last_point] = self.points();
@@ -339,7 +339,7 @@ impl ClosestSegment {
break_colinear_molding: bool,
temporary_adjacent_handles_while_molding: Option<[Option; 2]>,
) -> Option<[Option; 2]> {
- let transform = document.metadata().transform_to_viewport(self.layer);
+ let transform = document.metadata().transform_to_viewport_if_feeds(self.layer, &document.network_interface);
let start = self.bezier.start;
let end = self.bezier.end;
@@ -507,7 +507,7 @@ impl ShapeState {
continue;
};
- let to_document = document.metadata().transform_to_document(*layer);
+ let to_document = document.metadata().transform_to_document_if_feeds(*layer, &document.network_interface);
for &selected in &state.selected_points {
let source = match selected {
@@ -564,7 +564,11 @@ impl ShapeState {
let already_selected = selected_shape_state.is_point_selected(manipulator_point_id);
// Offset to snap the selected point to the cursor
- let offset = mouse_position - network_interface.document_metadata().transform_to_viewport(layer).transform_point2(point_position);
+ let offset = mouse_position
+ - network_interface
+ .document_metadata()
+ .transform_to_viewport_if_feeds(layer, network_interface)
+ .transform_point2(point_position);
// This is selecting the manipulator only for now, next to generalize to points
@@ -621,7 +625,11 @@ impl ShapeState {
let already_selected = selected_shape_state.is_point_selected(manipulator_point_id);
// Offset to snap the selected point to the cursor
- let offset = mouse_position - network_interface.document_metadata().transform_to_viewport(layer).transform_point2(point_position);
+ let offset = mouse_position
+ - network_interface
+ .document_metadata()
+ .transform_to_viewport_if_feeds(layer, network_interface)
+ .transform_point2(point_position);
// Gather current selection information
let points = self
@@ -653,7 +661,7 @@ impl ShapeState {
let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else {
return;
};
- let to_viewport = document.metadata().transform_to_viewport(layer);
+ let to_viewport = document.metadata().transform_to_viewport_if_feeds(layer, &document.network_interface);
let layer_mouse = to_viewport.inverse().transform_point2(mouse);
let state = self.selected_shape_state.entry(layer).or_default();
@@ -875,7 +883,7 @@ impl ShapeState {
}
let vector_data = network_interface.compute_modified_vector(layer)?;
- let transform = network_interface.document_metadata().transform_to_document(layer).inverse();
+ let transform = network_interface.document_metadata().transform_to_document_if_feeds(layer, network_interface).inverse();
let position = transform.transform_point2(new_position);
let current_position = point.get_position(&vector_data)?;
let delta = position - current_position;
@@ -1026,7 +1034,7 @@ impl ShapeState {
let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else {
continue;
};
- let transform = document.metadata().transform_to_document(layer);
+ let transform = document.metadata().transform_to_document_if_feeds(layer, &document.network_interface);
for &point in layer_state.selected_points.iter() {
let Some(handles) = point.get_handle_pair(&vector_data) else { continue };
@@ -1071,7 +1079,7 @@ impl ShapeState {
let mut normalized = handle_directions[0].and_then(|a| handle_directions[1].and_then(|b| (a - b).try_normalize()));
- if normalized.is_none() {
+ if normalized.is_none() || handle_directions.iter().any(|&d| d.is_some_and(|d| d.length_squared() < f64::EPSILON * 1e5)) {
handle_directions = anchor_positions.map(|relative_anchor| relative_anchor.map(|relative_anchor| (relative_anchor - anchor) / 3.));
normalized = handle_directions[0].and_then(|a| handle_directions[1].and_then(|b| (a - b).try_normalize()))
}
@@ -1116,8 +1124,8 @@ impl ShapeState {
let opposing_handles = handle_lengths.as_ref().and_then(|handle_lengths| handle_lengths.get(&layer));
- let transform_to_viewport_space = document.metadata().transform_to_viewport(layer);
- let transform_to_document_space = document.metadata().transform_to_document(layer);
+ let transform_to_viewport_space = document.metadata().transform_to_viewport_if_feeds(layer, &document.network_interface);
+ let transform_to_document_space = document.metadata().transform_to_document_if_feeds(layer, &document.network_interface);
let delta_transform = if in_viewport_space {
transform_to_viewport_space
} else {
@@ -1210,7 +1218,7 @@ impl ShapeState {
.iter()
.filter_map(|(&layer, state)| {
let vector_data = document.network_interface.compute_modified_vector(layer)?;
- let transform = document.metadata().transform_to_document(layer);
+ let transform = document.metadata().transform_to_document_if_feeds(layer, &document.network_interface);
let opposing_handle_lengths = vector_data
.colinear_manipulators
.iter()
@@ -1575,7 +1583,7 @@ impl ShapeState {
let mut manipulator_point = None;
let vector_data = network_interface.compute_modified_vector(layer)?;
- let viewspace = network_interface.document_metadata().transform_to_viewport(layer);
+ let viewspace = network_interface.document_metadata().transform_to_viewport_if_feeds(layer, network_interface);
// Handles
for (segment_id, bezier, _, _) in vector_data.segment_bezier_iter() {
@@ -1611,7 +1619,7 @@ impl ShapeState {
/// Find the `t` value along the path segment we have clicked upon, together with that segment ID.
fn closest_segment(&self, network_interface: &NodeNetworkInterface, layer: LayerNodeIdentifier, position: glam::DVec2, tolerance: f64) -> Option {
- let transform = network_interface.document_metadata().transform_to_viewport(layer);
+ let transform = network_interface.document_metadata().transform_to_viewport_if_feeds(layer, network_interface);
let layer_pos = transform.inverse().transform_point2(position);
let tolerance = tolerance + 0.5;
@@ -1785,7 +1793,7 @@ impl ShapeState {
pub fn flip_smooth_sharp(&self, network_interface: &NodeNetworkInterface, target: glam::DVec2, tolerance: f64, responses: &mut VecDeque) -> bool {
let mut process_layer = |layer| {
let vector_data = network_interface.compute_modified_vector(layer)?;
- let transform_to_screenspace = network_interface.document_metadata().transform_to_viewport(layer);
+ let transform_to_screenspace = network_interface.document_metadata().transform_to_viewport_if_feeds(layer, network_interface);
let mut result = None;
let mut closest_distance_squared = tolerance * tolerance;
@@ -1889,7 +1897,7 @@ impl ShapeState {
let vector_data = network_interface.compute_modified_vector(layer);
let Some(vector_data) = vector_data else { continue };
- let transform = network_interface.document_metadata().transform_to_viewport(layer);
+ let transform = network_interface.document_metadata().transform_to_viewport_if_feeds(layer, network_interface);
assert_eq!(vector_data.segment_domain.ids().len(), vector_data.start_point().count());
assert_eq!(vector_data.segment_domain.ids().len(), vector_data.end_point().count());
diff --git a/editor/src/messages/tool/common_functionality/shapes/ellipse_shape.rs b/editor/src/messages/tool/common_functionality/shapes/ellipse_shape.rs
index fe97c22318..700f3c2779 100644
--- a/editor/src/messages/tool/common_functionality/shapes/ellipse_shape.rs
+++ b/editor/src/messages/tool/common_functionality/shapes/ellipse_shape.rs
@@ -77,7 +77,7 @@ mod test_ellipse {
layers
.filter_map(|layer| {
let node_graph_layer = NodeGraphLayer::new(layer, &document.network_interface);
- let ellipse_node = node_graph_layer.upstream_node_id_from_protonode(ellipse::protonode_identifier())?;
+ let ellipse_node = node_graph_layer.upstream_node_id_from_protonode(ellipse::IDENTIFIER)?;
Some(ResolvedEllipse {
radius_x: instrumented.grab_protonode_input::(&vec![ellipse_node], &editor.runtime).unwrap(),
radius_y: instrumented.grab_protonode_input::(&vec![ellipse_node], &editor.runtime).unwrap(),
diff --git a/editor/src/messages/tool/common_functionality/utility_functions.rs b/editor/src/messages/tool/common_functionality/utility_functions.rs
index 23829271b0..6ae3f130b5 100644
--- a/editor/src/messages/tool/common_functionality/utility_functions.rs
+++ b/editor/src/messages/tool/common_functionality/utility_functions.rs
@@ -393,6 +393,7 @@ pub fn transforming_transform_cage(
input: &InputPreprocessorMessageHandler,
responses: &mut VecDeque,
layers_dragging: &mut Vec,
+ center_of_transformation: Option,
) -> (bool, bool, bool) {
let dragging_bounds = bounding_box_manager.as_mut().and_then(|bounding_box| {
let edges = bounding_box.check_selected_edges(input.mouse.position);
@@ -429,17 +430,12 @@ pub fn transforming_transform_cage(
}
});
- let mut selected = Selected::new(
- &mut bounds.original_transforms,
- &mut bounds.center_of_transformation,
- layers_dragging,
- responses,
- &document.network_interface,
- None,
- &ToolType::Select,
- None,
- );
- bounds.center_of_transformation = selected.mean_average_of_pivots();
+ bounds.center_of_transformation = center_of_transformation.unwrap_or_else(|| {
+ document
+ .network_interface
+ .selected_nodes()
+ .selected_visible_and_unlocked_layers_mean_average_origin(&document.network_interface)
+ });
// Check if we're hovering over a skew triangle
let edges = bounds.check_selected_edges(input.mouse.position);
@@ -469,18 +465,12 @@ pub fn transforming_transform_cage(
}
});
- let mut selected = Selected::new(
- &mut bounds.original_transforms,
- &mut bounds.center_of_transformation,
- &selected,
- responses,
- &document.network_interface,
- None,
- &ToolType::Select,
- None,
- );
-
- bounds.center_of_transformation = selected.mean_average_of_pivots();
+ bounds.center_of_transformation = center_of_transformation.unwrap_or_else(|| {
+ document
+ .network_interface
+ .selected_nodes()
+ .selected_visible_and_unlocked_layers_mean_average_origin(&document.network_interface)
+ });
}
*layers_dragging = selected;
diff --git a/editor/src/messages/tool/tool_message_handler.rs b/editor/src/messages/tool/tool_message_handler.rs
index 9413495488..6000301a18 100644
--- a/editor/src/messages/tool/tool_message_handler.rs
+++ b/editor/src/messages/tool/tool_message_handler.rs
@@ -12,6 +12,7 @@ use graphene_std::raster::color::Color;
const ARTBOARD_OVERLAY_PROVIDER: OverlayProvider = |context| DocumentMessage::DrawArtboardOverlays(context).into();
+#[derive(ExtractField)]
pub struct ToolMessageData<'a> {
pub document_id: DocumentId,
pub document: &'a mut DocumentMessageHandler,
@@ -21,7 +22,7 @@ pub struct ToolMessageData<'a> {
pub preferences: &'a PreferencesMessageHandler,
}
-#[derive(Debug, Default)]
+#[derive(Debug, Default, ExtractField)]
pub struct ToolMessageHandler {
pub tool_state: ToolFsmState,
pub transform_layer_handler: TransformLayerMessageHandler,
@@ -29,6 +30,7 @@ pub struct ToolMessageHandler {
pub tool_is_active: bool,
}
+#[message_handler_data]
impl MessageHandler> for ToolMessageHandler {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque, data: ToolMessageData) {
let ToolMessageData {
@@ -181,6 +183,11 @@ impl MessageHandler> for ToolMessageHandler {
send: Box::new(TransformLayerMessage::SelectionChanged.into()),
});
+ responses.add(BroadcastMessage::SubscribeEvent {
+ on: BroadcastEvent::SelectionChanged,
+ send: Box::new(SelectToolMessage::SyncHistory.into()),
+ });
+
self.tool_is_active = true;
let tool_data = &mut self.tool_state.tool_data;
diff --git a/editor/src/messages/tool/tool_messages/artboard_tool.rs b/editor/src/messages/tool/tool_messages/artboard_tool.rs
index d72e28df51..e14058c32c 100644
--- a/editor/src/messages/tool/tool_messages/artboard_tool.rs
+++ b/editor/src/messages/tool/tool_messages/artboard_tool.rs
@@ -13,7 +13,7 @@ use crate::messages::tool::common_functionality::transformation_cage::*;
use graph_craft::document::NodeId;
use graphene_std::renderer::Quad;
-#[derive(Default)]
+#[derive(Default, ExtractField)]
pub struct ArtboardTool {
fsm_state: ArtboardToolFsmState,
data: ArtboardToolData,
@@ -48,6 +48,7 @@ impl ToolMetadata for ArtboardTool {
}
}
+#[message_handler_data]
impl<'a> MessageHandler> for ArtboardTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque, tool_data: &mut ToolActionHandlerData<'a>) {
self.fsm_state.process_event(message, &mut self.data, tool_data, &(), responses, false);
@@ -567,7 +568,7 @@ mod test_artboard {
Ok(instrumented) => instrumented,
Err(e) => panic!("Failed to evaluate graph: {}", e),
};
- instrumented.grab_all_input::(&editor.runtime).collect()
+ instrumented.grab_all_input::(&editor.runtime).collect()
}
#[tokio::test]
diff --git a/editor/src/messages/tool/tool_messages/brush_tool.rs b/editor/src/messages/tool/tool_messages/brush_tool.rs
index b468603989..a625bdb9e6 100644
--- a/editor/src/messages/tool/tool_messages/brush_tool.rs
+++ b/editor/src/messages/tool/tool_messages/brush_tool.rs
@@ -1,6 +1,6 @@
use super::tool_prelude::*;
use crate::consts::DEFAULT_BRUSH_SIZE;
-use crate::messages::portfolio::document::graph_operation::transform_utils::{get_current_normalized_pivot, get_current_transform};
+use crate::messages::portfolio::document::graph_operation::transform_utils::get_current_transform;
use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type;
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
use crate::messages::portfolio::document::utility_types::network_interface::FlowType;
@@ -20,7 +20,7 @@ pub enum DrawMode {
Restore,
}
-#[derive(Default)]
+#[derive(Default, ExtractField)]
pub struct BrushTool {
fsm_state: BrushToolFsmState,
data: BrushToolData,
@@ -185,6 +185,7 @@ impl LayoutHolder for BrushTool {
}
}
+#[message_handler_data]
impl<'a> MessageHandler> for BrushTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque, tool_data: &mut ToolActionHandlerData<'a>) {
let ToolMessage::Brush(BrushToolMessage::UpdateOptions(action)) = message else {
@@ -286,9 +287,7 @@ impl BrushToolData {
}
if *reference == Some("Transform".to_string()) {
- let upstream = document.metadata().upstream_transform(node_id);
- let pivot = DAffine2::from_translation(upstream.transform_point2(get_current_normalized_pivot(&node.inputs)));
- self.transform = pivot * get_current_transform(&node.inputs) * pivot.inverse() * self.transform;
+ self.transform = get_current_transform(&node.inputs) * self.transform;
}
}
diff --git a/editor/src/messages/tool/tool_messages/eyedropper_tool.rs b/editor/src/messages/tool/tool_messages/eyedropper_tool.rs
index 3b3f324972..ce4b09d8e9 100644
--- a/editor/src/messages/tool/tool_messages/eyedropper_tool.rs
+++ b/editor/src/messages/tool/tool_messages/eyedropper_tool.rs
@@ -1,7 +1,7 @@
use super::tool_prelude::*;
use crate::messages::tool::utility_types::DocumentToolData;
-#[derive(Default)]
+#[derive(Default, ExtractField)]
pub struct EyedropperTool {
fsm_state: EyedropperToolFsmState,
data: EyedropperToolData,
@@ -39,6 +39,7 @@ impl LayoutHolder for EyedropperTool {
}
}
+#[message_handler_data]
impl<'a> MessageHandler> for EyedropperTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque, tool_data: &mut ToolActionHandlerData<'a>) {
self.fsm_state.process_event(message, &mut self.data, tool_data, &(), responses, true);
diff --git a/editor/src/messages/tool/tool_messages/fill_tool.rs b/editor/src/messages/tool/tool_messages/fill_tool.rs
index 5aeb063d87..94ad2b8c21 100644
--- a/editor/src/messages/tool/tool_messages/fill_tool.rs
+++ b/editor/src/messages/tool/tool_messages/fill_tool.rs
@@ -3,7 +3,7 @@ use crate::messages::portfolio::document::overlays::utility_types::OverlayContex
use crate::messages::tool::common_functionality::graph_modification_utils::NodeGraphLayer;
use graphene_std::vector::style::Fill;
-#[derive(Default)]
+#[derive(Default, ExtractField)]
pub struct FillTool {
fsm_state: FillToolFsmState,
}
@@ -41,6 +41,7 @@ impl LayoutHolder for FillTool {
}
}
+#[message_handler_data]
impl<'a> MessageHandler> for FillTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque, tool_data: &mut ToolActionHandlerData<'a>) {
self.fsm_state.process_event(message, &mut (), tool_data, &(), responses, true);
diff --git a/editor/src/messages/tool/tool_messages/freehand_tool.rs b/editor/src/messages/tool/tool_messages/freehand_tool.rs
index e2abddef2a..fb1539a818 100644
--- a/editor/src/messages/tool/tool_messages/freehand_tool.rs
+++ b/editor/src/messages/tool/tool_messages/freehand_tool.rs
@@ -13,7 +13,7 @@ use graphene_std::Color;
use graphene_std::vector::VectorModificationType;
use graphene_std::vector::{PointId, SegmentId};
-#[derive(Default)]
+#[derive(Default, ExtractField)]
pub struct FreehandTool {
fsm_state: FreehandToolFsmState,
data: FreehandToolData,
@@ -116,6 +116,7 @@ impl LayoutHolder for FreehandTool {
}
}
+#[message_handler_data]
impl<'a> MessageHandler> for FreehandTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque, tool_data: &mut ToolActionHandlerData<'a>) {
let ToolMessage::Freehand(FreehandToolMessage::UpdateOptions(action)) = message else {
diff --git a/editor/src/messages/tool/tool_messages/gradient_tool.rs b/editor/src/messages/tool/tool_messages/gradient_tool.rs
index 030da8ec1d..0e84f9585f 100644
--- a/editor/src/messages/tool/tool_messages/gradient_tool.rs
+++ b/editor/src/messages/tool/tool_messages/gradient_tool.rs
@@ -7,7 +7,7 @@ use crate::messages::tool::common_functionality::graph_modification_utils::{Node
use crate::messages::tool::common_functionality::snapping::SnapManager;
use graphene_std::vector::style::{Fill, Gradient, GradientType};
-#[derive(Default)]
+#[derive(Default, ExtractField)]
pub struct GradientTool {
fsm_state: GradientToolFsmState,
data: GradientToolData,
@@ -53,6 +53,7 @@ impl ToolMetadata for GradientTool {
}
}
+#[message_handler_data]
impl<'a> MessageHandler> for GradientTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque, tool_data: &mut ToolActionHandlerData<'a>) {
let ToolMessage::Gradient(GradientToolMessage::UpdateOptions(action)) = message else {
diff --git a/editor/src/messages/tool/tool_messages/navigate_tool.rs b/editor/src/messages/tool/tool_messages/navigate_tool.rs
index 0a76a331dc..9f9ef0307b 100644
--- a/editor/src/messages/tool/tool_messages/navigate_tool.rs
+++ b/editor/src/messages/tool/tool_messages/navigate_tool.rs
@@ -1,6 +1,6 @@
use super::tool_prelude::*;
-#[derive(Default)]
+#[derive(Default, ExtractField)]
pub struct NavigateTool {
fsm_state: NavigateToolFsmState,
tool_data: NavigateToolData,
@@ -38,6 +38,7 @@ impl LayoutHolder for NavigateTool {
}
}
+#[message_handler_data]
impl<'a> MessageHandler> for NavigateTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque, tool_data: &mut ToolActionHandlerData<'a>) {
self.fsm_state.process_event(message, &mut self.tool_data, tool_data, &(), responses, true);
diff --git a/editor/src/messages/tool/tool_messages/path_tool.rs b/editor/src/messages/tool/tool_messages/path_tool.rs
index dbce924fc9..d54ce54274 100644
--- a/editor/src/messages/tool/tool_messages/path_tool.rs
+++ b/editor/src/messages/tool/tool_messages/path_tool.rs
@@ -11,6 +11,7 @@ use crate::messages::portfolio::document::utility_types::network_interface::Node
use crate::messages::portfolio::document::utility_types::transformation::Axis;
use crate::messages::preferences::SelectionMode;
use crate::messages::tool::common_functionality::auto_panning::AutoPanning;
+use crate::messages::tool::common_functionality::pivot::{PivotGizmo, PivotGizmoType, PivotToolSource, pin_pivot_widget, pivot_gizmo_type_widget, pivot_reference_point_widget};
use crate::messages::tool::common_functionality::shape_editor::{
ClosestSegment, ManipulatorAngle, OpposingHandleLengths, SelectedLayerState, SelectedPointsInfo, SelectionChange, SelectionShape, SelectionShapeType, ShapeState,
};
@@ -18,11 +19,12 @@ use crate::messages::tool::common_functionality::snapping::{SnapCache, SnapCandi
use crate::messages::tool::common_functionality::utility_functions::{calculate_segment_angle, find_two_param_best_approximate};
use bezier_rs::{Bezier, BezierHandles, TValue};
use graphene_std::renderer::Quad;
+use graphene_std::transform::ReferencePoint;
use graphene_std::vector::{HandleExt, HandleId, NoHashBuilder, SegmentId, VectorData};
use graphene_std::vector::{ManipulatorPointId, PointId, VectorModificationType};
use std::vec;
-#[derive(Default)]
+#[derive(Default, ExtractField)]
pub struct PathTool {
fsm_state: PathToolFsmState,
tool_data: PathToolData,
@@ -106,6 +108,9 @@ pub enum PathToolMessage {
SelectedPointYChanged {
new_y: f64,
},
+ SetPivot {
+ position: ReferencePoint,
+ },
SwapSelectedHandles,
UpdateOptions(PathOptionsUpdate),
UpdateSelectedPointsStatus {
@@ -141,6 +146,9 @@ pub enum PathOptionsUpdate {
OverlayModeType(PathOverlayMode),
PointEditingMode { enabled: bool },
SegmentEditingMode { enabled: bool },
+ PivotGizmoType(PivotGizmoType),
+ TogglePivotGizmoType(bool),
+ TogglePivotPinned,
}
impl ToolMetadata for PathTool {
@@ -255,6 +263,20 @@ impl LayoutHolder for PathTool {
.selected_index(Some(self.options.path_overlay_mode as u32))
.widget_holder();
+ let [_checkbox, _dropdown] = {
+ let pivot_gizmo_type_widget = pivot_gizmo_type_widget(self.tool_data.pivot_gizmo.state, PivotToolSource::Path);
+ [pivot_gizmo_type_widget[0].clone(), pivot_gizmo_type_widget[2].clone()]
+ };
+
+ let has_something = !self.tool_data.saved_points_before_anchor_convert_smooth_sharp.is_empty();
+ let _pivot_reference = pivot_reference_point_widget(
+ has_something || !self.tool_data.pivot_gizmo.state.is_pivot(),
+ self.tool_data.pivot_gizmo.pivot.to_pivot_position(),
+ PivotToolSource::Path,
+ );
+
+ let _pin_pivot = pin_pivot_widget(self.tool_data.pivot_gizmo.pin_active(), false, PivotToolSource::Path);
+
Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row {
widgets: vec![
x_location,
@@ -268,13 +290,22 @@ impl LayoutHolder for PathTool {
point_editing_mode,
related_seperator.clone(),
segment_editing_mode,
- unrelated_seperator,
+ unrelated_seperator.clone(),
path_overlay_mode_widget,
+ unrelated_seperator.clone(),
+ // checkbox.clone(),
+ // related_seperator.clone(),
+ // dropdown.clone(),
+ // unrelated_seperator,
+ // pivot_reference,
+ // related_seperator.clone(),
+ // pin_pivot,
],
}]))
}
}
+#[message_handler_data]
impl<'a> MessageHandler> for PathTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque, tool_data: &mut ToolActionHandlerData<'a>) {
let updating_point = message == ToolMessage::Path(PathToolMessage::SelectedPointUpdated);
@@ -293,6 +324,29 @@ impl<'a> MessageHandler> for PathToo
self.options.path_editing_mode.segment_editing_mode = enabled;
responses.add(OverlaysMessage::Draw);
}
+ PathOptionsUpdate::PivotGizmoType(gizmo_type) => {
+ if !self.tool_data.pivot_gizmo.state.disabled {
+ self.tool_data.pivot_gizmo.state.gizmo_type = gizmo_type;
+ responses.add(ToolMessage::UpdateHints);
+ let pivot_gizmo = self.tool_data.pivot_gizmo();
+ responses.add(TransformLayerMessage::SetPivotGizmo { pivot_gizmo });
+ responses.add(NodeGraphMessage::RunDocumentGraph);
+ self.send_layout(responses, LayoutTarget::ToolOptions);
+ }
+ }
+ PathOptionsUpdate::TogglePivotGizmoType(state) => {
+ self.tool_data.pivot_gizmo.state.disabled = !state;
+ responses.add(ToolMessage::UpdateHints);
+ responses.add(NodeGraphMessage::RunDocumentGraph);
+ self.send_layout(responses, LayoutTarget::ToolOptions);
+ }
+
+ PathOptionsUpdate::TogglePivotPinned => {
+ self.tool_data.pivot_gizmo.pivot.pinned = !self.tool_data.pivot_gizmo.pivot.pinned;
+ responses.add(ToolMessage::UpdateHints);
+ responses.add(NodeGraphMessage::RunDocumentGraph);
+ self.send_layout(responses, LayoutTarget::ToolOptions);
+ }
},
ToolMessage::Path(PathToolMessage::ClosePath) => {
responses.add(DocumentMessage::AddTransaction);
@@ -443,6 +497,8 @@ struct PathToolData {
last_click_time: u64,
dragging_state: DraggingState,
angle: f64,
+ pivot_gizmo: PivotGizmo,
+ ordered_points: Vec,
opposite_handle_position: Option,
last_clicked_point_was_selected: bool,
last_clicked_segment_was_selected: bool,
@@ -718,7 +774,7 @@ impl PathToolData {
let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else {
continue;
};
- let transform = document.metadata().transform_to_document(layer);
+ let transform = document.metadata().transform_to_document_if_feeds(layer, &document.network_interface);
let mut layer_manipulators = HashSet::with_hasher(NoHashBuilder);
for point in state.selected_points() {
@@ -828,7 +884,7 @@ impl PathToolData {
let selected_handle = selection.selected_points().next()?.as_handle()?;
let handle_id = selected_handle.to_manipulator_point();
- let layer_to_document = document.metadata().transform_to_document(*layer);
+ let layer_to_document = document.metadata().transform_to_document_if_feeds(*layer, &document.network_interface);
let vector_data = document.network_interface.compute_modified_vector(*layer)?;
let handle_position_local = selected_handle.to_manipulator_point().get_position(&vector_data)?;
@@ -870,7 +926,7 @@ impl PathToolData {
let anchor = handle_id.get_anchor(&vector_data);
let (angle, anchor_position) = calculate_adjacent_anchor_tangent(handle_id, anchor, adjacent_anchor, &vector_data);
- let layer_to_document = document.metadata().transform_to_document(*layer);
+ let layer_to_document = document.metadata().transform_to_document_if_feeds(*layer, &document.network_interface);
self.adjacent_anchor_offset = handle_id
.get_anchor_position(&vector_data)
@@ -1017,7 +1073,7 @@ impl PathToolData {
}
// If already hovering on a segment, then recalculate its closest point
else if let Some(closest_segment) = &mut self.segment {
- closest_segment.update_closest_point(document.metadata(), position);
+ closest_segment.update_closest_point(document.metadata(), &document.network_interface, position);
if closest_segment.too_far(position, SEGMENT_INSERTION_DISTANCE) {
self.segment = None;
@@ -1084,7 +1140,7 @@ impl PathToolData {
let layer = sliding_point_info.layer;
let Some(vector_data) = network_interface.compute_modified_vector(layer) else { return };
- let transform = network_interface.document_metadata().transform_to_viewport(layer);
+ let transform = network_interface.document_metadata().transform_to_viewport_if_feeds(layer, network_interface);
let layer_pos = transform.inverse().transform_point2(target_position);
let segments = sliding_point_info.connected_segments;
@@ -1315,6 +1371,16 @@ impl PathToolData {
}
}
}
+
+ fn pivot_gizmo(&self) -> PivotGizmo {
+ self.pivot_gizmo.clone()
+ }
+
+ fn sync_history(&mut self, points: &[ManipulatorPointId]) {
+ self.ordered_points.retain(|layer| points.contains(layer));
+ self.ordered_points.extend(points.iter().find(|&layer| !self.ordered_points.contains(layer)));
+ self.pivot_gizmo.point = self.ordered_points.last().copied()
+ }
}
impl Fsm for PathToolFsmState {
@@ -1327,6 +1393,10 @@ impl Fsm for PathToolFsmState {
update_dynamic_hints(self, responses, shape_editor, document, tool_data, tool_options);
let ToolMessage::Path(event) = event else { return self };
+
+ // TODO(mTvare6): Remove once gizmos are implemented for path_tool
+ tool_data.pivot_gizmo.state.disabled = true;
+
match (self, event) {
(_, PathToolMessage::SelectionChanged) => {
// Set the newly targeted layers to visible
@@ -1343,6 +1413,9 @@ impl Fsm for PathToolFsmState {
shape_editor.update_selected_anchors_status(display_anchors);
shape_editor.update_selected_handles_status(display_handles);
+ let new_points = shape_editor.selected_points().copied().collect::>();
+ tool_data.sync_history(&new_points);
+
self
}
(_, PathToolMessage::Overlays(mut overlay_context)) => {
@@ -1412,7 +1485,7 @@ impl Fsm for PathToolFsmState {
if let Some(closest_segment) = &tool_data.segment {
if tool_options.path_editing_mode.segment_editing_mode {
- let transform = document.metadata().transform_to_viewport(closest_segment.layer());
+ let transform = document.metadata().transform_to_viewport_if_feeds(closest_segment.layer(), &document.network_interface);
overlay_context.outline_overlay_bezier(closest_segment.bezier(), transform);
@@ -1430,7 +1503,7 @@ impl Fsm for PathToolFsmState {
}
} else {
let perp = closest_segment.calculate_perp(document);
- let point = closest_segment.closest_point(document.metadata());
+ let point = closest_segment.closest_point(document.metadata(), &document.network_interface);
// Draw an X on the segment
if tool_data.delete_segment_pressed {
@@ -1710,14 +1783,8 @@ impl Fsm for PathToolFsmState {
}
(PathToolFsmState::Ready, PathToolMessage::PointerMove { delete_segment, .. }) => {
tool_data.delete_segment_pressed = input.keyboard.get(delete_segment as usize);
-
- if !tool_data.saved_points_before_anchor_convert_smooth_sharp.is_empty() {
- tool_data.saved_points_before_anchor_convert_smooth_sharp.clear();
- }
-
- if tool_data.adjacent_anchor_offset.is_some() {
- tool_data.adjacent_anchor_offset = None;
- }
+ tool_data.saved_points_before_anchor_convert_smooth_sharp.clear();
+ tool_data.adjacent_anchor_offset = None;
tool_data.stored_selection = None;
responses.add(OverlaysMessage::Draw);
@@ -2208,6 +2275,18 @@ impl Fsm for PathToolFsmState {
responses.add(DocumentMessage::EndTransaction);
PathToolFsmState::Ready
}
+ (_, PathToolMessage::SetPivot { position }) => {
+ responses.add(DocumentMessage::StartTransaction);
+
+ tool_data.pivot_gizmo.pivot.last_non_none_reference_point = position;
+ let position: Option = position.into();
+ tool_data.pivot_gizmo.pivot.set_normalized_position(position.unwrap());
+ let pivot_gizmo = tool_data.pivot_gizmo();
+ responses.add(TransformLayerMessage::SetPivotGizmo { pivot_gizmo });
+ responses.add(NodeGraphMessage::RunDocumentGraph);
+
+ self
+ }
(_, _) => PathToolFsmState::Ready,
}
}
@@ -2280,7 +2359,10 @@ fn get_selection_status(network_interface: &NodeNetworkInterface, shape_state: &
return SelectionStatus::None;
};
- let coordinates = network_interface.document_metadata().transform_to_document(layer).transform_point2(local_position);
+ let coordinates = network_interface
+ .document_metadata()
+ .transform_to_document_if_feeds(layer, network_interface)
+ .transform_point2(local_position);
let manipulator_angle = if vector_data.colinear(point) { ManipulatorAngle::Colinear } else { ManipulatorAngle::Free };
return SelectionStatus::One(SingleSelectedPoint {
diff --git a/editor/src/messages/tool/tool_messages/pen_tool.rs b/editor/src/messages/tool/tool_messages/pen_tool.rs
index 14f95a48f7..53a9e4d17c 100644
--- a/editor/src/messages/tool/tool_messages/pen_tool.rs
+++ b/editor/src/messages/tool/tool_messages/pen_tool.rs
@@ -17,7 +17,7 @@ use graphene_std::Color;
use graphene_std::vector::{HandleId, ManipulatorPointId, NoHashBuilder, SegmentId, StrokeId, VectorData};
use graphene_std::vector::{PointId, VectorModificationType};
-#[derive(Default)]
+#[derive(Default, ExtractField)]
pub struct PenTool {
fsm_state: PenToolFsmState,
tool_data: PenToolData,
@@ -186,6 +186,7 @@ impl LayoutHolder for PenTool {
}
}
+#[message_handler_data]
impl<'a> MessageHandler> for PenTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque, tool_data: &mut ToolActionHandlerData<'a>) {
let ToolMessage::Pen(PenToolMessage::UpdateOptions(action)) = message else {
diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs
index 76158d08e5..e6f4a5d7a3 100644
--- a/editor/src/messages/tool/tool_messages/select_tool.rs
+++ b/editor/src/messages/tool/tool_messages/select_tool.rs
@@ -12,9 +12,10 @@ use crate::messages::portfolio::document::utility_types::nodes::SelectedNodes;
use crate::messages::preferences::SelectionMode;
use crate::messages::tool::common_functionality::auto_panning::AutoPanning;
use crate::messages::tool::common_functionality::compass_rose::{Axis, CompassRose};
+use crate::messages::tool::common_functionality::graph_modification_utils;
use crate::messages::tool::common_functionality::graph_modification_utils::is_layer_fed_by_node_of_name;
use crate::messages::tool::common_functionality::measure;
-use crate::messages::tool::common_functionality::pivot::Pivot;
+use crate::messages::tool::common_functionality::pivot::{PivotGizmo, PivotGizmoType, PivotToolSource, pin_pivot_widget, pivot_gizmo_type_widget, pivot_reference_point_widget};
use crate::messages::tool::common_functionality::shape_editor::SelectionShapeType;
use crate::messages::tool::common_functionality::snapping::{self, SnapCandidatePoint, SnapData, SnapManager};
use crate::messages::tool::common_functionality::transformation_cage::*;
@@ -28,7 +29,7 @@ use graphene_std::renderer::Rect;
use graphene_std::transform::ReferencePoint;
use std::fmt;
-#[derive(Default)]
+#[derive(Default, ExtractField)]
pub struct SelectTool {
fsm_state: SelectToolFsmState,
tool_data: SelectToolData,
@@ -43,6 +44,9 @@ pub struct SelectOptions {
#[derive(PartialEq, Eq, Clone, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)]
pub enum SelectOptionsUpdate {
NestedSelectionBehavior(NestedSelectionBehavior),
+ PivotGizmoType(PivotGizmoType),
+ TogglePivotGizmoType(bool),
+ TogglePivotPinned,
}
#[derive(Default, PartialEq, Eq, Clone, Copy, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)]
@@ -95,6 +99,14 @@ pub enum SelectToolMessage {
SetPivot {
position: ReferencePoint,
},
+ SyncHistory,
+ ShiftSelectedNodes {
+ offset: DVec2,
+ },
+ PivotShift {
+ offset: Option,
+ flush: bool,
+ },
}
impl ToolMetadata for SelectTool {
@@ -122,14 +134,12 @@ impl SelectTool {
DropdownInput::new(vec![layer_selection_behavior_entries])
.selected_index(Some((self.tool_data.nested_selection_behavior == NestedSelectionBehavior::Deepest) as u32))
- .tooltip("Choose if clicking nested layers directly selects the deepest, or selects the shallowest and deepens by double clicking")
- .widget_holder()
- }
-
- fn pivot_reference_point_widget(&self, disabled: bool) -> WidgetHolder {
- ReferencePointInput::new(self.tool_data.pivot.to_pivot_position())
- .on_update(|pivot_input: &ReferencePointInput| SelectToolMessage::SetPivot { position: pivot_input.value }.into())
- .disabled(disabled)
+ .tooltip(
+ "Selection Mode\n\
+ \n\
+ Shallow Select: clicks initially select the least-nested layers and double clicks drill deeper into the folder hierarchy.\n\
+ Deep Select: clicks directly select the most-nested layers in the folder hierarchy.",
+ )
.widget_holder()
}
@@ -178,7 +188,7 @@ impl SelectTool {
fn boolean_widgets(&self, selected_count: usize) -> impl Iterator
- + use<> {
let list = ::list();
- list.into_iter().map(|i| i.into_iter()).flatten().map(move |(operation, info)| {
+ list.iter().flat_map(|i| i.iter()).map(move |(operation, info)| {
let mut tooltip = info.label.to_string();
if let Some(doc) = info.docstring.as_deref() {
tooltip.push_str("\n\n");
@@ -203,9 +213,29 @@ impl LayoutHolder for SelectTool {
// Select mode (Deep/Shallow)
widgets.push(self.deep_selection_widget());
- // Pivot
+ // Pivot gizmo type (checkbox + dropdown for pivot/origin)
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
- widgets.push(self.pivot_reference_point_widget(self.tool_data.selected_layers_count == 0));
+ widgets.extend(pivot_gizmo_type_widget(self.tool_data.pivot_gizmo.state, PivotToolSource::Select));
+
+ if self.tool_data.pivot_gizmo.state.is_pivot_type() {
+ // Nine-position reference point widget
+ widgets.push(Separator::new(SeparatorType::Related).widget_holder());
+ widgets.push(pivot_reference_point_widget(
+ self.tool_data.selected_layers_count == 0 || !self.tool_data.pivot_gizmo.state.is_pivot(),
+ self.tool_data.pivot_gizmo.pivot.to_pivot_position(),
+ PivotToolSource::Select,
+ ));
+
+ // Pivot pin button
+ widgets.push(Separator::new(SeparatorType::Related).widget_holder());
+
+ let pin_active = self.tool_data.pivot_gizmo.pin_active();
+ let pin_enabled = self.tool_data.pivot_gizmo.pivot.old_pivot_position == ReferencePoint::None && !self.tool_data.pivot_gizmo.state.disabled;
+
+ if pin_active || pin_enabled {
+ widgets.push(pin_pivot_widget(pin_active, pin_enabled, PivotToolSource::Select));
+ }
+ }
// Align
let disabled = self.tool_data.selected_layers_count < 2;
@@ -242,16 +272,46 @@ impl LayoutHolder for SelectTool {
}
}
+#[message_handler_data]
impl<'a> MessageHandler> for SelectTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque, tool_data: &mut ToolActionHandlerData<'a>) {
- if let ToolMessage::Select(SelectToolMessage::SelectOptions(SelectOptionsUpdate::NestedSelectionBehavior(nested_selection_behavior))) = message {
- self.tool_data.nested_selection_behavior = nested_selection_behavior;
- responses.add(ToolMessage::UpdateHints);
+ let mut redraw_reference_pivot = false;
+
+ if let ToolMessage::Select(SelectToolMessage::SelectOptions(ref option_update)) = message {
+ match option_update {
+ SelectOptionsUpdate::NestedSelectionBehavior(nested_selection_behavior) => {
+ self.tool_data.nested_selection_behavior = *nested_selection_behavior;
+ responses.add(ToolMessage::UpdateHints);
+ }
+ SelectOptionsUpdate::PivotGizmoType(gizmo_type) => {
+ if !self.tool_data.pivot_gizmo.state.disabled {
+ self.tool_data.pivot_gizmo.state.gizmo_type = *gizmo_type;
+ responses.add(ToolMessage::UpdateHints);
+ let pivot_gizmo = self.tool_data.pivot_gizmo();
+ responses.add(TransformLayerMessage::SetPivotGizmo { pivot_gizmo });
+ responses.add(NodeGraphMessage::RunDocumentGraph);
+ redraw_reference_pivot = true;
+ }
+ }
+ SelectOptionsUpdate::TogglePivotGizmoType(state) => {
+ self.tool_data.pivot_gizmo.state.disabled = !state;
+ responses.add(ToolMessage::UpdateHints);
+ responses.add(NodeGraphMessage::RunDocumentGraph);
+ redraw_reference_pivot = true;
+ }
+
+ SelectOptionsUpdate::TogglePivotPinned => {
+ self.tool_data.pivot_gizmo.pivot.pinned = !self.tool_data.pivot_gizmo.pivot.pinned;
+ responses.add(ToolMessage::UpdateHints);
+ responses.add(NodeGraphMessage::RunDocumentGraph);
+ redraw_reference_pivot = true;
+ }
+ }
}
self.fsm_state.process_event(message, &mut self.tool_data, tool_data, &(), responses, false);
- if self.tool_data.pivot.should_refresh_pivot_position() || self.tool_data.selected_layers_changed {
+ if self.tool_data.pivot_gizmo.pivot.should_refresh_pivot_position() || self.tool_data.selected_layers_changed || redraw_reference_pivot {
// Send the layout containing the updated pivot position (a bit ugly to do it here not in the fsm but that doesn't have SelectTool)
self.send_layout(responses, LayoutTarget::ToolOptions);
self.tool_data.selected_layers_changed = false;
@@ -323,7 +383,8 @@ struct SelectToolData {
drag_current: ViewportPosition,
lasso_polygon: Vec,
selection_mode: Option,
- layers_dragging: Vec,
+ layers_dragging: Vec, // Unordered, often used as temporary buffer
+ ordered_layers: Vec, // Ordered list of layers
layer_selected_on_start: Option,
select_single_layer: Option,
axis_align: bool,
@@ -331,7 +392,9 @@ struct SelectToolData {
bounding_box_manager: Option,
snap_manager: SnapManager,
cursor: MouseCursorIcon,
- pivot: Pivot,
+ pivot_gizmo: PivotGizmo,
+ pivot_gizmo_start: Option,
+ pivot_gizmo_shift: Option,
compass_rose: CompassRose,
line_center: DVec2,
skew_edge: EdgeBool,
@@ -497,6 +560,24 @@ impl SelectToolData {
responses.add(NodeGraphMessage::SendGraph);
self.layers_dragging = original;
}
+
+ fn state_from_pivot_gizmo(&self, mouse: DVec2) -> Option {
+ match self.pivot_gizmo.state.gizmo_type {
+ PivotGizmoType::Pivot if self.pivot_gizmo.state.is_pivot() => self.pivot_gizmo.pivot.is_over(mouse).then_some(SelectToolFsmState::DraggingPivot),
+ _ => None,
+ }
+ }
+
+ fn pivot_gizmo(&self) -> PivotGizmo {
+ self.pivot_gizmo.clone()
+ }
+
+ fn sync_history(&mut self, document: &DocumentMessageHandler) {
+ let layers: Vec<_> = document.network_interface.selected_nodes().selected_visible_and_unlocked_layers(&document.network_interface).collect();
+ self.ordered_layers.retain(|layer| layers.contains(layer));
+ self.ordered_layers.extend(layers.iter().find(|&layer| !self.ordered_layers.contains(layer)));
+ self.pivot_gizmo.layer = self.ordered_layers.last().copied()
+ }
}
impl Fsm for SelectToolFsmState {
@@ -710,8 +791,63 @@ impl Fsm for SelectToolFsmState {
.flatten()
});
- // Update pivot
- tool_data.pivot.update_pivot(document, &mut overlay_context, Some((angle,)));
+ let mut active_origin = None;
+ let mut origin_angle = 0.;
+ if overlay_context.visibility_settings.origin() && !tool_data.pivot_gizmo.state.is_pivot_type() {
+ let get_angle = |layer: LayerNodeIdentifier| -> f64 {
+ let quad = Quad::from_box([DVec2::ZERO, DVec2::ONE]);
+ let bounds = document.metadata().transform_to_viewport_with_first_transform_node_if_group(layer, &document.network_interface) * quad;
+ (bounds.top_left() - bounds.top_right()).to_angle()
+ };
+ if tool_data.pivot_gizmo.state.gizmo_type == PivotGizmoType::Average {
+ let mut count = 0_usize;
+
+ let sum: f64 = document
+ .network_interface
+ .selected_nodes()
+ .selected_visible_and_unlocked_layers(&document.network_interface)
+ .map(get_angle)
+ .inspect(|_| count += 1)
+ .sum();
+ if count > 0 {
+ origin_angle = sum / count as f64;
+ }
+ } else if tool_data.pivot_gizmo.state.gizmo_type == PivotGizmoType::Active {
+ origin_angle = document
+ .network_interface
+ .selected_nodes()
+ .selected_visible_and_unlocked_layers(&document.network_interface)
+ .find(|&layer| Some(layer) == tool_data.pivot_gizmo.layer)
+ .iter()
+ .map(|&layer| get_angle(layer))
+ .sum();
+ }
+
+ for layer in document.network_interface.selected_nodes().selected_visible_and_unlocked_layers(&document.network_interface) {
+ let origin = graph_modification_utils::get_viewport_origin(layer, &document.network_interface);
+ if Some(layer) == tool_data.pivot_gizmo.layer {
+ active_origin = Some(origin);
+ continue;
+ }
+ overlay_context.dowel_pin(origin, origin_angle, None);
+ }
+ }
+ if let Some(origin) = active_origin {
+ overlay_context.dowel_pin(origin, origin_angle, Some(COLOR_OVERLAY_YELLOW));
+ }
+
+ let has_layers = document.network_interface.selected_nodes().has_selected_nodes();
+ let draw_pivot = tool_data.pivot_gizmo.state.is_pivot() && overlay_context.visibility_settings.pivot() && has_layers;
+ tool_data.pivot_gizmo.pivot.recalculate_pivot(document);
+ let pivot = draw_pivot.then_some(tool_data.pivot_gizmo.pivot.pivot).flatten();
+ if let Some(pivot) = pivot {
+ let offset = tool_data
+ .pivot_gizmo_start
+ .map(|offset| tool_data.pivot_gizmo.pivot_disconnected().then_some(tool_data.drag_current - offset).unwrap_or_default())
+ .unwrap_or_default();
+ let shift = tool_data.pivot_gizmo_shift.unwrap_or_default();
+ overlay_context.pivot(pivot + offset + shift, angle);
+ }
// Update compass rose
if overlay_context.visibility_settings.compass_rose() {
@@ -837,6 +973,15 @@ impl Fsm for SelectToolFsmState {
(SelectionShapeType::Lasso, _) => overlay_context.polygon(polygon, None, fill_color),
}
}
+
+ if let Self::Dragging { .. } = self {
+ let quad = Quad::from_box([tool_data.drag_start, tool_data.drag_current]);
+ let document_start = document.metadata().document_to_viewport.inverse().transform_point2(quad.top_left());
+ let document_current = document.metadata().document_to_viewport.inverse().transform_point2(quad.bottom_right());
+
+ overlay_context.translation_box(document_current - document_start, quad, None);
+ }
+
self
}
(_, SelectToolMessage::EditLayer) => {
@@ -868,7 +1013,8 @@ impl Fsm for SelectToolFsmState {
let intersection_list = document.click_list(input).collect::>();
let intersection = document.find_deepest(&intersection_list);
- let (resize, rotate, skew) = transforming_transform_cage(document, &mut tool_data.bounding_box_manager, input, responses, &mut tool_data.layers_dragging);
+ let position = tool_data.pivot_gizmo().position(document);
+ let (resize, rotate, skew) = transforming_transform_cage(document, &mut tool_data.bounding_box_manager, input, responses, &mut tool_data.layers_dragging, Some(position));
// If the user is dragging the bounding box bounds, go into ResizingBounds mode.
// If the user is dragging the rotate trigger, go into RotatingBounds mode.
@@ -883,20 +1029,17 @@ impl Fsm for SelectToolFsmState {
let angle = bounds.map_or(0., |quad| (quad.top_left() - quad.top_right()).to_angle());
let mouse_position = input.mouse.position;
let compass_rose_state = tool_data.compass_rose.compass_rose_state(mouse_position, angle);
- let is_over_pivot = tool_data.pivot.is_over(mouse_position);
let show_compass = bounds.is_some_and(|quad| quad.all_sides_at_least_width(COMPASS_ROSE_HOVER_RING_DIAMETER) && quad.contains(mouse_position));
let can_grab_compass_rose = compass_rose_state.can_grab() && (show_compass || bounds.is_none());
- let state = if is_over_pivot
- // Dragging the pivot
- {
+ let state = if let Some(state) = tool_data.state_from_pivot_gizmo(input.mouse.position) {
responses.add(DocumentMessage::StartTransaction);
// tool_data.snap_manager.start_snap(document, input, document.bounding_boxes(), true, true);
// tool_data.snap_manager.add_all_document_handles(document, input, &[], &[], &[]);
- SelectToolFsmState::DraggingPivot
+ state
}
// Dragging one (or two, forming a corner) of the transform cage bounding box edges
else if resize {
@@ -917,12 +1060,14 @@ impl Fsm for SelectToolFsmState {
}
tool_data.layers_dragging = selected;
-
tool_data.get_snap_candidates(document, input);
let (axis, using_compass) = {
let axis_state = compass_rose_state.axis_type().filter(|_| can_grab_compass_rose);
(axis_state.unwrap_or_default(), axis_state.is_some())
};
+
+ tool_data.pivot_gizmo_start = Some(tool_data.drag_current);
+
SelectToolFsmState::Dragging {
axis,
using_compass,
@@ -941,6 +1086,12 @@ impl Fsm for SelectToolFsmState {
let extend = input.keyboard.key(extend_selection);
if !extend && !input.keyboard.key(remove_from_selection) {
responses.add(DocumentMessage::DeselectAllLayers);
+
+ if !tool_data.pivot_gizmo.pivot.pinned {
+ let position = tool_data.pivot_gizmo.pivot.last_non_none_reference_point;
+ responses.add(SelectToolMessage::SetPivot { position });
+ }
+
tool_data.layers_dragging.clear();
}
@@ -955,6 +1106,9 @@ impl Fsm for SelectToolFsmState {
tool_data.get_snap_candidates(document, input);
responses.add(DocumentMessage::StartTransaction);
+
+ tool_data.pivot_gizmo_start = Some(tool_data.drag_current);
+
SelectToolFsmState::Dragging {
axis: Axis::None,
using_compass: false,
@@ -1098,7 +1252,10 @@ impl Fsm for SelectToolFsmState {
(SelectToolFsmState::DraggingPivot, SelectToolMessage::PointerMove(modifier_keys)) => {
let mouse_position = input.mouse.position;
let snapped_mouse_position = mouse_position;
- tool_data.pivot.set_viewport_position(snapped_mouse_position, document, responses);
+
+ tool_data.pivot_gizmo.pivot.set_viewport_position(snapped_mouse_position);
+
+ responses.add(NodeGraphMessage::RunDocumentGraph);
// Auto-panning
let messages = [
@@ -1143,7 +1300,7 @@ impl Fsm for SelectToolFsmState {
.map_or(MouseCursorIcon::Default, |bounds| bounds.get_cursor(input, true, dragging_bounds, Some(tool_data.skew_edge)));
// Dragging the pivot overrules the other operations
- if tool_data.pivot.is_over(input.mouse.position) {
+ if tool_data.state_from_pivot_gizmo(input.mouse.position).is_some() {
cursor = MouseCursorIcon::Move;
}
@@ -1283,20 +1440,32 @@ impl Fsm for SelectToolFsmState {
tool_data.snap_manager.cleanup(responses);
tool_data.select_single_layer = None;
+ if let Some(start) = tool_data.pivot_gizmo_start {
+ let offset = tool_data.pivot_gizmo.pivot_disconnected().then_some(tool_data.drag_current - start).unwrap_or_default();
+ if let Some(v) = tool_data.pivot_gizmo.pivot.pivot.as_mut() {
+ *v += offset;
+ }
+ }
+ tool_data.pivot_gizmo_start = None;
+
+ let pivot_gizmo = tool_data.pivot_gizmo();
+ responses.add(TransformLayerMessage::SetPivotGizmo { pivot_gizmo });
+
let selection = tool_data.nested_selection_behavior;
SelectToolFsmState::Ready { selection }
}
(
- SelectToolFsmState::ResizingBounds
- | SelectToolFsmState::SkewingBounds { .. }
- | SelectToolFsmState::RotatingBounds
- | SelectToolFsmState::Dragging { .. }
- | SelectToolFsmState::DraggingPivot,
+ SelectToolFsmState::ResizingBounds | SelectToolFsmState::SkewingBounds { .. } | SelectToolFsmState::RotatingBounds | SelectToolFsmState::DraggingPivot,
SelectToolMessage::DragStop { .. } | SelectToolMessage::Enter,
) => {
let drag_too_small = input.mouse.position.distance(tool_data.drag_start) < 10. * f64::EPSILON;
let response = if drag_too_small { DocumentMessage::AbortTransaction } else { DocumentMessage::EndTransaction };
+
+ let pivot_gizmo = tool_data.pivot_gizmo();
+ responses.add(TransformLayerMessage::SetPivotGizmo { pivot_gizmo });
+
responses.add(response);
+
tool_data.axis_align = false;
tool_data.snap_manager.cleanup(responses);
@@ -1432,8 +1601,48 @@ impl Fsm for SelectToolFsmState {
(_, SelectToolMessage::SetPivot { position }) => {
responses.add(DocumentMessage::StartTransaction);
+ tool_data.pivot_gizmo.pivot.last_non_none_reference_point = position;
+ tool_data.pivot_gizmo.pivot.pinned = false;
+
let pos: Option = position.into();
- tool_data.pivot.set_normalized_position(pos.unwrap(), document, responses);
+
+ tool_data.pivot_gizmo.pivot.set_normalized_position(pos.unwrap());
+
+ let pivot_gizmo = tool_data.pivot_gizmo();
+ responses.add(TransformLayerMessage::SetPivotGizmo { pivot_gizmo });
+
+ responses.add(NodeGraphMessage::RunDocumentGraph);
+
+ self
+ }
+ (_, SelectToolMessage::SyncHistory) => {
+ tool_data.sync_history(document);
+
+ self
+ }
+ (_, SelectToolMessage::ShiftSelectedNodes { offset }) => {
+ let offset = document.metadata().document_to_viewport.transform_vector2(offset);
+ if tool_data.pivot_gizmo.pivot_disconnected() {
+ if let Some(v) = tool_data.pivot_gizmo.pivot.pivot.as_mut() {
+ *v += offset;
+ }
+
+ let pivot_gizmo = tool_data.pivot_gizmo();
+ responses.add(TransformLayerMessage::SetPivotGizmo { pivot_gizmo });
+ }
+
+ self
+ }
+ (_, SelectToolMessage::PivotShift { offset, flush }) => {
+ if flush {
+ tool_data.pivot_gizmo.pivot.pivot.as_mut().map(|v| *v += tool_data.pivot_gizmo_shift.take().unwrap_or_default());
+ let pivot_gizmo = tool_data.pivot_gizmo();
+ responses.add(TransformLayerMessage::SetPivotGizmo { pivot_gizmo });
+ return self;
+ }
+ if tool_data.pivot_gizmo.pivot_disconnected() {
+ tool_data.pivot_gizmo_shift = offset;
+ }
self
}
@@ -1658,6 +1867,7 @@ fn drag_deepest_manipulation(responses: &mut VecDeque, selected: Vec MessageHandler> for SplineTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque, tool_data: &mut ToolActionHandlerData<'a>) {
let ToolMessage::Spline(SplineToolMessage::UpdateOptions(action)) = message else {
diff --git a/editor/src/messages/tool/tool_messages/text_tool.rs b/editor/src/messages/tool/tool_messages/text_tool.rs
index e56e53d477..52430f09ca 100644
--- a/editor/src/messages/tool/tool_messages/text_tool.rs
+++ b/editor/src/messages/tool/tool_messages/text_tool.rs
@@ -9,7 +9,6 @@ use crate::messages::portfolio::document::utility_types::network_interface::Inpu
use crate::messages::tool::common_functionality::auto_panning::AutoPanning;
use crate::messages::tool::common_functionality::color_selector::{ToolColorOptions, ToolColorType};
use crate::messages::tool::common_functionality::graph_modification_utils::{self, is_layer_fed_by_node_of_name};
-use crate::messages::tool::common_functionality::pivot::Pivot;
use crate::messages::tool::common_functionality::resize::Resize;
use crate::messages::tool::common_functionality::snapping::{self, SnapCandidatePoint, SnapData};
use crate::messages::tool::common_functionality::transformation_cage::*;
@@ -21,7 +20,7 @@ use graphene_std::renderer::Quad;
use graphene_std::text::{Font, FontCache, TypesettingConfig, lines_clipping, load_font};
use graphene_std::vector::style::Fill;
-#[derive(Default)]
+#[derive(Default, ExtractField)]
pub struct TextTool {
fsm_state: TextToolFsmState,
tool_data: TextToolData,
@@ -171,6 +170,7 @@ impl LayoutHolder for TextTool {
}
}
+#[message_handler_data]
impl<'a> MessageHandler> for TextTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque, tool_data: &mut ToolActionHandlerData<'a>) {
let ToolMessage::Text(TextToolMessage::UpdateOptions(action)) = message else {
@@ -283,7 +283,6 @@ struct TextToolData {
// Since the overlays must be drawn without knowledge of the inputs
cached_resize_bounds: [DVec2; 2],
bounding_box_manager: Option,
- pivot: Pivot,
snap_candidates: Vec,
// TODO: Handle multiple layers in the future
layer_dragging: Option,
@@ -526,7 +525,6 @@ impl Fsm for TextToolFsmState {
}
bounding_box_manager.render_overlays(&mut overlay_context, false);
- tool_data.pivot.update_pivot(document, &mut overlay_context, None);
}
} else {
tool_data.bounding_box_manager.take();
diff --git a/editor/src/messages/tool/transform_layer/transform_layer_message.rs b/editor/src/messages/tool/transform_layer/transform_layer_message.rs
index e68d2702c4..c819260e58 100644
--- a/editor/src/messages/tool/transform_layer/transform_layer_message.rs
+++ b/editor/src/messages/tool/transform_layer/transform_layer_message.rs
@@ -2,6 +2,7 @@ use crate::messages::input_mapper::utility_types::input_keyboard::Key;
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
use crate::messages::portfolio::document::utility_types::transformation::TransformType;
use crate::messages::prelude::*;
+use crate::messages::tool::common_functionality::pivot::PivotGizmo;
use glam::DVec2;
#[impl_message(Message, ToolMessage, TransformLayer)]
@@ -29,4 +30,5 @@ pub enum TransformLayerMessage {
TypeDecimalPoint,
TypeDigit { digit: u8 },
TypeNegate,
+ SetPivotGizmo { pivot_gizmo: PivotGizmo },
}
diff --git a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs
index e449bbd3b8..b9b9880e98 100644
--- a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs
+++ b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs
@@ -5,6 +5,7 @@ use crate::messages::portfolio::document::utility_types::document_metadata::Laye
use crate::messages::portfolio::document::utility_types::misc::PTZ;
use crate::messages::portfolio::document::utility_types::transformation::{Axis, OriginalTransforms, Selected, TransformOperation, TransformType, Typing};
use crate::messages::prelude::*;
+use crate::messages::tool::common_functionality::pivot::{PivotGizmo, PivotGizmoType};
use crate::messages::tool::common_functionality::shape_editor::ShapeState;
use crate::messages::tool::tool_messages::tool_prelude::Key;
use crate::messages::tool::utility_types::{ToolData, ToolType};
@@ -20,7 +21,7 @@ const TRANSFORM_GRS_OVERLAY_PROVIDER: OverlayProvider = |context| TransformLayer
const SLOW_KEY: Key = Key::Shift;
const INCREMENTS_KEY: Key = Key::Control;
-#[derive(Debug, Clone, Default)]
+#[derive(Debug, Clone, Default, ExtractField)]
pub struct TransformLayerMessageHandler {
pub transform_operation: TransformOperation,
@@ -34,8 +35,11 @@ pub struct TransformLayerMessageHandler {
start_mouse: ViewportPosition,
original_transforms: OriginalTransforms,
+ pivot_gizmo: PivotGizmo,
pivot: ViewportPosition,
+ path_bounds: Option<[DVec2; 2]>,
+
local_pivot: DocumentPosition,
local_mouse_start: DocumentPosition,
grab_target: DocumentPosition,
@@ -61,27 +65,64 @@ impl TransformLayerMessageHandler {
}
}
-fn calculate_pivot(selected_points: &Vec<&ManipulatorPointId>, vector_data: &VectorData, viewspace: DAffine2, get_location: impl Fn(&ManipulatorPointId) -> Option) -> Option<(DVec2, DVec2)> {
+fn calculate_pivot(
+ document: &DocumentMessageHandler,
+ selected_points: &Vec<&ManipulatorPointId>,
+ vector_data: &VectorData,
+ viewspace: DAffine2,
+ get_location: impl Fn(&ManipulatorPointId) -> Option,
+ gizmo: &mut PivotGizmo,
+) -> (Option<(DVec2, DVec2)>, Option<[DVec2; 2]>) {
+ let average_position = || {
+ let mut point_count = 0_usize;
+ selected_points.iter().filter_map(|p| get_location(p)).inspect(|_| point_count += 1).sum::() / point_count as f64
+ };
+ let bounds = selected_points.iter().filter_map(|p| get_location(p)).fold(None, |acc: Option<[DVec2; 2]>, point| {
+ if let Some([mut min, mut max]) = acc {
+ min.x = min.x.min(point.x);
+ min.y = min.y.min(point.y);
+ max.x = max.x.max(point.x);
+ max.y = max.y.max(point.y);
+ Some([min, max])
+ } else {
+ Some([point, point])
+ }
+ });
+ gizmo.pivot.recalculate_pivot_for_layer(document, bounds);
+ let position = || {
+ (if !gizmo.state.disabled {
+ match gizmo.state.gizmo_type {
+ PivotGizmoType::Average => None,
+ PivotGizmoType::Active => gizmo.point.and_then(|p| get_location(&p)),
+ PivotGizmoType::Pivot => gizmo.pivot.pivot,
+ }
+ } else {
+ None
+ })
+ .unwrap_or_else(average_position)
+ };
let [point] = selected_points.as_slice() else {
// Handle the case where there are multiple points
- let mut point_count = 0;
- let average_position = selected_points.iter().filter_map(|p| get_location(p)).inspect(|_| point_count += 1).sum::() / point_count as f64;
-
- return Some((average_position, average_position));
+ let position = position();
+ return (Some((position, position)), bounds);
};
match point {
ManipulatorPointId::PrimaryHandle(_) | ManipulatorPointId::EndHandle(_) => {
// Get the anchor position and transform it to the pivot
- let pivot_pos = point.get_anchor_position(vector_data).map(|anchor_position| viewspace.transform_point2(anchor_position))?;
- let target = viewspace.transform_point2(point.get_position(vector_data)?);
- Some((pivot_pos, target))
+ let (Some(pivot_position), Some(position)) = (
+ point.get_anchor_position(vector_data).map(|anchor_position| viewspace.transform_point2(anchor_position)),
+ point.get_position(vector_data),
+ ) else {
+ return (None, None);
+ };
+ let target = viewspace.transform_point2(position);
+ (Some((pivot_position, target)), None)
}
_ => {
// Calculate the average position of all selected points
- let mut point_count = 0;
- let average_position = selected_points.iter().filter_map(|p| get_location(p)).inspect(|_| point_count += 1).sum::() / point_count as f64;
- Some((average_position, average_position))
+ let position = position();
+ (Some((position, position)), bounds)
}
}
}
@@ -134,6 +175,26 @@ fn update_colinear_handles(selected_layers: &[LayerNodeIdentifier], document: &D
}
type TransformData<'a> = (&'a DocumentMessageHandler, &'a InputPreprocessorMessageHandler, &'a ToolData, &'a mut ShapeState);
+
+pub fn custom_data() -> MessageData {
+ MessageData::new(
+ String::from("TransformData<'a>"),
+ // TODO: When is resolved and released,
+ // TODO: use to get
+ // TODO: the line number instead of hardcoding it to the magic number on the following lines
+ // TODO: which points to the line of the `type TransformData<'a> = ...` definition above.
+ // TODO: Also, utilize the line number in the actual output, since it is currently unused.
+ vec![
+ (String::from("&'a DocumentMessageHandler"), 177),
+ (String::from("&'a InputPreprocessorMessageHandler"), 177),
+ (String::from("&'a ToolData"), 177),
+ (String::from("&'a mut ShapeState"), 177),
+ ],
+ file!(),
+ )
+}
+
+#[message_handler_data(CustomData)]
impl MessageHandler> for TransformLayerMessageHandler {
fn process_message(&mut self, message: TransformLayerMessage, responses: &mut VecDeque, (document, input, tool_data, shape_editor): TransformData) {
let using_path_tool = tool_data.active_tool_type == ToolType::Path;
@@ -177,18 +238,17 @@ impl MessageHandler> for TransformLayer
}
if !using_path_tool {
- *selected.pivot = selected.mean_average_of_pivots();
+ self.pivot_gizmo.recalculate_transform(document);
+ *selected.pivot = self.pivot_gizmo.position(document);
self.local_pivot = document.metadata().document_to_viewport.inverse().transform_point2(*selected.pivot);
- self.grab_target = document.metadata().document_to_viewport.inverse().transform_point2(selected.mean_average_of_pivots());
+ self.grab_target = self.local_pivot;
}
// Here vector data from all layers is not considered which can be a problem in pivot calculation
else if let Some(vector_data) = selected_layers.first().and_then(|&layer| document.network_interface.compute_modified_vector(layer)) {
*selected.original_transforms = OriginalTransforms::default();
let viewspace = document.metadata().transform_to_viewport(selected_layers[0]);
-
let selected_segments = shape_editor.selected_segments().collect::>();
-
let mut affected_points = shape_editor.selected_points().copied().collect::>();
for (segment_id, _, start, end) in vector_data.segment_bezier_iter() {
@@ -201,8 +261,16 @@ impl MessageHandler> for TransformLayer
let affected_point_refs = affected_points.iter().collect();
let get_location = |point: &&ManipulatorPointId| point.get_position(&vector_data).map(|position| viewspace.transform_point2(position));
- if let Some((new_pivot, grab_target)) = calculate_pivot(&affected_point_refs, &vector_data, viewspace, |point: &ManipulatorPointId| get_location(&point)) {
+ if let (Some((new_pivot, grab_target)), bounds) = calculate_pivot(
+ document,
+ &affected_point_refs,
+ &vector_data,
+ viewspace,
+ |point: &ManipulatorPointId| get_location(&point),
+ &mut self.pivot_gizmo,
+ ) {
*selected.pivot = new_pivot;
+ self.path_bounds = bounds;
self.local_pivot = document_to_viewport.inverse().transform_point2(*selected.pivot);
self.grab_target = document_to_viewport.inverse().transform_point2(grab_target);
@@ -228,116 +296,93 @@ impl MessageHandler> for TransformLayer
return;
}
- for layer in document.metadata().all_layers() {
- if !document.network_interface.is_artboard(&layer.to_node(), &[]) {
- continue;
- };
+ let viewport_box = input.viewport_bounds.size();
+ let axis_constraint = self.transform_operation.axis_constraint();
- let viewport_box = input.viewport_bounds.size();
- let axis_constraint = self.transform_operation.axis_constraint();
+ let format_rounded = |value: f64, precision: usize| {
+ if self.typing.digits.is_empty() || !self.transform_operation.can_begin_typing() {
+ format!("{:.*}", precision, value).trim_end_matches('0').trim_end_matches('.').to_string()
+ } else {
+ self.typing.string.clone()
+ }
+ };
- let format_rounded = |value: f64, precision: usize| {
- if self.typing.digits.is_empty() || !self.transform_operation.can_begin_typing() {
- format!("{:.*}", precision, value).trim_end_matches('0').trim_end_matches('.').to_string()
+ // TODO: Ensure removing this and adding this doesn't change the position of layers under PTZ ops
+ // responses.add(TransformLayerMessage::PointerMove {
+ // slow_key: SLOW_KEY,
+ // increments_key: INCREMENTS_KEY,
+ // });
+
+ match self.transform_operation {
+ TransformOperation::None => (),
+ TransformOperation::Grabbing(translation) => {
+ let translation = translation.to_dvec(self.initial_transform, self.increments);
+ let viewport_translate = document_to_viewport.transform_vector2(translation);
+ let pivot = document_to_viewport.transform_point2(self.grab_target);
+ let quad = Quad::from_box([pivot, pivot + viewport_translate]);
+
+ responses.add(SelectToolMessage::PivotShift {
+ offset: Some(viewport_translate),
+ flush: false,
+ });
+
+ let typed_string = (!self.typing.digits.is_empty() && self.transform_operation.can_begin_typing()).then(|| self.typing.string.clone());
+ overlay_context.translation_box(translation, quad, typed_string);
+ }
+ TransformOperation::Scaling(scale) => {
+ let scale = scale.to_f64(self.increments);
+ let text = format!("{}x", format_rounded(scale, 3));
+ let pivot = document_to_viewport.transform_point2(self.local_pivot);
+ let start_mouse = document_to_viewport.transform_point2(self.local_mouse_start);
+ let local_edge = start_mouse - pivot;
+ let local_edge = project_edge_to_quad(local_edge, &self.layer_bounding_box, self.local, axis_constraint);
+ let boundary_point = pivot + local_edge * scale.min(1.);
+ let end_point = pivot + local_edge * scale.max(1.);
+
+ if scale > 0. {
+ overlay_context.dashed_line(pivot, boundary_point, None, None, Some(2.), Some(2.), Some(0.5));
+ }
+ overlay_context.line(boundary_point, end_point, None, None);
+
+ let transform = DAffine2::from_translation(boundary_point.midpoint(pivot) + local_edge.perp().normalize_or(DVec2::X) * local_edge.element_product().signum() * 24.);
+ overlay_context.text(&text, COLOR_OVERLAY_BLUE, None, transform, 16., [Pivot::Middle, Pivot::Middle]);
+ }
+ TransformOperation::Rotating(rotation) => {
+ let angle = rotation.to_f64(self.increments);
+ let pivot = document_to_viewport.transform_point2(self.local_pivot);
+ let start_mouse = document_to_viewport.transform_point2(self.local_mouse_start);
+ let offset_angle = if self.grs_pen_handle {
+ self.handle - self.last_point
+ } else if using_path_tool {
+ start_mouse - pivot
} else {
- self.typing.string.clone()
- }
- };
-
- // TODO: Ensure removing this and adding this doesn't change the position of layers under PTZ ops
- // responses.add(TransformLayerMessage::PointerMove {
- // slow_key: SLOW_KEY,
- // increments_key: INCREMENTS_KEY,
- // });
-
- match self.transform_operation {
- TransformOperation::None => (),
- TransformOperation::Grabbing(translation) => {
- let translation = translation.to_dvec(self.initial_transform, self.increments);
- let viewport_translate = document_to_viewport.transform_vector2(translation);
- let pivot = document_to_viewport.transform_point2(self.grab_target);
- let quad = Quad::from_box([pivot, pivot + viewport_translate]).0;
- let e1 = (self.layer_bounding_box.0[1] - self.layer_bounding_box.0[0]).normalize_or(DVec2::X);
-
- if matches!(axis_constraint, Axis::Both | Axis::X) && translation.x != 0. {
- let end = if self.local { (quad[1] - quad[0]).rotate(e1) + quad[0] } else { quad[1] };
- overlay_context.dashed_line(quad[0], end, None, None, Some(2.), Some(2.), Some(0.5));
-
- let x_transform = DAffine2::from_translation((quad[0] + end) / 2.);
- overlay_context.text(&format_rounded(translation.x, 3), COLOR_OVERLAY_BLUE, None, x_transform, 4., [Pivot::Middle, Pivot::End]);
- }
-
- if matches!(axis_constraint, Axis::Both | Axis::Y) && translation.y != 0. {
- let end = if self.local { (quad[3] - quad[0]).rotate(e1) + quad[0] } else { quad[3] };
- overlay_context.dashed_line(quad[0], end, None, None, Some(2.), Some(2.), Some(0.5));
- let x_parameter = viewport_translate.x.clamp(-1., 1.);
- let y_transform = DAffine2::from_translation((quad[0] + end) / 2. + x_parameter * DVec2::X * 0.);
- let pivot_selection = if x_parameter >= -1e-3 { Pivot::Start } else { Pivot::End };
- if axis_constraint != Axis::Both || self.typing.digits.is_empty() || !self.transform_operation.can_begin_typing() {
- overlay_context.text(&format_rounded(translation.y, 2), COLOR_OVERLAY_BLUE, None, y_transform, 3., [pivot_selection, Pivot::Middle]);
- }
- }
-
- if matches!(axis_constraint, Axis::Both) && translation.x != 0. && translation.y != 0. {
- overlay_context.line(quad[1], quad[2], None, None);
- overlay_context.line(quad[3], quad[2], None, None);
- }
- }
- TransformOperation::Scaling(scale) => {
- let scale = scale.to_f64(self.increments);
- let text = format!("{}x", format_rounded(scale, 3));
- let pivot = document_to_viewport.transform_point2(self.local_pivot);
- let start_mouse = document_to_viewport.transform_point2(self.local_mouse_start);
- let local_edge = start_mouse - pivot;
- let local_edge = project_edge_to_quad(local_edge, &self.layer_bounding_box, self.local, axis_constraint);
- let boundary_point = pivot + local_edge * scale.min(1.);
- let end_point = pivot + local_edge * scale.max(1.);
-
- if scale > 0. {
- overlay_context.dashed_line(pivot, boundary_point, None, None, Some(2.), Some(2.), Some(0.5));
- }
- overlay_context.line(boundary_point, end_point, None, None);
-
- let transform = DAffine2::from_translation(boundary_point.midpoint(pivot) + local_edge.perp().normalize_or(DVec2::X) * local_edge.element_product().signum() * 24.);
- overlay_context.text(&text, COLOR_OVERLAY_BLUE, None, transform, 16., [Pivot::Middle, Pivot::Middle]);
- }
- TransformOperation::Rotating(rotation) => {
- let angle = rotation.to_f64(self.increments);
- let pivot = document_to_viewport.transform_point2(self.local_pivot);
- let start_mouse = document_to_viewport.transform_point2(self.local_mouse_start);
- let offset_angle = if self.grs_pen_handle {
- self.handle - self.last_point
- } else if using_path_tool {
- start_mouse - pivot
- } else {
- self.layer_bounding_box.top_right() - self.layer_bounding_box.top_right()
- };
- let tilt_offset = document.document_ptz.unmodified_tilt();
- let offset_angle = offset_angle.to_angle() + tilt_offset;
- let width = viewport_box.max_element();
- let radius = start_mouse.distance(pivot);
- let arc_radius = ANGLE_MEASURE_RADIUS_FACTOR * width;
- let radius = radius.clamp(ARC_MEASURE_RADIUS_FACTOR_RANGE.0 * width, ARC_MEASURE_RADIUS_FACTOR_RANGE.1 * width);
- let angle_in_degrees = angle.to_degrees();
- let display_angle = if angle_in_degrees.is_sign_positive() {
- angle_in_degrees - (angle_in_degrees / 360.).floor() * 360.
- } else if angle_in_degrees.is_sign_negative() {
- angle_in_degrees - ((angle_in_degrees / 360.).floor() + 1.) * 360.
- } else {
- angle_in_degrees
- };
- let text = format!("{}°", format_rounded(display_angle, 2));
- let text_texture_width = overlay_context.get_width(&text) / 2.;
- let text_texture_height = 12.;
- let text_angle_on_unit_circle = DVec2::from_angle((angle % TAU) / 2. + offset_angle);
- let text_texture_position = DVec2::new(
- (arc_radius + 4. + text_texture_width) * text_angle_on_unit_circle.x,
- (arc_radius + text_texture_height) * text_angle_on_unit_circle.y,
- );
- let transform = DAffine2::from_translation(text_texture_position + pivot);
- overlay_context.draw_angle(pivot, radius, arc_radius, offset_angle, angle);
- overlay_context.text(&text, COLOR_OVERLAY_BLUE, None, transform, 16., [Pivot::Middle, Pivot::Middle]);
- }
+ self.layer_bounding_box.top_right() - self.layer_bounding_box.top_right()
+ };
+ let tilt_offset = document.document_ptz.unmodified_tilt();
+ let offset_angle = offset_angle.to_angle() + tilt_offset;
+ let width = viewport_box.max_element();
+ let radius = start_mouse.distance(pivot);
+ let arc_radius = ANGLE_MEASURE_RADIUS_FACTOR * width;
+ let radius = radius.clamp(ARC_MEASURE_RADIUS_FACTOR_RANGE.0 * width, ARC_MEASURE_RADIUS_FACTOR_RANGE.1 * width);
+ let angle_in_degrees = angle.to_degrees();
+ let display_angle = if angle_in_degrees.is_sign_positive() {
+ angle_in_degrees - (angle_in_degrees / 360.).floor() * 360.
+ } else if angle_in_degrees.is_sign_negative() {
+ angle_in_degrees - ((angle_in_degrees / 360.).floor() + 1.) * 360.
+ } else {
+ angle_in_degrees
+ };
+ let text = format!("{}°", format_rounded(display_angle, 2));
+ let text_texture_width = overlay_context.get_width(&text) / 2.;
+ let text_texture_height = 12.;
+ let text_angle_on_unit_circle = DVec2::from_angle((angle % TAU) / 2. + offset_angle);
+ let text_texture_position = DVec2::new(
+ (arc_radius + 4. + text_texture_width) * text_angle_on_unit_circle.x,
+ (arc_radius + text_texture_height) * text_angle_on_unit_circle.y,
+ );
+ let transform = DAffine2::from_translation(text_texture_position + pivot);
+ overlay_context.draw_angle(pivot, radius, arc_radius, offset_angle, angle);
+ overlay_context.text(&text, COLOR_OVERLAY_BLUE, None, transform, 16., [Pivot::Middle, Pivot::Middle]);
}
}
}
@@ -364,6 +409,8 @@ impl MessageHandler> for TransformLayer
responses.add(NodeGraphMessage::RunDocumentGraph);
}
+ responses.add(SelectToolMessage::PivotShift { offset: None, flush: true });
+
if final_transform {
responses.add(OverlaysMessage::RemoveProvider(TRANSFORM_GRS_OVERLAY_PROVIDER));
}
@@ -487,6 +534,7 @@ impl MessageHandler> for TransformLayer
responses.add(ToolMessage::UpdateHints);
}
+ responses.add(SelectToolMessage::PivotShift { offset: None, flush: false });
responses.add(OverlaysMessage::RemoveProvider(TRANSFORM_GRS_OVERLAY_PROVIDER));
}
TransformLayerMessage::ConstrainX => {
@@ -694,6 +742,9 @@ impl MessageHandler> for TransformLayer
self.initial_transform,
)
}
+ TransformLayerMessage::SetPivotGizmo { pivot_gizmo } => {
+ self.pivot_gizmo = pivot_gizmo;
+ }
}
}
diff --git a/editor/src/messages/tool/utility_types.rs b/editor/src/messages/tool/utility_types.rs
index fbbec768e4..fc06385f43 100644
--- a/editor/src/messages/tool/utility_types.rs
+++ b/editor/src/messages/tool/utility_types.rs
@@ -18,6 +18,7 @@ use graphene_std::text::FontCache;
use std::borrow::Cow;
use std::fmt::{self, Debug};
+#[derive(ExtractField)]
pub struct ToolActionHandlerData<'a> {
pub document: &'a mut DocumentMessageHandler,
pub document_id: DocumentId,
diff --git a/editor/src/messages/workspace/workspace_message_handler.rs b/editor/src/messages/workspace/workspace_message_handler.rs
index 397e7cf00b..47c81aab0e 100644
--- a/editor/src/messages/workspace/workspace_message_handler.rs
+++ b/editor/src/messages/workspace/workspace_message_handler.rs
@@ -1,10 +1,11 @@
use crate::messages::prelude::*;
-#[derive(Debug, Clone, Default)]
+#[derive(Debug, Clone, Default, ExtractField)]
pub struct WorkspaceMessageHandler {
node_graph_visible: bool,
}
+#[message_handler_data]
impl MessageHandler for WorkspaceMessageHandler {
fn process_message(&mut self, message: WorkspaceMessage, _responses: &mut VecDeque, _data: ()) {
match message {
diff --git a/editor/src/node_graph_executor.rs b/editor/src/node_graph_executor.rs
index dbb87c07f0..ba2f52d7b4 100644
--- a/editor/src/node_graph_executor.rs
+++ b/editor/src/node_graph_executor.rs
@@ -413,6 +413,7 @@ mod test {
use super::*;
use crate::messages::portfolio::document::utility_types::network_interface::NodeNetworkInterface;
use crate::test_utils::test_prelude::{self, NodeGraphLayer};
+ use graph_craft::ProtoNodeIdentifier;
use graph_craft::document::NodeNetwork;
use graphene_std::Context;
use graphene_std::NodeInputDecleration;
@@ -422,7 +423,7 @@ mod test {
/// Stores all of the monitor nodes that have been attached to a graph
#[derive(Default)]
pub struct Instrumented {
- protonodes_by_name: HashMap>>>,
+ protonodes_by_name: HashMap>>>,
protonodes_by_path: HashMap, Vec>>,
}
@@ -449,7 +450,7 @@ mod test {
}
if let DocumentNodeImplementation::ProtoNode(identifier) = &mut node.implementation {
path.push(*id);
- self.protonodes_by_name.entry(identifier.name.to_string()).or_default().push(monitor_node_ids.clone());
+ self.protonodes_by_name.entry(identifier.clone()).or_default().push(monitor_node_ids.clone());
self.protonodes_by_path.insert(path.clone(), monitor_node_ids);
path.pop();
}
@@ -457,7 +458,7 @@ mod test {
for (input, monitor_id) in monitor_nodes {
let monitor_node = DocumentNode {
inputs: vec![input],
- implementation: DocumentNodeImplementation::proto("graphene_core::memo::MonitorNode"),
+ implementation: DocumentNodeImplementation::ProtoNode(graphene_std::memo::monitor::IDENTIFIER),
manual_composition: Some(graph_craft::generic!(T)),
skip_deduplication: true,
..Default::default()
@@ -495,7 +496,7 @@ mod test {
Input::Result: Send + Sync + Clone + 'static,
{
self.protonodes_by_name
- .get(Input::identifier())
+ .get(&Input::identifier())
.map_or([].as_slice(), |x| x.as_slice())
.iter()
.filter_map(|inputs| inputs.get(Input::INDEX))
diff --git a/editor/src/node_graph_executor/runtime.rs b/editor/src/node_graph_executor/runtime.rs
index a93f73546c..227999143c 100644
--- a/editor/src/node_graph_executor/runtime.rs
+++ b/editor/src/node_graph_executor/runtime.rs
@@ -1,12 +1,12 @@
use super::*;
use crate::messages::frontend::utility_types::{ExportBounds, FileType};
use glam::{DAffine2, DVec2};
-use graph_craft::concrete;
use graph_craft::document::value::TaggedValue;
use graph_craft::document::{NodeId, NodeNetwork};
use graph_craft::graphene_compiler::Compiler;
use graph_craft::proto::GraphErrors;
use graph_craft::wasm_application_io::EditorPreferences;
+use graph_craft::{ProtoNodeIdentifier, concrete};
use graphene_std::Context;
use graphene_std::application_io::{NodeGraphUpdateMessage, NodeGraphUpdateSender, RenderConfig};
use graphene_std::instances::Instance;
@@ -46,7 +46,7 @@ pub struct NodeRuntime {
inspect_state: Option,
/// Mapping of the fully-qualified node paths to their preprocessor substitutions.
- substitutions: HashMap,
+ substitutions: HashMap,
// TODO: Remove, it doesn't need to be persisted anymore
/// The current renders of the thumbnails for layer nodes.
@@ -435,7 +435,7 @@ impl InspectState {
let monitor_node = DocumentNode {
inputs: vec![NodeInput::node(inspect_node, 0)], // Connect to the primary output of the inspect node
- implementation: DocumentNodeImplementation::proto("graphene_core::memo::MonitorNode"),
+ implementation: DocumentNodeImplementation::ProtoNode(graphene_std::memo::monitor::IDENTIFIER),
manual_composition: Some(graph_craft::generic!(T)),
skip_deduplication: true,
..Default::default()
diff --git a/editor/src/utility_traits.rs b/editor/src/utility_traits.rs
index 711a8cc34b..850d730b13 100644
--- a/editor/src/utility_traits.rs
+++ b/editor/src/utility_traits.rs
@@ -45,3 +45,19 @@ pub trait TransitiveChild: Into + Into {
pub trait Hint {
fn hints(&self) -> HashMap;
}
+
+pub trait HierarchicalTree {
+ fn build_message_tree() -> DebugMessageTree;
+
+ fn message_handler_data_str() -> MessageData {
+ MessageData::new(String::new(), Vec::new(), "")
+ }
+
+ fn message_handler_str() -> MessageData {
+ MessageData::new(String::new(), Vec::new(), "")
+ }
+
+ fn path() -> &'static str {
+ ""
+ }
+}
diff --git a/editor/src/utility_types.rs b/editor/src/utility_types.rs
new file mode 100644
index 0000000000..6b5dc6de6b
--- /dev/null
+++ b/editor/src/utility_types.rs
@@ -0,0 +1,99 @@
+#[derive(Debug)]
+pub struct MessageData {
+ name: String,
+ fields: Vec<(String, usize)>,
+ path: &'static str,
+}
+
+impl MessageData {
+ pub fn new(name: String, fields: Vec<(String, usize)>, path: &'static str) -> MessageData {
+ MessageData { name, fields, path }
+ }
+
+ pub fn name(&self) -> &str {
+ &self.name
+ }
+
+ pub fn fields(&self) -> &Vec<(String, usize)> {
+ &self.fields
+ }
+
+ pub fn path(&self) -> &'static str {
+ self.path
+ }
+}
+
+#[derive(Debug)]
+pub struct DebugMessageTree {
+ name: String,
+ variants: Option