mirror of
https://gitlab.freedesktop.org/dabrain34/GstPipelineStudio.git
synced 2024-05-13 05:42:42 +00:00
Compare commits
3 commits
4cdc01c16b
...
b2fe8f5005
Author | SHA1 | Date | |
---|---|---|---|
b2fe8f5005 | |||
44d64ccdc4 | |||
ee29b07296 |
331
Cargo.lock
generated
331
Cargo.lock
generated
|
@ -17,6 +17,21 @@ version = "1.0.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "android-tzdata"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
|
||||
|
||||
[[package]]
|
||||
name = "android_system_properties"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.12.1"
|
||||
|
@ -32,6 +47,19 @@ version = "1.0.44"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61604a8f862e1d5c3229fdd78f8b02c68dcf73a4c4b05fd636d12240aaa242c1"
|
||||
|
||||
[[package]]
|
||||
name = "async-channel"
|
||||
version = "2.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ca33f4bc4ed1babef42cad36cc1f51fa88be00420404e5b1e80ab1b18f7678c"
|
||||
dependencies = [
|
||||
"concurrent-queue",
|
||||
"event-listener",
|
||||
"event-listener-strategy",
|
||||
"futures-core",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atomic_refcell"
|
||||
version = "0.1.8"
|
||||
|
@ -98,6 +126,12 @@ version = "2.4.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.4.3"
|
||||
|
@ -131,9 +165,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.72"
|
||||
version = "1.0.83"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee"
|
||||
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-expr"
|
||||
|
@ -152,15 +189,16 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.19"
|
||||
version = "0.4.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
|
||||
checksum = "9f13690e35a5e4ace198e7beea2895d29f3a9cc55015fcebe6336bd2010af9eb"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"num-integer",
|
||||
"android-tzdata",
|
||||
"iana-time-zone",
|
||||
"js-sys",
|
||||
"num-traits",
|
||||
"time",
|
||||
"winapi",
|
||||
"wasm-bindgen",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -178,6 +216,27 @@ dependencies = [
|
|||
"vec_map",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "concurrent-queue"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d16048cd947b08fa32c24458a22f5dc5e835264f689f4f5653210c69fd107363"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345"
|
||||
|
||||
[[package]]
|
||||
name = "dtoa"
|
||||
version = "0.4.8"
|
||||
|
@ -190,6 +249,12 @@ version = "1.9.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||
|
||||
[[package]]
|
||||
name = "error-chain"
|
||||
version = "0.10.0"
|
||||
|
@ -199,6 +264,27 @@ dependencies = [
|
|||
"backtrace",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "event-listener"
|
||||
version = "4.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67b215c49b2b248c855fb73579eb1f4f26c38ffdc12973e20e07b91d78d5646e"
|
||||
dependencies = [
|
||||
"concurrent-queue",
|
||||
"parking",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "event-listener-strategy"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3"
|
||||
dependencies = [
|
||||
"event-listener",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "failure"
|
||||
version = "0.1.8"
|
||||
|
@ -557,10 +643,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "gst-plugin-gtk4"
|
||||
version = "0.11.0"
|
||||
version = "0.11.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3ee0132150ee059c35642b51c5d663eadb9fa4d21f83a56dd584b03c1c45ffd"
|
||||
checksum = "551340110f16646449f27453598c22d7ab6b59960380175be097056dc00b2b7d"
|
||||
dependencies = [
|
||||
"async-channel",
|
||||
"gdk4-win32",
|
||||
"gst-plugin-version-helper",
|
||||
"gstreamer",
|
||||
|
@ -573,18 +660,19 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "gst-plugin-version-helper"
|
||||
version = "0.7.3"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a6a4dd1cb931cc6b49af354a68f21b3aee46b5b07370215d942f3a71542123f"
|
||||
checksum = "334c37a15ca23861ad8159c8ff6e20f011aa2000defc5c9159096a28842f811b"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"toml_edit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gstreamer"
|
||||
version = "0.21.0"
|
||||
version = "0.21.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8cdb86791dc39a5443f7d08cf3e7ae9c88a94991aba620d177cb5804838201f"
|
||||
checksum = "de95703f4c8e79f4f4e42279cf1ab0e5a46b7ece4a9dfcd16424164af7be9055"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"futures-channel",
|
||||
|
@ -599,6 +687,7 @@ dependencies = [
|
|||
"num-rational",
|
||||
"option-operations",
|
||||
"paste",
|
||||
"pin-project-lite",
|
||||
"pretty-hex",
|
||||
"smallvec",
|
||||
"thiserror",
|
||||
|
@ -662,9 +751,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "gstreamer-sys"
|
||||
version = "0.21.0"
|
||||
version = "0.21.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a70e3a99118bcd1221f8a62d7a905bae5e5cc2cda678bb46bf3cd36e0f899d33"
|
||||
checksum = "564cda782b3e6eed1b81cb4798a06794db56440fb05b422505be689f34ce3bc4"
|
||||
dependencies = [
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
|
@ -703,9 +792,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "gtk4"
|
||||
version = "0.7.2"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3b095b26f2a2df70be1805d3590eeb9d7a05ecb5be9649b82defc72dc56228c"
|
||||
checksum = "5aeb51aa3e9728575a053e1f43543cd9992ac2477e1b186ad824fd4adfb70842"
|
||||
dependencies = [
|
||||
"cairo-rs",
|
||||
"field-offset",
|
||||
|
@ -755,6 +844,12 @@ dependencies = [
|
|||
"system-deps",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.3.3"
|
||||
|
@ -779,6 +874,29 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.59"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6a67363e2aa4443928ce15e57ebae94fd8949958fd1223c4cfc0cd473ad7539"
|
||||
dependencies = [
|
||||
"android_system_properties",
|
||||
"core-foundation-sys",
|
||||
"iana-time-zone-haiku",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"windows-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone-haiku"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.1.5"
|
||||
|
@ -791,10 +909,20 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.11.0"
|
||||
name = "indexmap"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57"
|
||||
checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
@ -811,6 +939,15 @@ version = "1.0.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.58"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3fac17f7123a73ca62df411b1bf727ccc805daa070338fda671c86dac1bdc27"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
|
@ -963,6 +1100,12 @@ dependencies = [
|
|||
"system-deps",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae"
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.6"
|
||||
|
@ -986,9 +1129,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.7"
|
||||
version = "0.2.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443"
|
||||
checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
|
@ -1004,9 +1147,9 @@ checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe"
|
|||
|
||||
[[package]]
|
||||
name = "pretty-hex"
|
||||
version = "0.3.0"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c6fa0831dd7cc608c38a5e323422a0077678fa5744aa2be4ad91c4ece8eec8d5"
|
||||
checksum = "bbc83ee4a840062f368f9096d80077a9841ec117e17e7f700df81958f1451254"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-crate"
|
||||
|
@ -1349,17 +1492,6 @@ dependencies = [
|
|||
"syn 1.0.80",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"wasi",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "1.5.1"
|
||||
|
@ -1393,6 +1525,23 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1"
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.20.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"toml_datetime",
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ucd-trie"
|
||||
version = "0.1.3"
|
||||
|
@ -1468,10 +1617,58 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.10.0+wasi-snapshot-preview1"
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.81"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
|
||||
checksum = "7c53b543413a17a202f4be280a7e5c62a1c69345f5de525ee64f8cfdbc954994"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.81"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5491a68ab4500fa6b4d726bd67408630c3dbe9c4fe7bda16d5c82a1fd8c7340a"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"lazy_static",
|
||||
"log 0.4.14",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.80",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.81"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c441e177922bc58f1e12c022624b6216378e5febc2f0533e41ba443d505b80aa"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.81"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d94ac45fcf608c1f45ef53e748d35660f168490c10b23704c7779ab8f5c3048"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.80",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.81"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a89911bd99e5f3659ec4acf9c4d93b0a90fe4a2a11f15328472058edc5261be"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
|
@ -1505,19 +1702,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.48.0"
|
||||
name = "windows-core"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.48.5"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
|
||||
checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
|
@ -1530,45 +1736,54 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.48.5"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
||||
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.48.5"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.48.5"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
||||
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.48.5"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
||||
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.48.5"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
||||
checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.48.5"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
||||
checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.48.5"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
||||
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.5.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7cf47b659b318dccbd69cc4797a39ae128f533dce7902a1096044d1967b9c16"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xml-rs"
|
||||
|
|
|
@ -7,9 +7,9 @@ rust-version = "1.70.0"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
gtk = { version = "0.7.2", package = "gtk4" }
|
||||
gst = { package = "gstreamer", version = "0.21.0" }
|
||||
gst-plugin-gtk4 = { version = "0.11.0", optional=true }
|
||||
gtk = { version = "0.7.3", package = "gtk4" }
|
||||
gst = { package = "gstreamer", version = "0.21.3" }
|
||||
gst-plugin-gtk4 = { version = "0.11.3", optional=true }
|
||||
anyhow = "1"
|
||||
log = "0.4.11"
|
||||
once_cell = "1.7.2"
|
||||
|
|
|
@ -26,10 +26,11 @@ use std::fmt::Write as _;
|
|||
use std::ops;
|
||||
use std::rc::{Rc, Weak};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum PipelineState {
|
||||
Playing,
|
||||
Paused,
|
||||
#[default]
|
||||
Stopped,
|
||||
Error,
|
||||
}
|
||||
|
@ -40,7 +41,7 @@ impl fmt::Display for PipelineState {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct Player(Rc<PlayerInner>);
|
||||
|
||||
// Deref into the contained struct to make usage a bit more ergonomic
|
||||
|
@ -83,7 +84,7 @@ fn gst_log_handler(
|
|||
GPS_GST_LOG!("{}", log_message);
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Default)]
|
||||
pub struct PlayerInner {
|
||||
app: RefCell<Option<GPSApp>>,
|
||||
pipeline: RefCell<Option<gst::Pipeline>>,
|
||||
|
|
|
@ -19,13 +19,14 @@ use gtk::{gio, glib, graphene};
|
|||
use std::cell::{Cell, Ref, RefCell};
|
||||
use std::path::Path;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Default)]
|
||||
enum TabState {
|
||||
#[default]
|
||||
Undefined = 0,
|
||||
Modified,
|
||||
Saved,
|
||||
}
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct GraphTab {
|
||||
graphview: RefCell<GM::GraphView>,
|
||||
player: RefCell<GPS::Player>,
|
||||
|
@ -173,7 +174,7 @@ pub fn setup_graphbook(app: &GPSApp) {
|
|||
graphbook.connect_switch_page(move |_book, widget, page| {
|
||||
let graphview = widget
|
||||
.first_child()
|
||||
.expect("Unable to get the child from the graphbook, ie the graphview");
|
||||
.expect("Unable to get the child from the graphbook, ie the scrolledWindow");
|
||||
if let Ok(graphview) = graphview.dynamic_cast::<GM::GraphView>() {
|
||||
let app = upgrade_weak!(app_weak);
|
||||
GPS_TRACE!("graphview.id() {} graphbook page {}", graphview.id(), page);
|
||||
|
@ -191,8 +192,11 @@ pub fn create_graphtab(app: &GPSApp, id: u32, name: Option<&str>) {
|
|||
.builder
|
||||
.object("graphbook")
|
||||
.expect("Couldn't get graphbook");
|
||||
let drawing_area_window: gtk::Viewport = gtk::Viewport::builder().build();
|
||||
drawing_area_window.set_child(Some(&*graphtab(app, id).graphview()));
|
||||
|
||||
let scrollwindow = gtk::ScrolledWindow::builder()
|
||||
.name("graphview_scroll")
|
||||
.child(&*graphtab(app, id).graphview())
|
||||
.build();
|
||||
|
||||
let tab_box = gtk::Box::new(gtk::Orientation::Horizontal, 0);
|
||||
let label = gt.widget_label();
|
||||
|
@ -209,8 +213,8 @@ pub fn create_graphtab(app: &GPSApp, id: u32, name: Option<&str>) {
|
|||
graphbook.remove_page(Some(current_graphtab(&app).id()));
|
||||
}));
|
||||
tab_box.append(&close_button);
|
||||
graphbook.append_page(&drawing_area_window, Some(&tab_box));
|
||||
graphbook.set_tab_reorderable(&drawing_area_window, true);
|
||||
graphbook.append_page(&scrollwindow, Some(&tab_box));
|
||||
graphbook.set_tab_reorderable(&scrollwindow, true);
|
||||
let app_weak = app.downgrade();
|
||||
gt.graphview().connect_local(
|
||||
"graph-updated",
|
||||
|
|
|
@ -25,7 +25,7 @@ use once_cell::sync::Lazy;
|
|||
use std::io::Cursor;
|
||||
|
||||
use gtk::{
|
||||
gdk::{BUTTON_PRIMARY, BUTTON_SECONDARY},
|
||||
gdk,
|
||||
glib::{self, clone, subclass::Signal},
|
||||
graphene, gsk,
|
||||
prelude::*,
|
||||
|
@ -39,26 +39,38 @@ use std::{cmp::Ordering, collections::HashMap};
|
|||
static GRAPHVIEW_STYLE: &str = include_str!("graphview.css");
|
||||
pub static GRAPHVIEW_XML_VERSION: &str = "0.1";
|
||||
|
||||
const CANVAS_SIZE: f64 = 5000.0;
|
||||
|
||||
mod imp {
|
||||
use super::*;
|
||||
|
||||
use std::{
|
||||
cell::{Cell, RefCell},
|
||||
rc::Rc,
|
||||
};
|
||||
use std::cell::{Cell, RefCell};
|
||||
|
||||
use log::warn;
|
||||
|
||||
pub struct DragState {
|
||||
node: glib::WeakRef<Node>,
|
||||
/// This stores the offset of the pointer to the origin of the node,
|
||||
/// so that we can keep the pointer over the same position when moving the node
|
||||
///
|
||||
/// The offset is normalized to the default zoom-level of 1.0.
|
||||
offset: graphene::Point,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct GraphView {
|
||||
pub(super) id: Cell<u32>,
|
||||
pub(super) nodes: RefCell<HashMap<u32, Node>>,
|
||||
pub(super) nodes: RefCell<HashMap<u32, (Node, graphene::Point)>>,
|
||||
pub(super) links: RefCell<HashMap<u32, Link>>,
|
||||
pub(super) current_node_id: Cell<u32>,
|
||||
pub(super) current_port_id: Cell<u32>,
|
||||
pub(super) current_link_id: Cell<u32>,
|
||||
pub(super) port_selected: RefCell<Option<Port>>,
|
||||
pub(super) mouse_position: Cell<(f64, f64)>,
|
||||
pub dragged_node: RefCell<Option<DragState>>,
|
||||
pub hadjustment: RefCell<Option<gtk::Adjustment>>,
|
||||
pub vadjustment: RefCell<Option<gtk::Adjustment>>,
|
||||
pub zoom_factor: Cell<f64>,
|
||||
}
|
||||
|
||||
#[glib::object_subclass]
|
||||
|
@ -66,10 +78,11 @@ mod imp {
|
|||
const NAME: &'static str = "GraphView";
|
||||
type Type = super::GraphView;
|
||||
type ParentType = gtk::Widget;
|
||||
type Interfaces = (gtk::Scrollable,);
|
||||
|
||||
fn class_init(klass: &mut Self::Class) {
|
||||
// The layout manager determines how child widgets are laid out.
|
||||
klass.set_layout_manager_type::<gtk::FixedLayout>();
|
||||
//klass.set_layout_manager_type::<gtk::FixedLayout>();
|
||||
klass.set_css_name("graphview");
|
||||
}
|
||||
}
|
||||
|
@ -79,65 +92,79 @@ mod imp {
|
|||
let obj = self.obj();
|
||||
self.parent_constructed();
|
||||
|
||||
let drag_state = Rc::new(RefCell::new(None));
|
||||
self.obj().set_overflow(gtk::Overflow::Hidden);
|
||||
|
||||
let drag_controller = gtk::GestureDrag::new();
|
||||
|
||||
drag_controller.connect_drag_begin(
|
||||
clone!(@strong drag_state => move |drag_controller, x, y| {
|
||||
let mut drag_state = drag_state.borrow_mut();
|
||||
let widget = drag_controller
|
||||
.widget()
|
||||
.dynamic_cast::<Self::Type>()
|
||||
.expect("drag-begin event is not on the GraphView");
|
||||
// pick() should at least return the widget itself.
|
||||
let target = widget.pick(x, y, gtk::PickFlags::DEFAULT).expect("drag-begin pick() did not return a widget");
|
||||
*drag_state = if target.ancestor(Port::static_type()).is_some() {
|
||||
// The user targeted a port, so the dragging should be handled by the Port
|
||||
// component instead of here.
|
||||
None
|
||||
} else if let Some(target) = target.ancestor(Node::static_type()) {
|
||||
// The user targeted a Node without targeting a specific Port.
|
||||
// Drag the Node around the screen.
|
||||
if let Some((x, y)) = widget.node_position(&target) {
|
||||
Some((target, x, y))
|
||||
} else {
|
||||
error!("Failed to obtain position of dragged node, drag aborted.");
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
drag_controller.connect_drag_begin(|drag_controller, x, y| {
|
||||
let widget = drag_controller
|
||||
.widget()
|
||||
.dynamic_cast::<super::GraphView>()
|
||||
.expect("drag-begin event is not on the GraphView");
|
||||
let mut dragged_node = widget.imp().dragged_node.borrow_mut();
|
||||
|
||||
// pick() should at least return the widget itself.
|
||||
let target = widget
|
||||
.pick(x, y, gtk::PickFlags::DEFAULT)
|
||||
.expect("drag-begin pick() did not return a widget");
|
||||
*dragged_node = if target.ancestor(Port::static_type()).is_some() {
|
||||
// The user targeted a port, so the dragging should be handled by the Port
|
||||
// component instead of here.
|
||||
None
|
||||
} else if let Some(target) = target.ancestor(Node::static_type()) {
|
||||
// The user targeted a Node without targeting a specific Port.
|
||||
// Drag the Node around the screen.
|
||||
let node = target.dynamic_cast_ref::<Node>().unwrap();
|
||||
|
||||
let Some(canvas_node_pos) = widget.node_position(node) else { return };
|
||||
let canvas_cursor_pos = widget
|
||||
.imp()
|
||||
.screen_space_to_canvas_space_transform()
|
||||
.transform_point(&graphene::Point::new(x as f32, y as f32));
|
||||
|
||||
Some(DragState {
|
||||
node: node.clone().downgrade(),
|
||||
offset: graphene::Point::new(
|
||||
canvas_cursor_pos.x() - canvas_node_pos.x(),
|
||||
canvas_cursor_pos.y() - canvas_node_pos.y(),
|
||||
),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
));
|
||||
drag_controller.connect_drag_update(
|
||||
clone!(@strong drag_state => move |drag_controller, x, y| {
|
||||
let widget = drag_controller
|
||||
.widget()
|
||||
.dynamic_cast::<Self::Type>()
|
||||
.expect("drag-update event is not on the GraphView");
|
||||
let drag_state = drag_state.borrow();
|
||||
if let Some((ref node, x1, y1)) = *drag_state {
|
||||
widget.move_node(node, x1 + x as f32, y1 + y as f32);
|
||||
}
|
||||
}
|
||||
),
|
||||
);
|
||||
drag_controller.connect_drag_end(
|
||||
clone!(@strong drag_state => move |drag_controller, _x, _y| {
|
||||
let widget = drag_controller
|
||||
.widget()
|
||||
.dynamic_cast::<Self::Type>()
|
||||
.expect("drag-end event is not on the GraphView");
|
||||
widget.graph_updated();
|
||||
}
|
||||
),
|
||||
);
|
||||
});
|
||||
drag_controller.connect_drag_update(|drag_controller, x, y| {
|
||||
let widget = drag_controller
|
||||
.widget()
|
||||
.dynamic_cast::<super::GraphView>()
|
||||
.expect("drag-update event is not on the GraphView");
|
||||
let dragged_node = widget.imp().dragged_node.borrow();
|
||||
let Some(DragState { node, offset }) = dragged_node.as_ref() else { return };
|
||||
let Some(node) = node.upgrade() else { return };
|
||||
|
||||
let (start_x, start_y) = drag_controller
|
||||
.start_point()
|
||||
.expect("Drag has no start point");
|
||||
|
||||
let onscreen_node_origin =
|
||||
graphene::Point::new((start_x + x) as f32, (start_y + y) as f32);
|
||||
let transform = widget.imp().screen_space_to_canvas_space_transform();
|
||||
let canvas_node_origin = transform.transform_point(&onscreen_node_origin);
|
||||
|
||||
widget.move_node(
|
||||
&node,
|
||||
&graphene::Point::new(
|
||||
canvas_node_origin.x() - offset.x(),
|
||||
canvas_node_origin.y() - offset.y(),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
let gesture = gtk::GestureClick::new();
|
||||
gesture.set_button(0);
|
||||
gesture.connect_pressed(
|
||||
clone!(@weak obj, @weak drag_controller => move |gesture, _n_press, x, y| {
|
||||
if gesture.current_button() == BUTTON_SECONDARY {
|
||||
if gesture.current_button() == gdk::BUTTON_SECONDARY {
|
||||
let widget = drag_controller.widget()
|
||||
.dynamic_cast::<Self::Type>()
|
||||
.expect("click event is not on the GraphView");
|
||||
|
@ -155,7 +182,7 @@ mod imp {
|
|||
widget.unselect_all();
|
||||
obj.emit_by_name::<()>("graph-right-clicked", &[&graphene::Point::new(x as f32,y as f32)]);
|
||||
}
|
||||
} else if gesture.current_button() == BUTTON_PRIMARY {
|
||||
} else if gesture.current_button() == gdk::BUTTON_PRIMARY {
|
||||
let widget = drag_controller.widget()
|
||||
.dynamic_cast::<Self::Type>()
|
||||
.expect("click event is not on the GraphView");
|
||||
|
@ -177,7 +204,7 @@ mod imp {
|
|||
);
|
||||
|
||||
gesture.connect_released(clone!(@weak gesture, @weak obj, @weak drag_controller => move |_gesture, _n_press, x, y| {
|
||||
if gesture.current_button() == BUTTON_PRIMARY {
|
||||
if gesture.current_button() == gdk::BUTTON_PRIMARY {
|
||||
let widget = drag_controller
|
||||
.widget()
|
||||
.dynamic_cast::<Self::Type>()
|
||||
|
@ -229,6 +256,8 @@ mod imp {
|
|||
info!("double clicked link id {}", link.id());
|
||||
obj.emit_by_name::<()>("link-double-clicked", &[&link.id(), &graphene::Point::new(x as f32,y as f32)]);
|
||||
}
|
||||
} else {
|
||||
info!("double click {}",widget.width());
|
||||
}
|
||||
|
||||
// Click to something else than a port
|
||||
|
@ -237,27 +266,49 @@ mod imp {
|
|||
}
|
||||
}
|
||||
}));
|
||||
obj.add_controller(drag_controller);
|
||||
obj.add_controller(gesture);
|
||||
|
||||
let event_motion = gtk::EventControllerMotion::new();
|
||||
event_motion.connect_motion(glib::clone!(@weak obj => move |_e, x, y| {
|
||||
let graphview = obj;
|
||||
if graphview.selected_port().is_some() {
|
||||
graphview.set_mouse_position(x,y);
|
||||
graphview.queue_draw();
|
||||
graphview.queue_allocate();
|
||||
}
|
||||
|
||||
}));
|
||||
|
||||
obj.add_controller(drag_controller);
|
||||
obj.add_controller(gesture);
|
||||
obj.add_controller(event_motion);
|
||||
|
||||
let scroll_controller =
|
||||
gtk::EventControllerScroll::new(gtk::EventControllerScrollFlags::BOTH_AXES);
|
||||
|
||||
scroll_controller.connect_scroll(|eventcontroller, _, delta_y| {
|
||||
let event = eventcontroller.current_event().unwrap(); // We are inside the event handler, so it must have an event
|
||||
|
||||
if event
|
||||
.modifier_state()
|
||||
.contains(gdk::ModifierType::CONTROL_MASK)
|
||||
{
|
||||
let widget = eventcontroller
|
||||
.widget()
|
||||
.downcast::<super::GraphView>()
|
||||
.unwrap();
|
||||
widget.set_zoom_factor(widget.zoom_factor() + (0.1 * -delta_y), None);
|
||||
|
||||
glib::Propagation::Stop
|
||||
} else {
|
||||
glib::Propagation::Proceed
|
||||
}
|
||||
});
|
||||
self.obj().add_controller(scroll_controller);
|
||||
}
|
||||
|
||||
fn dispose(&self) {
|
||||
self.nodes
|
||||
.borrow()
|
||||
.values()
|
||||
.for_each(|node| node.unparent())
|
||||
.for_each(|(node, _)| node.unparent())
|
||||
}
|
||||
|
||||
fn signals() -> &'static [Signal] {
|
||||
|
@ -301,18 +352,97 @@ mod imp {
|
|||
});
|
||||
SIGNALS.as_ref()
|
||||
}
|
||||
fn properties() -> &'static [glib::ParamSpec] {
|
||||
static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
|
||||
vec![
|
||||
glib::ParamSpecOverride::for_interface::<gtk::Scrollable>("hadjustment"),
|
||||
glib::ParamSpecOverride::for_interface::<gtk::Scrollable>("vadjustment"),
|
||||
glib::ParamSpecOverride::for_interface::<gtk::Scrollable>("hscroll-policy"),
|
||||
glib::ParamSpecOverride::for_interface::<gtk::Scrollable>("vscroll-policy"),
|
||||
glib::ParamSpecDouble::builder("zoom-factor")
|
||||
.minimum(0.3)
|
||||
.maximum(4.0)
|
||||
.default_value(1.0)
|
||||
.flags(glib::ParamFlags::CONSTRUCT | glib::ParamFlags::READWRITE)
|
||||
.build(),
|
||||
]
|
||||
});
|
||||
|
||||
PROPERTIES.as_ref()
|
||||
}
|
||||
|
||||
fn property(&self, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
|
||||
match pspec.name() {
|
||||
"hadjustment" => self.hadjustment.borrow().to_value(),
|
||||
"vadjustment" => self.vadjustment.borrow().to_value(),
|
||||
"hscroll-policy" | "vscroll-policy" => gtk::ScrollablePolicy::Natural.to_value(),
|
||||
"zoom-factor" => self.zoom_factor.get().to_value(),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn set_property(&self, _id: usize, value: &glib::Value, pspec: &glib::ParamSpec) {
|
||||
let obj = self.obj();
|
||||
|
||||
match pspec.name() {
|
||||
"hadjustment" => {
|
||||
obj.set_adjustment(&obj, value.get().ok(), gtk::Orientation::Horizontal)
|
||||
}
|
||||
"vadjustment" => {
|
||||
obj.set_adjustment(&obj, value.get().ok(), gtk::Orientation::Vertical)
|
||||
}
|
||||
"hscroll-policy" | "vscroll-policy" => {}
|
||||
"zoom-factor" => {
|
||||
self.zoom_factor.set(value.get().unwrap());
|
||||
obj.queue_allocate();
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WidgetImpl for GraphView {
|
||||
fn size_allocate(&self, _width: i32, _height: i32, baseline: i32) {
|
||||
let widget = &*self.obj();
|
||||
|
||||
let zoom_factor = self.zoom_factor.get();
|
||||
|
||||
for (node, point) in self.nodes.borrow().values() {
|
||||
let (_, natural_size) = node.preferred_size();
|
||||
|
||||
let transform = self
|
||||
.canvas_space_to_screen_space_transform()
|
||||
.translate(point);
|
||||
|
||||
node.allocate(
|
||||
(natural_size.width() as f64 * zoom_factor).ceil() as i32,
|
||||
(natural_size.height() as f64 * zoom_factor).ceil() as i32,
|
||||
baseline,
|
||||
Some(transform),
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(ref hadjustment) = *self.hadjustment.borrow() {
|
||||
widget.set_adjustment_values(widget, hadjustment, gtk::Orientation::Horizontal);
|
||||
}
|
||||
if let Some(ref vadjustment) = *self.vadjustment.borrow() {
|
||||
widget.set_adjustment_values(widget, vadjustment, gtk::Orientation::Vertical);
|
||||
}
|
||||
}
|
||||
|
||||
fn snapshot(&self, snapshot: >k::Snapshot) {
|
||||
/* FIXME: A lot of hardcoded values in here.
|
||||
Try to use relative units (em) and colours from the theme as much as possible. */
|
||||
|
||||
let widget = &*self.obj();
|
||||
let alloc = widget.allocation();
|
||||
// Draw all children
|
||||
// Draw all visible children
|
||||
self.nodes
|
||||
.borrow()
|
||||
.values()
|
||||
.for_each(|node| self.obj().snapshot_child(node, snapshot));
|
||||
// Cull nodes from rendering when they are outside the visible canvas area
|
||||
.filter(|(node, _)| alloc.intersect(&node.allocation()).is_some())
|
||||
.for_each(|(node, _)| widget.snapshot_child(node, snapshot));
|
||||
|
||||
for link in self.links.borrow().values() {
|
||||
if let Some((from_x, from_y, to_x, to_y)) = self.link_coordinates(link) {
|
||||
|
@ -353,56 +483,77 @@ mod imp {
|
|||
}
|
||||
}
|
||||
|
||||
impl ScrollableImpl for GraphView {}
|
||||
|
||||
impl GraphView {
|
||||
/// Returns a [`gsk::Transform`] matrix that can translate from canvas space to screen space.
|
||||
///
|
||||
/// Canvas space is non-zoomed, and (0, 0) is fixed at the middle of the graph. \
|
||||
/// Screen space is zoomed and adjusted for scrolling, (0, 0) is at the top-left corner of the window.
|
||||
///
|
||||
/// This is the inverted form of [`Self::screen_space_to_canvas_space_transform()`].
|
||||
fn canvas_space_to_screen_space_transform(&self) -> gsk::Transform {
|
||||
let hadj = self.hadjustment.borrow().as_ref().unwrap().value();
|
||||
let vadj = self.vadjustment.borrow().as_ref().unwrap().value();
|
||||
let zoom_factor = self.zoom_factor.get();
|
||||
|
||||
gsk::Transform::new()
|
||||
.translate(&graphene::Point::new(-hadj as f32, -vadj as f32))
|
||||
.scale(zoom_factor as f32, zoom_factor as f32)
|
||||
}
|
||||
|
||||
/// Returns a [`gsk::Transform`] matrix that can translate from screen space to canvas space.
|
||||
///
|
||||
/// This is the inverted form of [`Self::canvas_space_to_screen_space_transform()`], see that function for a more detailed explantion.
|
||||
fn screen_space_to_canvas_space_transform(&self) -> gsk::Transform {
|
||||
self.canvas_space_to_screen_space_transform()
|
||||
.invert()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
fn link_from_coordinates(&self, node_from: u32, port_from: u32) -> (f64, f64) {
|
||||
let nodes = self.nodes.borrow();
|
||||
|
||||
let widget = &*self.obj();
|
||||
let from_node = nodes
|
||||
.get(&node_from)
|
||||
.unwrap_or_else(|| (panic!("Unable to get node from {}", node_from)));
|
||||
|
||||
let from_port = from_node
|
||||
.0
|
||||
.port(port_from)
|
||||
.unwrap_or_else(|| panic!("Unable to get port from {}", port_from));
|
||||
let (mut from_x, mut from_y, fw, fh) = (
|
||||
from_port.allocation().x(),
|
||||
from_port.allocation().y(),
|
||||
from_port.allocation().width(),
|
||||
from_port.allocation().height(),
|
||||
);
|
||||
let (fnx, fny) = (from_node.allocation().x(), from_node.allocation().y());
|
||||
|
||||
if let Some((port_x, port_y)) = from_port.translate_coordinates(from_node, 0.0, 0.0) {
|
||||
from_x = fnx + fw + port_x as i32;
|
||||
from_y = fny + (fh / 2) + port_y as i32;
|
||||
}
|
||||
let (x, y) = from_port
|
||||
.translate_coordinates(
|
||||
widget,
|
||||
(from_port.width() / 2) as f64,
|
||||
(from_port.height() / 2) as f64,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
(from_x as f64, from_y as f64)
|
||||
(x, y)
|
||||
}
|
||||
|
||||
fn link_to_coordinates(&self, node_to: u32, port_to: u32) -> (f64, f64) {
|
||||
let nodes = self.nodes.borrow();
|
||||
let widget = &*self.obj();
|
||||
|
||||
let to_node = nodes
|
||||
.get(&node_to)
|
||||
.unwrap_or_else(|| panic!("Unable to get node to {}", node_to));
|
||||
let to_port = to_node
|
||||
.0
|
||||
.port(port_to)
|
||||
.unwrap_or_else(|| panic!("Unable to get port to {}", port_to));
|
||||
let (mut to_x, mut to_y, th) = (
|
||||
to_port.allocation().x(),
|
||||
to_port.allocation().y(),
|
||||
to_port.allocation().height(),
|
||||
);
|
||||
let (x, y) = to_port
|
||||
.translate_coordinates(
|
||||
widget,
|
||||
(to_port.width() / 2) as f64,
|
||||
(to_port.height() / 2) as f64,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let (tnx, tny) = (to_node.allocation().x(), to_node.allocation().y());
|
||||
|
||||
if let Some((port_x, port_y)) = to_port.translate_coordinates(to_node, 0.0, 0.0) {
|
||||
to_x += tnx + port_x as i32;
|
||||
to_y = tny + (th / 2) + port_y as i32;
|
||||
}
|
||||
//trace!("{} {} -> {} {}", fx, fy, tx, ty);
|
||||
(to_x.into(), to_y.into())
|
||||
(x, y)
|
||||
}
|
||||
/// Retrieves coordinates for the drawn link to start at and to end at.
|
||||
///
|
||||
|
@ -469,6 +620,8 @@ glib::wrapper! {
|
|||
}
|
||||
|
||||
impl GraphView {
|
||||
pub const ZOOM_MIN: f64 = 0.3;
|
||||
pub const ZOOM_MAX: f64 = 4.0;
|
||||
/// Create a new graphview
|
||||
///
|
||||
/// # Returns
|
||||
|
@ -482,6 +635,7 @@ impl GraphView {
|
|||
&provider,
|
||||
gtk::STYLE_PROVIDER_PRIORITY_APPLICATION,
|
||||
);
|
||||
|
||||
glib::Object::new::<Self>()
|
||||
}
|
||||
|
||||
|
@ -505,6 +659,40 @@ impl GraphView {
|
|||
self.remove_all_nodes();
|
||||
}
|
||||
|
||||
pub fn zoom_factor(&self) -> f64 {
|
||||
self.property("zoom-factor")
|
||||
}
|
||||
|
||||
pub fn set_zoom_factor(&self, zoom_factor: f64, anchor: Option<(f64, f64)>) {
|
||||
let private = imp::GraphView::from_obj(self);
|
||||
let zoom_factor = zoom_factor.clamp(Self::ZOOM_MIN, Self::ZOOM_MAX);
|
||||
|
||||
let (anchor_x_screen, anchor_y_screen) = anchor.unwrap_or_else(|| {
|
||||
(
|
||||
self.allocation().width() as f64 / 2.0,
|
||||
self.allocation().height() as f64 / 2.0,
|
||||
)
|
||||
});
|
||||
|
||||
let old_zoom = private.zoom_factor.get();
|
||||
let hadjustment_ref = private.hadjustment.borrow();
|
||||
let vadjustment_ref = private.vadjustment.borrow();
|
||||
let hadjustment = hadjustment_ref.as_ref().unwrap();
|
||||
let vadjustment = vadjustment_ref.as_ref().unwrap();
|
||||
|
||||
let x_total = (anchor_x_screen + hadjustment.value()) / old_zoom;
|
||||
let y_total = (anchor_y_screen + vadjustment.value()) / old_zoom;
|
||||
|
||||
let new_hadjustment = x_total * zoom_factor - anchor_x_screen;
|
||||
let new_vadjustment = y_total * zoom_factor - anchor_y_screen;
|
||||
|
||||
hadjustment.set_value(new_hadjustment);
|
||||
vadjustment.set_value(new_vadjustment);
|
||||
|
||||
self.set_property("zoom-factor", zoom_factor);
|
||||
info!("zoom factor {}", zoom_factor);
|
||||
}
|
||||
|
||||
// Node
|
||||
|
||||
/// Create a new node with a new id
|
||||
|
@ -560,9 +748,10 @@ impl GraphView {
|
|||
.nodes
|
||||
.borrow()
|
||||
.values()
|
||||
.filter_map(|node| {
|
||||
// Map nodes to locations, discard nodes without location
|
||||
self.node_position(&node.clone().upcast())
|
||||
.map(|node| {
|
||||
// Map nodes to their locations
|
||||
let point = self.node_position(&node.0.clone().upcast()).unwrap();
|
||||
(point.x(), point.y())
|
||||
})
|
||||
.filter(|(x2, _)| {
|
||||
// Only look for other nodes that have a similar x coordinate
|
||||
|
@ -572,11 +761,13 @@ impl GraphView {
|
|||
// Get max in column
|
||||
y1.partial_cmp(y2).unwrap_or(Ordering::Equal)
|
||||
})
|
||||
.map_or(20_f32, |(_x, y)| y + 100.0);
|
||||
.map_or(20_f32, |(_x, y)| y + 120.0);
|
||||
|
||||
self.move_node(&node.clone().upcast(), x, y);
|
||||
let node_id = node.id();
|
||||
private.nodes.borrow_mut().insert(node.id(), node);
|
||||
private
|
||||
.nodes
|
||||
.borrow_mut()
|
||||
.insert(node.id(), (node, graphene::Point::new(x, y)));
|
||||
self.emit_by_name::<()>("node-added", &[&private.id.get(), &node_id]);
|
||||
self.graph_updated();
|
||||
}
|
||||
|
@ -585,17 +776,16 @@ impl GraphView {
|
|||
///
|
||||
pub fn remove_node(&self, id: u32) {
|
||||
let private = imp::GraphView::from_obj(self);
|
||||
let mut nodes = private.nodes.borrow_mut();
|
||||
if let Some(node) = nodes.remove(&id) {
|
||||
while let Some(link_id) = self.node_is_linked(node.id()) {
|
||||
|
||||
if let Some(node) = private.nodes.borrow_mut().remove(&id) {
|
||||
while let Some(link_id) = self.node_is_linked(node.0.id()) {
|
||||
info!("Remove link id {}", link_id);
|
||||
private.links.borrow_mut().remove(&link_id);
|
||||
}
|
||||
node.unparent();
|
||||
node.0.unparent();
|
||||
} else {
|
||||
warn!("Tried to remove non-existent node (id={}) from graph", id);
|
||||
}
|
||||
self.queue_draw();
|
||||
}
|
||||
|
||||
/// Select all nodes according to the NodeType
|
||||
|
@ -607,9 +797,9 @@ impl GraphView {
|
|||
let nodes_list: Vec<_> = nodes
|
||||
.iter()
|
||||
.filter(|(_, node)| {
|
||||
*node.node_type().unwrap() == node_type || node_type == NodeType::All
|
||||
*node.0.node_type().unwrap() == node_type || node_type == NodeType::All
|
||||
})
|
||||
.map(|(_, node)| node.clone())
|
||||
.map(|(_, node)| node.0.clone())
|
||||
.collect();
|
||||
nodes_list
|
||||
}
|
||||
|
@ -619,7 +809,12 @@ impl GraphView {
|
|||
/// Returns `None` if the node is not in the graphview.
|
||||
pub fn node(&self, id: u32) -> Option<Node> {
|
||||
let private = imp::GraphView::from_obj(self);
|
||||
private.nodes.borrow().get(&id).cloned()
|
||||
|
||||
if let Some(node) = private.nodes.borrow().get(&id).cloned() {
|
||||
Some(node.0)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the node with the specified node name inside the graphview.
|
||||
|
@ -628,8 +823,8 @@ impl GraphView {
|
|||
pub fn node_by_unique_name(&self, unique_name: &str) -> Option<Node> {
|
||||
let private = imp::GraphView::from_obj(self);
|
||||
for node in private.nodes.borrow().values() {
|
||||
if node.unique_name() == unique_name {
|
||||
return Some(node.clone());
|
||||
if node.0.unique_name() == unique_name {
|
||||
return Some(node.0.clone());
|
||||
}
|
||||
}
|
||||
None
|
||||
|
@ -646,7 +841,6 @@ impl GraphView {
|
|||
private.current_node_id.set(0);
|
||||
private.current_port_id.set(0);
|
||||
private.current_link_id.set(0);
|
||||
self.queue_draw();
|
||||
}
|
||||
|
||||
/// Check if the node is linked
|
||||
|
@ -665,21 +859,12 @@ impl GraphView {
|
|||
/// Get the position of the specified node inside the graphview.
|
||||
///
|
||||
/// Returns `None` if the node is not in the graphview.
|
||||
pub(super) fn node_position(&self, node: >k::Widget) -> Option<(f32, f32)> {
|
||||
let layout_manager = self
|
||||
.layout_manager()
|
||||
.expect("Failed to get layout manager")
|
||||
.dynamic_cast::<gtk::FixedLayout>()
|
||||
.expect("Failed to cast to FixedLayout");
|
||||
|
||||
let node = layout_manager
|
||||
.layout_child(node)
|
||||
.dynamic_cast::<gtk::FixedLayoutChild>()
|
||||
.expect("Could not cast to FixedLayoutChild");
|
||||
let transform = node
|
||||
.transform()
|
||||
.expect("Failed to obtain transform from layout child");
|
||||
Some(transform.to_translate())
|
||||
pub(super) fn node_position(&self, node: &Node) -> Option<graphene::Point> {
|
||||
self.imp()
|
||||
.nodes
|
||||
.borrow()
|
||||
.get(&node.id())
|
||||
.map(|(_, point)| *point)
|
||||
}
|
||||
|
||||
// Port
|
||||
|
@ -713,9 +898,8 @@ impl GraphView {
|
|||
/// Return true if the port presence is not always.
|
||||
pub fn can_remove_port(&self, node_id: u32, port_id: u32) -> bool {
|
||||
let private = imp::GraphView::from_obj(self);
|
||||
let nodes = private.nodes.borrow();
|
||||
if let Some(node) = nodes.get(&node_id) {
|
||||
return node.can_remove_port(port_id);
|
||||
if let Some(node) = private.nodes.borrow().get(&node_id) {
|
||||
return node.0.can_remove_port(port_id);
|
||||
}
|
||||
warn!("Unable to find a node with the id {}", node_id);
|
||||
false
|
||||
|
@ -725,12 +909,11 @@ impl GraphView {
|
|||
///
|
||||
pub fn remove_port(&self, node_id: u32, port_id: u32) {
|
||||
let private = imp::GraphView::from_obj(self);
|
||||
let nodes = private.nodes.borrow();
|
||||
if let Some(node) = nodes.get(&node_id) {
|
||||
if let Some(node) = private.nodes.borrow().get(&node_id) {
|
||||
if let Some(link_id) = self.port_is_linked(port_id) {
|
||||
self.remove_link(link_id);
|
||||
}
|
||||
node.remove_port(port_id);
|
||||
node.0.remove_port(port_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -864,8 +1047,8 @@ impl GraphView {
|
|||
}
|
||||
}
|
||||
for node in private.nodes.borrow_mut().values() {
|
||||
if node.selected() {
|
||||
node_id = Some(node.id());
|
||||
if node.0.selected() {
|
||||
node_id = Some(node.0.id());
|
||||
}
|
||||
}
|
||||
if let Some(id) = link_id {
|
||||
|
@ -895,8 +1078,8 @@ impl GraphView {
|
|||
)?;
|
||||
|
||||
//Get the nodes
|
||||
let nodes = self.all_nodes(NodeType::All);
|
||||
for node in nodes {
|
||||
|
||||
for node in self.all_nodes(NodeType::All) {
|
||||
writer.write(
|
||||
XMLWEvent::start_element("Node")
|
||||
.attr("name", &node.name())
|
||||
|
@ -1104,12 +1287,13 @@ impl GraphView {
|
|||
"Node" => {
|
||||
if let Some(node) = current_node {
|
||||
let id = node.id();
|
||||
let position = node.position();
|
||||
let position =
|
||||
graphene::Point::new(node.position().0, node.position().1);
|
||||
node.update_properties(¤t_node_properties);
|
||||
current_node_properties.clear();
|
||||
self.add_node(node);
|
||||
if let Some(node) = self.node(id) {
|
||||
self.move_node(&node.upcast(), position.0, position.1);
|
||||
self.move_node(&node, &position);
|
||||
}
|
||||
|
||||
self.update_current_node_id(id);
|
||||
|
@ -1207,38 +1391,31 @@ impl GraphView {
|
|||
false
|
||||
}
|
||||
|
||||
fn move_node(&self, widget: >k::Widget, x: f32, y: f32) {
|
||||
let node = widget
|
||||
.clone()
|
||||
.dynamic_cast::<Node>()
|
||||
.expect("Unable to convert to Node");
|
||||
node.set_position(x, y);
|
||||
let layout_manager = self
|
||||
.layout_manager()
|
||||
.expect("Failed to get layout manager")
|
||||
.dynamic_cast::<gtk::FixedLayout>()
|
||||
.expect("Failed to cast to FixedLayout");
|
||||
fn move_node(&self, widget: &Node, point: &graphene::Point) {
|
||||
let mut nodes = self.imp().nodes.borrow_mut();
|
||||
let mut node = nodes
|
||||
.get_mut(&widget.id())
|
||||
.expect("Node is not on the graph");
|
||||
node.1 = graphene::Point::new(
|
||||
point.x().clamp(
|
||||
-(CANVAS_SIZE / 2.0) as f32,
|
||||
(CANVAS_SIZE / 2.0) as f32 - widget.width() as f32,
|
||||
),
|
||||
point.y().clamp(
|
||||
-(CANVAS_SIZE / 2.0) as f32,
|
||||
(CANVAS_SIZE / 2.0) as f32 - widget.height() as f32,
|
||||
),
|
||||
);
|
||||
|
||||
let transform = gsk::Transform::new()
|
||||
// Nodes should not be able to be dragged out of the view, so we use `max(coordinate, 0.0)` to prevent that.
|
||||
.translate(&graphene::Point::new(f32::max(x, 0.0), f32::max(y, 0.0)));
|
||||
|
||||
layout_manager
|
||||
.layout_child(widget)
|
||||
.dynamic_cast::<gtk::FixedLayoutChild>()
|
||||
.expect("Could not cast to FixedLayoutChild")
|
||||
.set_transform(&transform);
|
||||
|
||||
// FIXME: If links become proper widgets,
|
||||
// we don't need to redraw the full graph everytime.
|
||||
self.queue_draw();
|
||||
self.queue_allocate();
|
||||
}
|
||||
|
||||
fn unselect_nodes(&self) {
|
||||
let private = imp::GraphView::from_obj(self);
|
||||
for node in private.nodes.borrow_mut().values() {
|
||||
node.set_selected(false);
|
||||
node.unselect_all_ports();
|
||||
node.0.set_selected(false);
|
||||
node.0.unselect_all_ports();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1286,7 +1463,7 @@ impl GraphView {
|
|||
|
||||
fn graph_updated(&self) {
|
||||
let private = imp::GraphView::from_obj(self);
|
||||
self.queue_draw();
|
||||
self.queue_allocate();
|
||||
self.emit_by_name::<()>("graph-updated", &[&private.id.get()]);
|
||||
}
|
||||
|
||||
|
@ -1362,6 +1539,47 @@ impl GraphView {
|
|||
private.current_port_id.set(port_id);
|
||||
}
|
||||
}
|
||||
fn set_adjustment(
|
||||
&self,
|
||||
obj: &super::GraphView,
|
||||
adjustment: Option<>k::Adjustment>,
|
||||
orientation: gtk::Orientation,
|
||||
) {
|
||||
let private = imp::GraphView::from_obj(self);
|
||||
match orientation {
|
||||
gtk::Orientation::Horizontal => *private.hadjustment.borrow_mut() = adjustment.cloned(),
|
||||
gtk::Orientation::Vertical => *private.vadjustment.borrow_mut() = adjustment.cloned(),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
|
||||
if let Some(adjustment) = adjustment {
|
||||
adjustment.connect_value_changed(clone!(@weak obj => move |_| obj.queue_allocate() ));
|
||||
}
|
||||
}
|
||||
|
||||
fn set_adjustment_values(
|
||||
&self,
|
||||
obj: &super::GraphView,
|
||||
adjustment: >k::Adjustment,
|
||||
orientation: gtk::Orientation,
|
||||
) {
|
||||
let private = imp::GraphView::from_obj(self);
|
||||
let size = match orientation {
|
||||
gtk::Orientation::Horizontal => obj.width(),
|
||||
gtk::Orientation::Vertical => obj.height(),
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
let zoom_factor = private.zoom_factor.get();
|
||||
|
||||
adjustment.configure(
|
||||
adjustment.value(),
|
||||
-(CANVAS_SIZE / 2.0) * zoom_factor,
|
||||
(CANVAS_SIZE / 2.0) * zoom_factor,
|
||||
(f64::from(size) * 0.1) * zoom_factor,
|
||||
(f64::from(size) * 0.9) * zoom_factor,
|
||||
f64::from(size) * zoom_factor,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for GraphView {
|
||||
|
|
|
@ -209,17 +209,11 @@
|
|||
<property name="orientation">vertical</property>
|
||||
<property name="position">400</property>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="drawing_area-window">
|
||||
<property name="hexpand">True</property>
|
||||
<property name="vexpand">True</property>
|
||||
<property name="child">
|
||||
<object class="GtkNotebook" id="graphbook">
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkNotebook" id="notebook-debug">
|
||||
|
|
Loading…
Reference in a new issue