diff --git a/Cargo.lock b/Cargo.lock
index 05c1f0cc..313df4a7 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -449,6 +449,29 @@ dependencies = [
"syn 2.0.106",
]
+[[package]]
+name = "atk"
+version = "0.18.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "241b621213072e993be4f6f3a9e4b45f65b7e6faad43001be957184b7bb1824b"
+dependencies = [
+ "atk-sys",
+ "glib 0.18.5",
+ "libc",
+]
+
+[[package]]
+name = "atk-sys"
+version = "0.18.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c5e48b684b0ca77d2bbadeef17424c2ea3c897d44d566a1617e7e8f30614d086"
+dependencies = [
+ "glib-sys 0.18.1",
+ "gobject-sys 0.18.0",
+ "libc",
+ "system-deps 6.2.2",
+]
+
[[package]]
name = "atomic-waker"
version = "1.1.2"
@@ -775,6 +798,31 @@ version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
+[[package]]
+name = "cairo-rs"
+version = "0.18.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2"
+dependencies = [
+ "bitflags 2.9.4",
+ "cairo-sys-rs",
+ "glib 0.18.5",
+ "libc",
+ "once_cell",
+ "thiserror 1.0.69",
+]
+
+[[package]]
+name = "cairo-sys-rs"
+version = "0.18.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "685c9fa8e590b8b3d678873528d83411db17242a73fccaed827770ea0fedda51"
+dependencies = [
+ "glib-sys 0.18.1",
+ "libc",
+ "system-deps 6.2.2",
+]
+
[[package]]
name = "calloop"
version = "0.13.0"
@@ -848,7 +896,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02"
dependencies = [
"smallvec",
- "target-lexicon",
+ "target-lexicon 0.12.16",
+]
+
+[[package]]
+name = "cfg-expr"
+version = "0.20.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a2c5f3bf25ec225351aa1c8e230d04d880d3bd89dea133537dafad4ae291e5c"
+dependencies = [
+ "smallvec",
+ "target-lexicon 0.13.2",
]
[[package]]
@@ -1014,7 +1072,7 @@ dependencies = [
"serde_core",
"serde_json",
"toml 0.9.7",
- "winnow",
+ "winnow 0.7.13",
"yaml-rust2",
]
@@ -1369,7 +1427,9 @@ version = "0.1.0"
dependencies = [
"anyhow",
"chrono",
+ "gio 0.21.2",
"glam",
+ "gtk",
"log",
"rust-embed",
"wgui",
@@ -1757,6 +1817,16 @@ dependencies = [
"simd-adler32",
]
+[[package]]
+name = "field-offset"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f"
+dependencies = [
+ "memoffset",
+ "rustc_version",
+]
+
[[package]]
name = "find-msvc-tools"
version = "0.1.2"
@@ -1979,6 +2049,64 @@ dependencies = [
"slab",
]
+[[package]]
+name = "gdk"
+version = "0.18.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9f245958c627ac99d8e529166f9823fb3b838d1d41fd2b297af3075093c2691"
+dependencies = [
+ "cairo-rs",
+ "gdk-pixbuf",
+ "gdk-sys",
+ "gio 0.18.4",
+ "glib 0.18.5",
+ "libc",
+ "pango",
+]
+
+[[package]]
+name = "gdk-pixbuf"
+version = "0.18.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "50e1f5f1b0bfb830d6ccc8066d18db35c487b1b2b1e8589b5dfe9f07e8defaec"
+dependencies = [
+ "gdk-pixbuf-sys",
+ "gio 0.18.4",
+ "glib 0.18.5",
+ "libc",
+ "once_cell",
+]
+
+[[package]]
+name = "gdk-pixbuf-sys"
+version = "0.18.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9839ea644ed9c97a34d129ad56d38a25e6756f99f3a88e15cd39c20629caf7"
+dependencies = [
+ "gio-sys 0.18.1",
+ "glib-sys 0.18.1",
+ "gobject-sys 0.18.0",
+ "libc",
+ "system-deps 6.2.2",
+]
+
+[[package]]
+name = "gdk-sys"
+version = "0.18.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c2d13f38594ac1e66619e188c6d5a1adb98d11b2fcf7894fc416ad76aa2f3f7"
+dependencies = [
+ "cairo-sys-rs",
+ "gdk-pixbuf-sys",
+ "gio-sys 0.18.1",
+ "glib-sys 0.18.1",
+ "gobject-sys 0.18.0",
+ "libc",
+ "pango-sys",
+ "pkg-config",
+ "system-deps 6.2.2",
+]
+
[[package]]
name = "generic-array"
version = "0.14.7"
@@ -2038,6 +2166,68 @@ version = "0.31.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
+[[package]]
+name = "gio"
+version = "0.18.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d4fc8f532f87b79cbc51a79748f16a6828fb784be93145a322fa14d06d354c73"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-io",
+ "futures-util",
+ "gio-sys 0.18.1",
+ "glib 0.18.5",
+ "libc",
+ "once_cell",
+ "pin-project-lite",
+ "smallvec",
+ "thiserror 1.0.69",
+]
+
+[[package]]
+name = "gio"
+version = "0.21.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed68efc12b748a771be2dccc49480d8584004382967c98323245fc3c38b74a42"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-io",
+ "futures-util",
+ "gio-sys 0.21.2",
+ "glib 0.21.3",
+ "libc",
+ "pin-project-lite",
+ "smallvec",
+]
+
+[[package]]
+name = "gio-sys"
+version = "0.18.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37566df850baf5e4cb0dfb78af2e4b9898d817ed9263d1090a2df958c64737d2"
+dependencies = [
+ "glib-sys 0.18.1",
+ "gobject-sys 0.18.0",
+ "libc",
+ "system-deps 6.2.2",
+ "winapi",
+]
+
+[[package]]
+name = "gio-sys"
+version = "0.21.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "171ed2f6dd927abbe108cfd9eebff2052c335013f5879d55bab0dc1dee19b706"
+dependencies = [
+ "glib-sys 0.21.2",
+ "gobject-sys 0.21.2",
+ "libc",
+ "system-deps 7.0.5",
+ "windows-sys 0.61.0",
+]
+
[[package]]
name = "gl_generator"
version = "0.14.0"
@@ -2059,18 +2249,183 @@ dependencies = [
"serde",
]
+[[package]]
+name = "glib"
+version = "0.18.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5"
+dependencies = [
+ "bitflags 2.9.4",
+ "futures-channel",
+ "futures-core",
+ "futures-executor",
+ "futures-task",
+ "futures-util",
+ "gio-sys 0.18.1",
+ "glib-macros 0.18.5",
+ "glib-sys 0.18.1",
+ "gobject-sys 0.18.0",
+ "libc",
+ "memchr",
+ "once_cell",
+ "smallvec",
+ "thiserror 1.0.69",
+]
+
+[[package]]
+name = "glib"
+version = "0.21.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e1f2cbc4577536c849335878552f42086bfd25a8dcd6f54a18655cf818b20c8f"
+dependencies = [
+ "bitflags 2.9.4",
+ "futures-channel",
+ "futures-core",
+ "futures-executor",
+ "futures-task",
+ "futures-util",
+ "gio-sys 0.21.2",
+ "glib-macros 0.21.2",
+ "glib-sys 0.21.2",
+ "gobject-sys 0.21.2",
+ "libc",
+ "memchr",
+ "smallvec",
+]
+
+[[package]]
+name = "glib-macros"
+version = "0.18.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0bb0228f477c0900c880fd78c8759b95c7636dbd7842707f49e132378aa2acdc"
+dependencies = [
+ "heck 0.4.1",
+ "proc-macro-crate 2.0.2",
+ "proc-macro-error",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.106",
+]
+
+[[package]]
+name = "glib-macros"
+version = "0.21.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "55eda916eecdae426d78d274a17b48137acdca6fba89621bd3705f2835bc719f"
+dependencies = [
+ "heck 0.5.0",
+ "proc-macro-crate 3.4.0",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.106",
+]
+
+[[package]]
+name = "glib-sys"
+version = "0.18.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898"
+dependencies = [
+ "libc",
+ "system-deps 6.2.2",
+]
+
+[[package]]
+name = "glib-sys"
+version = "0.21.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d09d3d0fddf7239521674e57b0465dfbd844632fec54f059f7f56112e3f927e1"
+dependencies = [
+ "libc",
+ "system-deps 7.0.5",
+]
+
[[package]]
name = "glob"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
+[[package]]
+name = "gobject-sys"
+version = "0.18.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44"
+dependencies = [
+ "glib-sys 0.18.1",
+ "libc",
+ "system-deps 6.2.2",
+]
+
+[[package]]
+name = "gobject-sys"
+version = "0.21.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "538e41d8776173ec107e7b0f2aceced60abc368d7e1d81c1f0e2ecd35f59080d"
+dependencies = [
+ "glib-sys 0.21.2",
+ "libc",
+ "system-deps 7.0.5",
+]
+
[[package]]
name = "grid"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12101ecc8225ea6d675bc70263074eab6169079621c2186fe0c66590b2df9681"
+[[package]]
+name = "gtk"
+version = "0.18.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd56fb197bfc42bd5d2751f4f017d44ff59fbb58140c6b49f9b3b2bdab08506a"
+dependencies = [
+ "atk",
+ "cairo-rs",
+ "field-offset",
+ "futures-channel",
+ "gdk",
+ "gdk-pixbuf",
+ "gio 0.18.4",
+ "glib 0.18.5",
+ "gtk-sys",
+ "gtk3-macros",
+ "libc",
+ "pango",
+ "pkg-config",
+]
+
+[[package]]
+name = "gtk-sys"
+version = "0.18.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f29a1c21c59553eb7dd40e918be54dccd60c52b049b75119d5d96ce6b624414"
+dependencies = [
+ "atk-sys",
+ "cairo-sys-rs",
+ "gdk-pixbuf-sys",
+ "gdk-sys",
+ "gio-sys 0.18.1",
+ "glib-sys 0.18.1",
+ "gobject-sys 0.18.0",
+ "libc",
+ "pango-sys",
+ "system-deps 6.2.2",
+]
+
+[[package]]
+name = "gtk3-macros"
+version = "0.18.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "52ff3c5b21f14f0736fed6dcfc0bfb4225ebf5725f3c0209edeec181e4d73e9d"
+dependencies = [
+ "proc-macro-crate 1.3.1",
+ "proc-macro-error",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.106",
+]
+
[[package]]
name = "half"
version = "2.6.0"
@@ -2688,7 +3043,7 @@ dependencies = [
"libspa-sys",
"nix 0.27.1",
"nom",
- "system-deps",
+ "system-deps 6.2.2",
]
[[package]]
@@ -2698,7 +3053,7 @@ source = "git+https://gitlab.freedesktop.org/galister/pipewire-rs.git#ba32202c3c
dependencies = [
"bindgen 0.69.5",
"cc",
- "system-deps",
+ "system-deps 6.2.2",
]
[[package]]
@@ -3113,7 +3468,7 @@ version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d"
dependencies = [
- "proc-macro-crate",
+ "proc-macro-crate 3.4.0",
"proc-macro2",
"quote",
"syn 2.0.106",
@@ -3540,6 +3895,31 @@ dependencies = [
"ttf-parser 0.25.1",
]
+[[package]]
+name = "pango"
+version = "0.18.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7ca27ec1eb0457ab26f3036ea52229edbdb74dee1edd29063f5b9b010e7ebee4"
+dependencies = [
+ "gio 0.18.4",
+ "glib 0.18.5",
+ "libc",
+ "once_cell",
+ "pango-sys",
+]
+
+[[package]]
+name = "pango-sys"
+version = "0.18.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "436737e391a843e5933d6d9aa102cb126d501e815b83601365a948a518555dc5"
+dependencies = [
+ "glib-sys 0.18.1",
+ "gobject-sys 0.18.0",
+ "libc",
+ "system-deps 6.2.2",
+]
+
[[package]]
name = "parking"
version = "2.2.1"
@@ -3721,7 +4101,7 @@ source = "git+https://gitlab.freedesktop.org/galister/pipewire-rs.git#ba32202c3c
dependencies = [
"bindgen 0.69.5",
"libspa-sys",
- "system-deps",
+ "system-deps 6.2.2",
]
[[package]]
@@ -3804,6 +4184,26 @@ dependencies = [
"syn 2.0.106",
]
+[[package]]
+name = "proc-macro-crate"
+version = "1.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919"
+dependencies = [
+ "once_cell",
+ "toml_edit 0.19.15",
+]
+
+[[package]]
+name = "proc-macro-crate"
+version = "2.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b00f26d3400549137f92511a46ac1cd8ce37cb5598a96d382381458b992a5d24"
+dependencies = [
+ "toml_datetime 0.6.3",
+ "toml_edit 0.20.2",
+]
+
[[package]]
name = "proc-macro-crate"
version = "3.4.0"
@@ -4020,7 +4420,7 @@ dependencies = [
"rand 0.8.5",
"rand_chacha 0.3.1",
"simd_helpers",
- "system-deps",
+ "system-deps 6.2.2",
"thiserror 1.0.69",
"v_frame",
"wasm-bindgen",
@@ -4848,10 +5248,23 @@ version = "6.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349"
dependencies = [
- "cfg-expr",
+ "cfg-expr 0.15.8",
"heck 0.5.0",
"pkg-config",
- "toml 0.8.23",
+ "toml 0.8.2",
+ "version-compare",
+]
+
+[[package]]
+name = "system-deps"
+version = "7.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e4be53aa0cba896d2dc615bd42bbc130acdcffa239e0a2d965ea5b3b2a86ffdb"
+dependencies = [
+ "cfg-expr 0.20.3",
+ "heck 0.5.0",
+ "pkg-config",
+ "toml 0.8.2",
"version-compare",
]
@@ -4873,6 +5286,12 @@ version = "0.12.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
+[[package]]
+name = "target-lexicon"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e502f78cdbb8ba4718f566c418c52bc729126ffd16baee5baa718cf25dd5a69a"
+
[[package]]
name = "tempfile"
version = "3.22.0"
@@ -5037,14 +5456,14 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "toml"
-version = "0.8.23"
+version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362"
+checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d"
dependencies = [
"serde",
"serde_spanned 0.6.9",
- "toml_datetime 0.6.11",
- "toml_edit 0.22.27",
+ "toml_datetime 0.6.3",
+ "toml_edit 0.20.2",
]
[[package]]
@@ -5057,14 +5476,14 @@ dependencies = [
"serde_spanned 1.0.2",
"toml_datetime 0.7.2",
"toml_parser",
- "winnow",
+ "winnow 0.7.13",
]
[[package]]
name = "toml_datetime"
-version = "0.6.11"
+version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c"
+checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b"
dependencies = [
"serde",
]
@@ -5080,15 +5499,26 @@ dependencies = [
[[package]]
name = "toml_edit"
-version = "0.22.27"
+version = "0.19.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a"
+checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
+dependencies = [
+ "indexmap 2.11.4",
+ "toml_datetime 0.6.3",
+ "winnow 0.5.40",
+]
+
+[[package]]
+name = "toml_edit"
+version = "0.20.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338"
dependencies = [
"indexmap 2.11.4",
"serde",
"serde_spanned 0.6.9",
- "toml_datetime 0.6.11",
- "winnow",
+ "toml_datetime 0.6.3",
+ "winnow 0.5.40",
]
[[package]]
@@ -5100,7 +5530,7 @@ dependencies = [
"indexmap 2.11.4",
"toml_datetime 0.7.2",
"toml_parser",
- "winnow",
+ "winnow 0.7.13",
]
[[package]]
@@ -5109,7 +5539,7 @@ version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4cf893c33be71572e0e9aa6dd15e6677937abd686b066eac3f8cd3531688a627"
dependencies = [
- "winnow",
+ "winnow 0.7.13",
]
[[package]]
@@ -5435,7 +5865,7 @@ version = "0.35.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1dc929c42c9336fd082079ac3ea30126e4a0dfe36fd2e2b3581303f7d140d20f"
dependencies = [
- "proc-macro-crate",
+ "proc-macro-crate 3.4.0",
"proc-macro2",
"quote",
"syn 2.0.106",
@@ -6282,6 +6712,15 @@ dependencies = [
"xkbcommon-dl",
]
+[[package]]
+name = "winnow"
+version = "0.5.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876"
+dependencies = [
+ "memchr",
+]
+
[[package]]
name = "winnow"
version = "0.7.13"
@@ -6586,7 +7025,7 @@ dependencies = [
"tracing",
"uds_windows",
"windows-sys 0.60.2",
- "winnow",
+ "winnow 0.7.13",
"zbus_macros",
"zbus_names",
"zvariant",
@@ -6598,7 +7037,7 @@ version = "5.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57e797a9c847ed3ccc5b6254e8bcce056494b375b511b3d6edcec0aeb4defaca"
dependencies = [
- "proc-macro-crate",
+ "proc-macro-crate 3.4.0",
"proc-macro2",
"quote",
"syn 2.0.106",
@@ -6615,7 +7054,7 @@ checksum = "7be68e64bf6ce8db94f63e72f0c7eb9a60d733f7e0499e628dfab0f84d6bcb97"
dependencies = [
"serde",
"static_assertions",
- "winnow",
+ "winnow 0.7.13",
"zvariant",
]
@@ -6724,7 +7163,7 @@ dependencies = [
"enumflags2",
"serde",
"url",
- "winnow",
+ "winnow 0.7.13",
"zvariant_derive",
"zvariant_utils",
]
@@ -6735,7 +7174,7 @@ version = "5.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6643fd0b26a46d226bd90d3f07c1b5321fe9bb7f04673cb37ac6d6883885b68e"
dependencies = [
- "proc-macro-crate",
+ "proc-macro-crate 3.4.0",
"proc-macro2",
"quote",
"syn 2.0.106",
@@ -6752,5 +7191,5 @@ dependencies = [
"quote",
"serde",
"syn 2.0.106",
- "winnow",
+ "winnow 0.7.13",
]
diff --git a/dash-frontend/Cargo.toml b/dash-frontend/Cargo.toml
index 9da4e9f7..b90d900d 100644
--- a/dash-frontend/Cargo.toml
+++ b/dash-frontend/Cargo.toml
@@ -10,3 +10,5 @@ glam = { workspace = true }
log = { workspace = true }
rust-embed = { workspace = true }
chrono = "0.4.42"
+gio = "0.21.2"
+gtk = "0.18.2"
diff --git a/dash-frontend/assets/gui/tab/apps.xml b/dash-frontend/assets/gui/tab/apps.xml
index 4dc42b74..d477a3c4 100644
--- a/dash-frontend/assets/gui/tab/apps.xml
+++ b/dash-frontend/assets/gui/tab/apps.xml
@@ -1,6 +1,19 @@
+
+
+
+
@@ -17,5 +30,12 @@
+
\ No newline at end of file
diff --git a/dash-frontend/src/lib.rs b/dash-frontend/src/lib.rs
index 198d5a19..16b946a6 100644
--- a/dash-frontend/src/lib.rs
+++ b/dash-frontend/src/lib.rs
@@ -8,7 +8,7 @@ use wgui::{
globals::WguiGlobals,
i18n::Translation,
layout::{LayoutParams, RcLayout, WidgetID},
- parser::{ParseDocumentParams, ParserState},
+ parser::{Fetchable, ParseDocumentParams, ParserState},
widget::label::WidgetLabel,
};
@@ -19,6 +19,7 @@ use crate::tab::{
mod assets;
mod tab;
+mod util;
mod various;
pub struct Frontend {
diff --git a/dash-frontend/src/tab/apps.rs b/dash-frontend/src/tab/apps.rs
index 771ad0b6..ea56f1de 100644
--- a/dash-frontend/src/tab/apps.rs
+++ b/dash-frontend/src/tab/apps.rs
@@ -1,10 +1,23 @@
-use wgui::parser::{ParseDocumentParams, ParserState};
+use std::{collections::HashMap, rc::Rc};
-use crate::tab::{Tab, TabParams, TabType};
+use wgui::{
+ components::{self, button::ComponentButton},
+ layout::WidgetPair,
+ parser::{Fetchable, ParseDocumentParams, ParserData, ParserState},
+ taffy::{self, Dimension, prelude::length},
+};
+
+use crate::{
+ tab::{Tab, TabParams, TabType},
+ util::{self, desktop_finder::DesktopEntry},
+};
pub struct TabApps {
#[allow(dead_code)]
pub state: ParserState,
+
+ entries: Vec,
+ app_list: AppList,
}
impl Tab for TabApps {
@@ -13,19 +26,106 @@ impl Tab for TabApps {
}
}
+#[derive(Default)]
+struct AppList {
+ data: Vec,
+}
+
impl TabApps {
- pub fn new(params: TabParams) -> anyhow::Result {
- let state = wgui::parser::parse_from_assets(
- &ParseDocumentParams {
- globals: params.globals.clone(),
- path: "gui/tab/apps.xml",
- extra: Default::default(),
- },
- params.layout,
- params.listeners,
- params.parent_id,
+ pub fn new(mut tab_params: TabParams) -> anyhow::Result {
+ let doc_params = &ParseDocumentParams {
+ globals: tab_params.globals.clone(),
+ path: "gui/tab/apps.xml",
+ extra: Default::default(),
+ };
+
+ let mut state = wgui::parser::parse_from_assets(
+ doc_params,
+ tab_params.layout,
+ tab_params.listeners,
+ tab_params.parent_id,
)?;
- Ok(Self { state })
+ gtk::init()?;
+
+ let entries = util::desktop_finder::find_entries()?;
+
+ let app_list_parent = state.fetch_widget(&tab_params.layout.state, "app_list_parent")?;
+
+ let mut app_list = AppList::default();
+ app_list.mount_entries(&entries, &mut state, doc_params, &mut tab_params, &app_list_parent)?;
+
+ Ok(Self {
+ app_list,
+ state,
+ entries,
+ })
+ }
+}
+
+impl AppList {
+ fn mount_entry(
+ &mut self,
+ parser_state: &mut ParserState,
+ doc_params: &ParseDocumentParams,
+ params: &mut TabParams,
+ list_parent: &WidgetPair,
+ entry: &DesktopEntry,
+ ) -> anyhow::Result<()> {
+ let mut template_params = HashMap::new();
+
+ // entry icon
+ template_params.insert(
+ Rc::from("src_ext"),
+ entry
+ .icon_path
+ .as_ref()
+ .map_or_else(|| Rc::from(""), |icon_path| Rc::from(icon_path.as_str())),
+ );
+
+ // entry fallback (question mark) icon
+ template_params.insert(
+ Rc::from("src"),
+ if entry.icon_path.is_none() {
+ Rc::from("dashboard/terminal.svg")
+ } else {
+ Rc::from("")
+ },
+ );
+
+ template_params.insert(Rc::from("name"), Rc::from(entry.app_name.as_str()));
+
+ let data = parser_state.parse_template(
+ doc_params,
+ "AppEntry",
+ params.layout,
+ params.listeners,
+ list_parent.id,
+ template_params,
+ )?;
+
+ let button = data.fetch_component_as::("button")?;
+ button.on_click(Box::new(move |common, evt| {
+ log::info!("click");
+ Ok(())
+ }));
+
+ self.data.push(data);
+
+ Ok(())
+ }
+
+ fn mount_entries(
+ &mut self,
+ entries: &[DesktopEntry],
+ parser_state: &mut ParserState,
+ doc_params: &ParseDocumentParams,
+ params: &mut TabParams,
+ list_parent: &WidgetPair,
+ ) -> anyhow::Result<()> {
+ for entry in entries {
+ self.mount_entry(parser_state, doc_params, params, list_parent, entry)?;
+ }
+ Ok(())
}
}
diff --git a/dash-frontend/src/tab/home.rs b/dash-frontend/src/tab/home.rs
index 38447114..0d90db5c 100644
--- a/dash-frontend/src/tab/home.rs
+++ b/dash-frontend/src/tab/home.rs
@@ -1,7 +1,7 @@
use wgui::{
components::button::ComponentButton,
i18n::Translation,
- parser::{ParseDocumentParams, ParserState},
+ parser::{Fetchable, ParseDocumentParams, ParserState},
widget::label::WidgetLabel,
};
diff --git a/dash-frontend/src/util/desktop_finder.rs b/dash-frontend/src/util/desktop_finder.rs
new file mode 100644
index 00000000..42327a47
--- /dev/null
+++ b/dash-frontend/src/util/desktop_finder.rs
@@ -0,0 +1,129 @@
+use gio::prelude::{AppInfoExt, IconExt};
+use gtk::traits::IconThemeExt;
+
+#[derive(Debug)]
+pub struct DesktopEntry {
+ pub exec_path: String,
+ pub exec_args: Vec,
+ pub app_name: String,
+ pub icon_path: Option,
+ pub categories: Vec,
+}
+
+pub struct EntrySearchCell {
+ pub exec_path: String,
+ pub exec_args: Vec,
+ pub app_name: String,
+ pub icon_name: Option,
+ pub categories: Vec,
+}
+
+const CMD_BLACKLIST: [&str; 1] = [
+ "lsp-plugins", // LSP Plugins collection. They clutter the application list a lot
+];
+
+const CATEGORY_TYPE_BLACKLIST: [&str; 5] = ["GTK", "Qt", "X-XFCE", "X-Bluetooth", "ConsoleOnly"];
+
+pub fn find_entries() -> anyhow::Result> {
+ let Some(icon_theme) = gtk::IconTheme::default() else {
+ anyhow::bail!("Failed to get current icon theme information");
+ };
+
+ let mut res = Vec::::new();
+
+ let info = gio::AppInfo::all();
+
+ log::debug!("app entry count {}", info.len());
+
+ 'outer: for app_entry in info {
+ let Some(app_entry_id) = app_entry.id() else {
+ log::warn!(
+ "failed to get desktop entry ID for application named \"{}\"",
+ app_entry.name()
+ );
+ continue;
+ };
+
+ let Some(desktop_app) = gio::DesktopAppInfo::new(&app_entry_id) else {
+ log::warn!(
+ "failed to find desktop app file from application named \"{}\"",
+ app_entry.name()
+ );
+ continue;
+ };
+
+ if desktop_app.is_nodisplay() || desktop_app.is_hidden() {
+ continue;
+ }
+
+ let Some(cmd) = desktop_app.commandline() else {
+ continue;
+ };
+
+ let name = String::from(desktop_app.name());
+
+ let exec = String::from(cmd.to_string_lossy());
+
+ for blacklisted in CMD_BLACKLIST {
+ if exec.contains(blacklisted) {
+ continue 'outer;
+ }
+ }
+
+ let (exec_path, exec_args) = match exec.split_once(" ") {
+ Some((left, right)) => (
+ String::from(left),
+ right
+ .split(" ")
+ .filter(|arg| !arg.starts_with('%')) // exclude arguments like "%f"
+ .map(String::from)
+ .collect(),
+ ),
+ None => (exec, Vec::new()),
+ };
+
+ let icon_path = match desktop_app.icon() {
+ Some(icon) => {
+ if let Some(icon_str) = icon.to_string() {
+ if let Some(s_icon) = icon_theme.lookup_icon(&icon_str, 128, gtk::IconLookupFlags::GENERIC_FALLBACK) {
+ s_icon.filename().map(|p| String::from(p.to_string_lossy()))
+ } else {
+ None
+ }
+ } else {
+ None
+ }
+ }
+ None => None,
+ };
+
+ let categories: Vec = match desktop_app.categories() {
+ Some(categories) => categories
+ .split(";")
+ .filter(|s| !s.is_empty())
+ .filter(|s| {
+ for b in CATEGORY_TYPE_BLACKLIST {
+ if *s == b {
+ return false;
+ }
+ }
+ true
+ })
+ .map(String::from)
+ .collect(),
+ None => Vec::new(),
+ };
+
+ let entry = DesktopEntry {
+ app_name: name,
+ categories,
+ exec_path,
+ exec_args,
+ icon_path,
+ };
+
+ res.push(entry);
+ }
+
+ Ok(res)
+}
diff --git a/dash-frontend/src/util/mod.rs b/dash-frontend/src/util/mod.rs
new file mode 100644
index 00000000..b37699fc
--- /dev/null
+++ b/dash-frontend/src/util/mod.rs
@@ -0,0 +1 @@
+pub mod desktop_finder;
diff --git a/uidev/src/main.rs b/uidev/src/main.rs
index fc6fa4d0..02ff8f5b 100644
--- a/uidev/src/main.rs
+++ b/uidev/src/main.rs
@@ -222,6 +222,11 @@ fn main() -> Result<(), Box> {
if event.state == ElementState::Pressed {
if event.physical_key == PhysicalKey::Code(KeyCode::F10) {
debug_draw_enabled = !debug_draw_enabled;
+ if debug_draw_enabled {
+ log::info!(
+ "Debug draw enabled\n\tAqua: widget boundary\n\tMagenta: Scissoring (separate render pass)"
+ );
+ }
testbed.layout().borrow_mut().mark_redraw();
}
@@ -336,10 +341,14 @@ fn main() -> Result<(), Box> {
};
let primitives = wgui::drawing::draw(&draw_params).unwrap();
- render_context
+ let draw_result = render_context
.draw(&mut shared_context, &mut cmd_buf, &primitives)
.unwrap();
+ if debug_draw_enabled {
+ log::debug!("pass count: {}", draw_result.pass_count);
+ }
+
cmd_buf.end_rendering().unwrap();
let cmd_buf = cmd_buf.build().unwrap();
diff --git a/uidev/src/testbed/testbed_generic.rs b/uidev/src/testbed/testbed_generic.rs
index f86f2123..d0c4b1bf 100644
--- a/uidev/src/testbed/testbed_generic.rs
+++ b/uidev/src/testbed/testbed_generic.rs
@@ -16,7 +16,7 @@ use wgui::{
globals::WguiGlobals,
i18n::Translation,
layout::{LayoutParams, RcLayout, Widget},
- parser::{ParseDocumentExtra, ParseDocumentParams, ParserState},
+ parser::{Fetchable, ParseDocumentExtra, ParseDocumentParams, ParserState},
widget::{label::WidgetLabel, rectangle::WidgetRectangle},
};
diff --git a/wgui/src/components/button.rs b/wgui/src/components/button.rs
index da0911f8..6a3939f1 100644
--- a/wgui/src/components/button.rs
+++ b/wgui/src/components/button.rs
@@ -1,5 +1,5 @@
use std::{cell::RefCell, rc::Rc};
-use taffy::{AlignItems, JustifyContent, prelude::length};
+use taffy::{AlignItems, JustifyContent};
use crate::{
animation::{Animation, AnimationEasing},
@@ -18,7 +18,7 @@ use crate::{
};
pub struct Params {
- pub text: Translation,
+ pub text: Option, // if unset, label will not be populated
pub color: Option,
pub border_color: Option,
pub hover_border_color: Option,
@@ -31,7 +31,7 @@ pub struct Params {
impl Default for Params {
fn default() -> Self {
Self {
- text: Translation::from_raw_text(""),
+ text: Some(Translation::from_raw_text("")),
color: None,
hover_color: None,
border_color: None,
@@ -232,7 +232,6 @@ pub fn construct(
// force-override style
style.align_items = Some(AlignItems::Center);
style.justify_content = Some(JustifyContent::Center);
- style.padding = length(1.0);
style.overflow.x = taffy::Overflow::Hidden;
style.overflow.y = taffy::Overflow::Hidden;
@@ -277,25 +276,30 @@ pub fn construct(
let light_text = (color.r + color.g + color.b) < 1.5;
- let (id_label, _node_label) = layout.add_child(
- id_rect,
- WidgetLabel::create(
- globals,
- WidgetLabelParams {
- content: params.text,
- style: TextStyle {
- weight: Some(FontWeight::Bold),
- color: Some(if light_text {
- Color::new(1.0, 1.0, 1.0, 1.0)
- } else {
- Color::new(0.0, 0.0, 0.0, 1.0)
- }),
- ..params.text_style
+ let id_label = if let Some(content) = params.text {
+ let (id_label, _node_label) = layout.add_child(
+ id_rect,
+ WidgetLabel::create(
+ globals,
+ WidgetLabelParams {
+ content,
+ style: TextStyle {
+ weight: Some(FontWeight::Bold),
+ color: Some(if light_text {
+ Color::new(1.0, 1.0, 1.0, 1.0)
+ } else {
+ Color::new(0.0, 0.0, 0.0, 1.0)
+ }),
+ ..params.text_style
+ },
},
- },
- ),
- Default::default(),
- )?;
+ ),
+ Default::default(),
+ )?;
+ id_label
+ } else {
+ WidgetID::default()
+ };
let data = Rc::new(Data {
id_label,
diff --git a/wgui/src/parser/component_button.rs b/wgui/src/parser/component_button.rs
index 9921ff49..b40f1f75 100644
--- a/wgui/src/parser/component_button.rs
+++ b/wgui/src/parser/component_button.rs
@@ -21,7 +21,7 @@ pub fn parse_component_button<'a, U1, U2>(
let mut hover_color: Option = None;
let mut hover_border_color: Option = None;
let mut round = WLength::Units(4.0);
- let mut translation = Translation::default();
+ let mut translation: Option = None;
let attribs: Vec<_> = iter_attribs(file, ctx, &node, false).collect();
let text_style = parse_text_style(&attribs);
@@ -30,10 +30,10 @@ pub fn parse_component_button<'a, U1, U2>(
for (key, value) in attribs {
match key.as_ref() {
"text" => {
- translation = Translation::from_raw_text(&value);
+ translation = Some(Translation::from_raw_text(&value));
}
"translation" => {
- translation = Translation::from_translation_key(&value);
+ translation = Some(Translation::from_translation_key(&value));
}
"round" => {
parse_round(&value, &mut round);
diff --git a/wgui/src/parser/mod.rs b/wgui/src/parser/mod.rs
index 0da414f1..af7c48cb 100644
--- a/wgui/src/parser/mod.rs
+++ b/wgui/src/parser/mod.rs
@@ -49,6 +49,11 @@ struct ParserFile {
template_parameters: HashMap, Rc>,
}
+/*
+ `components` could contain connected listener handles.
+ Do not drop them unless you don't need to handle any events,
+ including mouse-hover animations.
+*/
#[derive(Default, Clone)]
pub struct ParserData {
pub components_by_id: HashMap, ComponentWeak>,
@@ -60,6 +65,29 @@ pub struct ParserData {
macro_attribs: HashMap, MacroAttribs>,
}
+pub trait Fetchable {
+ /// Return a component by its string ID
+ fn fetch_component_by_id(&self, id: &str) -> anyhow::Result;
+
+ /// Return a component by the ID of the widget that owns it
+ fn fetch_component_by_widget_id(&self, widget_id: WidgetID) -> anyhow::Result;
+
+ /// Fetch a component by string ID and down‑cast it to a concrete component type `T` (see `components/mod.rs`)
+ fn fetch_component_as(&self, id: &str) -> anyhow::Result>;
+
+ /// Fetch a component by widget ID and down‑cast it to a concrete component type `T` (see `components/mod.rs`)
+ fn fetch_component_from_widget_id_as(&self, widget_id: WidgetID) -> anyhow::Result>;
+
+ /// Return a widget by its string ID
+ fn get_widget_id(&self, id: &str) -> anyhow::Result;
+
+ /// Retrieve the widget associated with a string ID, returning a `WidgetPair` (id and widget itself)
+ fn fetch_widget(&self, state: &LayoutState, id: &str) -> anyhow::Result;
+
+ /// Retrieve a widget by string ID and down‑cast its inner value to type `T` (see `widget/mod.rs`)
+ fn fetch_widget_as<'a, T: 'static>(&self, state: &'a LayoutState, id: &str) -> anyhow::Result>;
+}
+
impl ParserData {
fn take_results_from(&mut self, from: &mut Self) {
let ids = std::mem::take(&mut from.ids);
@@ -85,19 +113,9 @@ impl ParserData {
}
}
-/*
- WARNING: this struct could contain valid components with already bound listener handles.
- Make sure to store them somewhere in your code.
-*/
-#[derive(Default)]
-pub struct ParserState {
- pub data: ParserData,
- pub path: PathBuf,
-}
-
-impl ParserState {
- pub fn fetch_component_by_id(&self, id: &str) -> anyhow::Result {
- let Some(weak) = self.data.components_by_id.get(id) else {
+impl Fetchable for ParserData {
+ fn fetch_component_by_id(&self, id: &str) -> anyhow::Result {
+ let Some(weak) = self.components_by_id.get(id) else {
anyhow::bail!("Component by ID \"{id}\" doesn't exist");
};
@@ -108,8 +126,8 @@ impl ParserState {
Ok(Component(component))
}
- pub fn fetch_component_by_widget_id(&self, widget_id: WidgetID) -> anyhow::Result {
- let Some(weak) = self.data.components_by_widget_id.get(&widget_id) else {
+ fn fetch_component_by_widget_id(&self, widget_id: WidgetID) -> anyhow::Result {
+ let Some(weak) = self.components_by_widget_id.get(&widget_id) else {
anyhow::bail!("Component by widget ID \"{widget_id:?}\" doesn't exist");
};
@@ -120,37 +138,36 @@ impl ParserState {
Ok(Component(component))
}
- pub fn fetch_component_as(&self, id: &str) -> anyhow::Result> {
+ fn fetch_component_as(&self, id: &str) -> anyhow::Result> {
let component = self.fetch_component_by_id(id)?;
if !(*component.0).as_any().is::() {
anyhow::bail!("fetch_component_as({id}): type not matching");
}
- // safety: we already checked it above, should be safe to directly cast it
+ // safety: we just checked the type
unsafe { Ok(Rc::from_raw(Rc::into_raw(component.0).cast())) }
}
- pub fn fetch_component_from_widget_id_as(&self, widget_id: WidgetID) -> anyhow::Result> {
+ fn fetch_component_from_widget_id_as(&self, widget_id: WidgetID) -> anyhow::Result> {
let component = self.fetch_component_by_widget_id(widget_id)?;
if !(*component.0).as_any().is::() {
anyhow::bail!("fetch_component_by_widget_id({widget_id:?}): type not matching");
}
- // safety: we already checked it above, should be safe to directly cast it
+ // safety: we just checked the type
unsafe { Ok(Rc::from_raw(Rc::into_raw(component.0).cast())) }
}
- pub fn get_widget_id(&self, id: &str) -> anyhow::Result {
- match self.data.ids.get(id) {
+ fn get_widget_id(&self, id: &str) -> anyhow::Result {
+ match self.ids.get(id) {
Some(id) => Ok(*id),
None => anyhow::bail!("Widget by ID \"{id}\" doesn't exist"),
}
}
- // returns widget and its id at once
- pub fn fetch_widget(&self, state: &LayoutState, id: &str) -> anyhow::Result {
+ fn fetch_widget(&self, state: &LayoutState, id: &str) -> anyhow::Result {
let widget_id = self.get_widget_id(id)?;
let widget = state
.widgets
@@ -162,7 +179,7 @@ impl ParserState {
})
}
- pub fn fetch_widget_as<'a, T: 'static>(&self, state: &'a LayoutState, id: &str) -> anyhow::Result> {
+ fn fetch_widget_as<'a, T: 'static>(&self, state: &'a LayoutState, id: &str) -> anyhow::Result> {
let widget_id = self.get_widget_id(id)?;
let widget = state
.widgets
@@ -175,8 +192,23 @@ impl ParserState {
Ok(casted)
}
+}
- pub fn process_template(
+/*
+ WARNING: this struct could contain valid components with already bound listener handles.
+ Make sure to store them somewhere in your code.
+*/
+#[derive(Default)]
+pub struct ParserState {
+ pub data: ParserData,
+ pub path: PathBuf,
+}
+
+impl ParserState {
+ /// This function is suitable in cases if you don't want to pollute main parser state with dynamic IDs
+ /// Use `instantiate_template` instead unless you want to handle `components` results yourself.
+ /// Make sure not to drop them if you want to have your listener handles valid
+ pub fn parse_template(
&mut self,
doc_params: &ParseDocumentParams,
template_name: &str,
@@ -184,7 +216,7 @@ impl ParserState {
listeners: &mut EventListenerCollection,
widget_id: WidgetID,
template_parameters: HashMap, Rc>,
- ) -> anyhow::Result<()> {
+ ) -> anyhow::Result {
let Some(template) = self.data.templates.get(template_name) else {
anyhow::bail!("no template named \"{template_name}\" found");
};
@@ -204,13 +236,64 @@ impl ParserState {
};
parse_widget_other_internal(&template.clone(), template_parameters, &file, &mut ctx, widget_id)?;
+ Ok(ctx.data_local)
+ }
- self.data.take_results_from(&mut ctx.data_local);
+ /// Instantinate template by saving all the results into the main `ParserState`
+ pub fn instantiate_template(
+ &mut self,
+ doc_params: &ParseDocumentParams,
+ template_name: &str,
+ layout: &mut Layout,
+ listeners: &mut EventListenerCollection,
+ widget_id: WidgetID,
+ template_parameters: HashMap, Rc>,
+ ) -> anyhow::Result<()> {
+ let mut data_local = self.parse_template(
+ doc_params,
+ template_name,
+ layout,
+ listeners,
+ widget_id,
+ template_parameters,
+ )?;
+ self.data.take_results_from(&mut data_local);
Ok(())
}
}
+// convenience wrapper functions for `data`
+impl Fetchable for ParserState {
+ fn fetch_component_by_id(&self, id: &str) -> anyhow::Result {
+ self.data.fetch_component_by_id(id)
+ }
+
+ fn fetch_component_by_widget_id(&self, widget_id: WidgetID) -> anyhow::Result {
+ self.data.fetch_component_by_widget_id(widget_id)
+ }
+
+ fn fetch_component_as(&self, id: &str) -> anyhow::Result> {
+ self.data.fetch_component_as(id)
+ }
+
+ fn fetch_component_from_widget_id_as(&self, widget_id: WidgetID) -> anyhow::Result> {
+ self.data.fetch_component_from_widget_id_as(widget_id)
+ }
+
+ fn get_widget_id(&self, id: &str) -> anyhow::Result {
+ self.data.get_widget_id(id)
+ }
+
+ fn fetch_widget(&self, state: &LayoutState, id: &str) -> anyhow::Result {
+ self.data.fetch_widget(state, id)
+ }
+
+ fn fetch_widget_as<'a, T: 'static>(&self, state: &'a LayoutState, id: &str) -> anyhow::Result> {
+ self.data.fetch_widget_as(state, id)
+ }
+}
+
#[derive(Debug, Clone)]
struct MacroAttribs {
attribs: HashMap, Rc>,
diff --git a/wgui/src/parser/widget_sprite.rs b/wgui/src/parser/widget_sprite.rs
index cb18c918..72902f71 100644
--- a/wgui/src/parser/widget_sprite.rs
+++ b/wgui/src/parser/widget_sprite.rs
@@ -1,9 +1,6 @@
use crate::{
layout::WidgetID,
- parser::{
- ParserContext, ParserFile, iter_attribs, parse_children, parse_widget_universal,
- style::parse_style,
- },
+ parser::{ParserContext, ParserFile, iter_attribs, parse_children, parse_widget_universal, style::parse_style},
renderer_vk::text::custom_glyph::{CustomGlyphContent, CustomGlyphData},
widget::sprite::{WidgetSprite, WidgetSpriteParams},
};
@@ -24,17 +21,18 @@ pub fn parse_widget_sprite<'a, U1, U2>(
for (key, value) in attribs {
match key.as_ref() {
"src" => {
- glyph =
- match CustomGlyphContent::from_assets(&mut ctx.layout.state.globals.assets(), &value) {
+ if !value.is_empty() {
+ glyph = match CustomGlyphContent::from_assets(&mut ctx.layout.state.globals.assets(), &value) {
Ok(glyph) => Some(glyph),
Err(e) => {
log::warn!("failed to load {value}: {e}");
None
}
}
+ }
}
"src_ext" => {
- if std::fs::exists(value.as_ref()).unwrap_or(false) {
+ if !value.is_empty() && std::fs::exists(value.as_ref()).unwrap_or(false) {
glyph = CustomGlyphContent::from_file(&value).ok();
}
}
@@ -55,9 +53,7 @@ pub fn parse_widget_sprite<'a, U1, U2>(
log::warn!("No source for sprite node!");
}
- let (new_id, _) = ctx
- .layout
- .add_child(parent_id, WidgetSprite::create(params), style)?;
+ let (new_id, _) = ctx.layout.add_child(parent_id, WidgetSprite::create(params), style)?;
parse_widget_universal(file, ctx, node, new_id);
parse_children(file, ctx, node, new_id)?;
diff --git a/wgui/src/renderer_vk/context.rs b/wgui/src/renderer_vk/context.rs
index 70728847..d4b084b3 100644
--- a/wgui/src/renderer_vk/context.rs
+++ b/wgui/src/renderer_vk/context.rs
@@ -160,6 +160,10 @@ pub struct Context {
empty_text: Rc>,
}
+pub struct ContextDrawResult {
+ pub pass_count: u32,
+}
+
impl Context {
pub fn new(shared: &mut SharedContext, pixel_scale: f32) -> anyhow::Result {
let viewport = Viewport::new(&shared.gfx)?;
@@ -216,7 +220,7 @@ impl Context {
shared: &mut SharedContext,
cmd_buf: &mut GfxCommandBuffer,
primitives: &[drawing::RenderPrimitive],
- ) -> anyhow::Result<()> {
+ ) -> anyhow::Result {
self.dirty = false;
let atlas = shared.atlas_map.get_mut(self.shared_ctx_key).unwrap();
@@ -279,12 +283,14 @@ impl Context {
}
}
- log::info!("count {}", passes.len());
+ let res = ContextDrawResult {
+ pass_count: passes.len() as u32,
+ };
for mut pass in passes {
pass.submit(&shared.gfx, &mut self.viewport, cmd_buf, &mut atlas.text_atlas)?;
}
- Ok(())
+ Ok(res)
}
}
diff --git a/wlx-overlay-s/src/backend/wayvr/display.rs b/wlx-overlay-s/src/backend/wayvr/display.rs
index 2e9fb06b..29777f27 100644
--- a/wlx-overlay-s/src/backend/wayvr/display.rs
+++ b/wlx-overlay-s/src/backend/wayvr/display.rs
@@ -308,7 +308,7 @@ impl Display {
}
pub fn tick_render(&mut self, renderer: &mut GlesRenderer, time_ms: u64) -> anyhow::Result<()> {
- renderer.bind(&mut self.gles_texture)?;
+ renderer.bind(self.gles_texture.clone())?;
let size = Size::from((i32::from(self.width), i32::from(self.height)));
let damage: Rectangle = Rectangle::from_size(size);
diff --git a/wlx-overlay-s/src/overlays/keyboard/builder.rs b/wlx-overlay-s/src/overlays/keyboard/builder.rs
index 7ed77391..e68ba0f3 100644
--- a/wlx-overlay-s/src/overlays/keyboard/builder.rs
+++ b/wlx-overlay-s/src/overlays/keyboard/builder.rs
@@ -6,6 +6,7 @@ use wgui::{
drawing::Color,
event::{self, CallbackMetadata, EventListenerKind},
layout::LayoutParams,
+ parser::Fetchable,
renderer_vk::util,
taffy::{self, prelude::length},
widget::{
@@ -163,7 +164,7 @@ where
}
let template_key = format!("Key{:?}", key.cap_type);
- gui_state_key.process_template(
+ gui_state_key.instantiate_template(
&parse_doc_params,
&template_key,
&mut panel.layout,
diff --git a/wlx-overlay-s/src/overlays/watch.rs b/wlx-overlay-s/src/overlays/watch.rs
index 0086acfb..0ffa50b9 100644
--- a/wlx-overlay-s/src/overlays/watch.rs
+++ b/wlx-overlay-s/src/overlays/watch.rs
@@ -39,8 +39,9 @@ where
let mut params: HashMap, Rc> = HashMap::new();
params.insert("display".into(), (idx + 1).to_string().into());
params.insert("handle".into(), handle.0.to_string().into());
- parser_state
- .process_template(doc_params, "Set", layout, listeners, widget, params)?;
+ parser_state.instantiate_template(
+ doc_params, "Set", layout, listeners, widget, params,
+ )?;
}
Ok(())
},