feat: app grid and icons
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -9,3 +9,6 @@ Cargo.lock
|
|||||||
# These are backup files generated by rustfmt
|
# These are backup files generated by rustfmt
|
||||||
**/*.rs.bk
|
**/*.rs.bk
|
||||||
Cargo.lock
|
Cargo.lock
|
||||||
|
|
||||||
|
*.blend1
|
||||||
|
.vscode
|
||||||
423
Cargo.lock
generated
423
Cargo.lock
generated
@@ -8,6 +8,15 @@ version = "0.11.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3"
|
checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "addr2line"
|
||||||
|
version = "0.19.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97"
|
||||||
|
dependencies = [
|
||||||
|
"gimli",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "adler"
|
name = "adler"
|
||||||
version = "1.0.2"
|
version = "1.0.2"
|
||||||
@@ -25,15 +34,6 @@ dependencies = [
|
|||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "aho-corasick"
|
|
||||||
version = "0.7.20"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac"
|
|
||||||
dependencies = [
|
|
||||||
"memchr",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aliasable"
|
name = "aliasable"
|
||||||
version = "0.1.3"
|
version = "0.1.3"
|
||||||
@@ -62,9 +62,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.66"
|
version = "1.0.68"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6"
|
checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arrayref"
|
name = "arrayref"
|
||||||
@@ -84,6 +84,21 @@ version = "1.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "backtrace"
|
||||||
|
version = "0.3.67"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca"
|
||||||
|
dependencies = [
|
||||||
|
"addr2line",
|
||||||
|
"cc",
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"miniz_oxide 0.6.2",
|
||||||
|
"object",
|
||||||
|
"rustc-demangle",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "base64"
|
name = "base64"
|
||||||
version = "0.13.1"
|
version = "0.13.1"
|
||||||
@@ -102,21 +117,6 @@ version = "1.3.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "buildstructor"
|
|
||||||
version = "0.5.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "32e1c120c6c832d6101eeb3170eeaeec6aca98759b59c37a1f78b3becfa482a5"
|
|
||||||
dependencies = [
|
|
||||||
"lazy_static",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"str_inflector",
|
|
||||||
"syn",
|
|
||||||
"thiserror",
|
|
||||||
"try_match",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bumpalo"
|
name = "bumpalo"
|
||||||
version = "3.11.1"
|
version = "3.11.1"
|
||||||
@@ -168,6 +168,43 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap"
|
||||||
|
version = "4.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d8d93d855ce6a0aa87b8473ef9169482f40abaa2e9e0993024c35c902cbd5920"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"clap_derive",
|
||||||
|
"clap_lex",
|
||||||
|
"is-terminal",
|
||||||
|
"once_cell",
|
||||||
|
"strsim",
|
||||||
|
"termcolor",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_derive"
|
||||||
|
version = "4.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "684a277d672e91966334af371f1a7b5833f9aa00b07c84e92fbce95e00208ce8"
|
||||||
|
dependencies = [
|
||||||
|
"heck",
|
||||||
|
"proc-macro-error",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_lex"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "783fe232adfca04f90f56201b26d79682d4cd2625e0bc7290b95123afe558ade"
|
||||||
|
dependencies = [
|
||||||
|
"os_str_bytes",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cluFlock"
|
name = "cluFlock"
|
||||||
version = "1.2.7"
|
version = "1.2.7"
|
||||||
@@ -188,6 +225,21 @@ dependencies = [
|
|||||||
"unicode-width",
|
"unicode-width",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "color-eyre"
|
||||||
|
version = "0.6.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5a667583cca8c4f8436db8de46ea8233c42a7d9ae424a82d338f2e4675229204"
|
||||||
|
dependencies = [
|
||||||
|
"backtrace",
|
||||||
|
"color-spantrace",
|
||||||
|
"eyre",
|
||||||
|
"indenter",
|
||||||
|
"once_cell",
|
||||||
|
"owo-colors",
|
||||||
|
"tracing-error",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "color-maps"
|
name = "color-maps"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -210,6 +262,18 @@ dependencies = [
|
|||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "color-spantrace"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1ba75b3d9449ecdccb27ecbc479fdc0b87fa2dd43d2f8298f9bf0e59aacc8dce"
|
||||||
|
dependencies = [
|
||||||
|
"once_cell",
|
||||||
|
"owo-colors",
|
||||||
|
"tracing-core",
|
||||||
|
"tracing-error",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "color_quant"
|
name = "color_quant"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
@@ -330,6 +394,15 @@ version = "0.2.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8d7439c3735f405729d52c3fbbe4de140eaf938a1fe47d227c27f8254d4302a5"
|
checksum = "8d7439c3735f405729d52c3fbbe4de140eaf938a1fe47d227c27f8254d4302a5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "directories"
|
||||||
|
version = "4.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f51c5d4ddabd36886dd3e1438cb358cdcb0d7c499cb99cb4ac2e38e18b5cb210"
|
||||||
|
dependencies = [
|
||||||
|
"dirs-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dirs"
|
name = "dirs"
|
||||||
version = "4.0.0"
|
version = "4.0.0"
|
||||||
@@ -356,6 +429,27 @@ version = "1.8.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
|
checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "errno"
|
||||||
|
version = "0.2.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1"
|
||||||
|
dependencies = [
|
||||||
|
"errno-dragonfly",
|
||||||
|
"libc",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "errno-dragonfly"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "exr"
|
name = "exr"
|
||||||
version = "1.5.2"
|
version = "1.5.2"
|
||||||
@@ -371,6 +465,16 @@ dependencies = [
|
|||||||
"threadpool",
|
"threadpool",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "eyre"
|
||||||
|
version = "0.6.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb"
|
||||||
|
dependencies = [
|
||||||
|
"indenter",
|
||||||
|
"once_cell",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ez-pixmap"
|
name = "ez-pixmap"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
@@ -501,6 +605,12 @@ dependencies = [
|
|||||||
"weezl",
|
"weezl",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gimli"
|
||||||
|
version = "0.27.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dec7af912d60cdbd3677c1af9352ebae6fb8394d165568a2234df0fa00f87793"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "glam"
|
name = "glam"
|
||||||
version = "0.22.0"
|
version = "0.22.0"
|
||||||
@@ -525,6 +635,12 @@ dependencies = [
|
|||||||
"crunchy",
|
"crunchy",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "heck"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "hermit-abi"
|
||||||
version = "0.1.19"
|
version = "0.1.19"
|
||||||
@@ -534,6 +650,15 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hermit-abi"
|
||||||
|
version = "0.2.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iana-time-zone"
|
name = "iana-time-zone"
|
||||||
version = "0.1.53"
|
version = "0.1.53"
|
||||||
@@ -583,6 +708,12 @@ version = "0.10.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "df19da1e92fbfec043ca97d622955381b1f3ee72a180ec999912df31b1ccd951"
|
checksum = "df19da1e92fbfec043ca97d622955381b1f3ee72a180ec999912df31b1ccd951"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indenter"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "instant"
|
name = "instant"
|
||||||
version = "0.1.12"
|
version = "0.1.12"
|
||||||
@@ -592,6 +723,28 @@ dependencies = [
|
|||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "io-lifetimes"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e7d6c6f8c91b4b9ed43484ad1a938e393caf35960fce7f82a040497207bd8e9e"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "is-terminal"
|
||||||
|
version = "0.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189"
|
||||||
|
dependencies = [
|
||||||
|
"hermit-abi 0.2.6",
|
||||||
|
"io-lifetimes",
|
||||||
|
"rustix",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jpeg-decoder"
|
name = "jpeg-decoder"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
@@ -646,6 +799,12 @@ dependencies = [
|
|||||||
"cc",
|
"cc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "linux-raw-sys"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lock_api"
|
name = "lock_api"
|
||||||
version = "0.4.9"
|
version = "0.4.9"
|
||||||
@@ -677,6 +836,15 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "matchers"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
|
||||||
|
dependencies = [
|
||||||
|
"regex-automata",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.5.0"
|
version = "2.5.0"
|
||||||
@@ -772,6 +940,16 @@ dependencies = [
|
|||||||
"static_assertions",
|
"static_assertions",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nu-ansi-term"
|
||||||
|
version = "0.46.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
|
||||||
|
dependencies = [
|
||||||
|
"overload",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-integer"
|
name = "num-integer"
|
||||||
version = "0.1.45"
|
version = "0.1.45"
|
||||||
@@ -808,7 +986,7 @@ version = "1.14.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5"
|
checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hermit-abi",
|
"hermit-abi 0.1.19",
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -833,12 +1011,27 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "object"
|
||||||
|
version = "0.30.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2b8c786513eb403643f2a88c244c2aaa270ef2153f55094587d0c48a3cf22a83"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.16.0"
|
version = "1.16.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
|
checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "os_str_bytes"
|
||||||
|
version = "6.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ouroboros"
|
name = "ouroboros"
|
||||||
version = "0.15.5"
|
version = "0.15.5"
|
||||||
@@ -862,6 +1055,18 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "overload"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "owo-colors"
|
||||||
|
version = "3.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking_lot"
|
name = "parking_lot"
|
||||||
version = "0.11.2"
|
version = "0.11.2"
|
||||||
@@ -1014,11 +1219,14 @@ dependencies = [
|
|||||||
name = "protostar"
|
name = "protostar"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"clap",
|
||||||
|
"color-eyre",
|
||||||
|
"directories",
|
||||||
"dirs",
|
"dirs",
|
||||||
"ez-pixmap",
|
"ez-pixmap",
|
||||||
"glam",
|
"glam",
|
||||||
"image",
|
"image",
|
||||||
|
"lazy_static",
|
||||||
"manifest-dir-macros",
|
"manifest-dir-macros",
|
||||||
"mint",
|
"mint",
|
||||||
"nix",
|
"nix",
|
||||||
@@ -1027,6 +1235,7 @@ dependencies = [
|
|||||||
"stardust-xr-molecules",
|
"stardust-xr-molecules",
|
||||||
"tempdir",
|
"tempdir",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"tracing-subscriber",
|
||||||
"tween",
|
"tween",
|
||||||
"ustr",
|
"ustr",
|
||||||
"walkdir",
|
"walkdir",
|
||||||
@@ -1158,12 +1367,19 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.7.0"
|
version = "1.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a"
|
checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733"
|
||||||
|
dependencies = [
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-automata"
|
||||||
|
version = "0.1.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick",
|
|
||||||
"memchr",
|
|
||||||
"regex-syntax",
|
"regex-syntax",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1219,12 +1435,32 @@ dependencies = [
|
|||||||
"xmlparser",
|
"xmlparser",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc-demangle"
|
||||||
|
version = "0.1.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-hash"
|
name = "rustc-hash"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustix"
|
||||||
|
version = "0.36.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d4fdebc4b395b7fbb9ab11e462e20ed9051e7b16e42d24042c776eca0ac81b03"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"errno",
|
||||||
|
"io-lifetimes",
|
||||||
|
"libc",
|
||||||
|
"linux-raw-sys",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustybuzz"
|
name = "rustybuzz"
|
||||||
version = "0.6.0"
|
version = "0.6.0"
|
||||||
@@ -1270,18 +1506,18 @@ checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.151"
|
version = "1.0.152"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "97fed41fc1a24994d044e6db6935e69511a1153b52c15eb42493b26fa87feba0"
|
checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.151"
|
version = "1.0.152"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "255abe9a125a985c05190d687b320c12f9b1f0b99445e608c21ba0782c719ad8"
|
checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -1290,15 +1526,24 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_repr"
|
name = "serde_repr"
|
||||||
version = "0.1.9"
|
version = "0.1.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1fe39d9fbb0ebf5eb2c7cb7e2a47e4f462fad1379f1166b8ae49ad9eae89a7ca"
|
checksum = "9a5ec9fa74a20ebbe5d9ac23dac1fc96ba0ecfe9f50f2843b52e537b10fbcb4e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sharded-slab"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "signal-hook-registry"
|
name = "signal-hook-registry"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
@@ -1350,9 +1595,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "stardust-xr"
|
name = "stardust-xr"
|
||||||
version = "0.10.0"
|
version = "0.10.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2dd05e0962751e904acb73a3c96d09311b88658c186f6a15ced1786e059bb3eb"
|
checksum = "cd8541caad6c5c3e9c43ce4fa43a330f7a3df5ec293c88fd062fff46172ceb97"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"cluFlock",
|
"cluFlock",
|
||||||
@@ -1370,12 +1615,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "stardust-xr-fusion"
|
name = "stardust-xr-fusion"
|
||||||
version = "0.28.1"
|
version = "0.33.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1c12936fdb0f2a15e69e96e89dca15ef5aad5e43046ba58fa4697b562894395f"
|
checksum = "a95836cb0147824ee1be564ba104de65d022da86d50bdac526e29830e8e1cf7c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"buildstructor",
|
|
||||||
"color-rs",
|
"color-rs",
|
||||||
"flagset",
|
"flagset",
|
||||||
"glam",
|
"glam",
|
||||||
@@ -1394,9 +1638,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "stardust-xr-molecules"
|
name = "stardust-xr-molecules"
|
||||||
version = "0.10.1"
|
version = "0.16.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ab9a5aa267fe9489d4d38a0971572f96b218db6c59c2c0b6b1bbea002aac91ac"
|
checksum = "73d9a445dc6aef7010c17d972885cea278f96d5da70b030e6a39e3e041ca85df"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"color-rs",
|
"color-rs",
|
||||||
"flexbuffers",
|
"flexbuffers",
|
||||||
@@ -1407,6 +1651,7 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
"stardust-xr-fusion",
|
"stardust-xr-fusion",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"tracing",
|
||||||
"xkbcommon",
|
"xkbcommon",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1431,16 +1676,6 @@ version = "1.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "str_inflector"
|
|
||||||
version = "0.12.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ec0b848d5a7695b33ad1be00f84a3c079fe85c9278a325ff9159e6c99cef4ef7"
|
|
||||||
dependencies = [
|
|
||||||
"lazy_static",
|
|
||||||
"regex",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strict-num"
|
name = "strict-num"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -1450,6 +1685,12 @@ dependencies = [
|
|||||||
"float-cmp",
|
"float-cmp",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strsim"
|
||||||
|
version = "0.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "svgfilters"
|
name = "svgfilters"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
@@ -1501,24 +1742,33 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "1.0.37"
|
version = "1.0.38"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e"
|
checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror-impl",
|
"thiserror-impl",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror-impl"
|
name = "thiserror-impl"
|
||||||
version = "1.0.37"
|
version = "1.0.38"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb"
|
checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thread_local"
|
||||||
|
version = "1.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180"
|
||||||
|
dependencies = [
|
||||||
|
"once_cell",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "threadpool"
|
name = "threadpool"
|
||||||
version = "1.8.1"
|
version = "1.8.1"
|
||||||
@@ -1577,9 +1827,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.23.0"
|
version = "1.24.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "eab6d665857cc6ca78d6e80303a02cea7a7851e85dfbd77cbdc09bd129f1ef46"
|
checksum = "1d9f76183f91ecfb55e1d7d5602bd1d979e38a3a522fe900241cf195624d67ae"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"bytes",
|
"bytes",
|
||||||
@@ -1645,27 +1895,46 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a"
|
checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
"valuable",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "try_match"
|
name = "tracing-error"
|
||||||
version = "0.3.0"
|
version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "789f9cd474cc74c591dcc98669b846e158f2409ace4e6e342502ab44a41c584b"
|
checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"try_match_inner",
|
"tracing",
|
||||||
|
"tracing-subscriber",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "try_match_inner"
|
name = "tracing-log"
|
||||||
version = "0.4.0"
|
version = "0.1.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "607e6b75bc1bdf1a60d4201c500ca965834c11f30e25921cfd28569315db49a9"
|
checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro-error",
|
"lazy_static",
|
||||||
"proc-macro2",
|
"log",
|
||||||
"quote",
|
"tracing-core",
|
||||||
"syn",
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing-subscriber"
|
||||||
|
version = "0.3.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70"
|
||||||
|
dependencies = [
|
||||||
|
"matchers",
|
||||||
|
"nu-ansi-term",
|
||||||
|
"once_cell",
|
||||||
|
"regex",
|
||||||
|
"sharded-slab",
|
||||||
|
"smallvec",
|
||||||
|
"thread_local",
|
||||||
|
"tracing",
|
||||||
|
"tracing-core",
|
||||||
|
"tracing-log",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1676,9 +1945,9 @@ checksum = "375812fa44dab6df41c195cd2f7fecb488f6c09fbaafb62807488cefab642bff"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tween"
|
name = "tween"
|
||||||
version = "1.0.1"
|
version = "2.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "63e9aab86b1958c0ff7f3d18d04abd6d8e583d237f92e88191ce5c7bf481c5ec"
|
checksum = "f114398da254e78168e12edec0ece6b4ca15a97262ecd8e5efd5025e3fc30204"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-bidi"
|
name = "unicode-bidi"
|
||||||
@@ -1776,6 +2045,12 @@ dependencies = [
|
|||||||
"usvg",
|
"usvg",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "valuable"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "version_check"
|
name = "version_check"
|
||||||
version = "0.9.4"
|
version = "0.9.4"
|
||||||
|
|||||||
12
Cargo.toml
12
Cargo.toml
@@ -4,19 +4,23 @@ version = "0.3.0"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.66"
|
clap = { version = "4.1.3", features = ["derive"] }
|
||||||
|
color-eyre = "0.6.2"
|
||||||
|
directories = "4.0.1"
|
||||||
dirs = "4.0.0"
|
dirs = "4.0.0"
|
||||||
ez-pixmap = "0.2.2"
|
ez-pixmap = "0.2.2"
|
||||||
glam = { version = "0.22.0", features = ["mint"] }
|
glam = { version = "0.22.0", features = ["mint"] }
|
||||||
image = "0.24.5"
|
image = "0.24.5"
|
||||||
|
lazy_static = "1.4.0"
|
||||||
manifest-dir-macros = "0.1.16"
|
manifest-dir-macros = "0.1.16"
|
||||||
mint = "0.5.9"
|
mint = "0.5.9"
|
||||||
nix = "0.26.1"
|
nix = "0.26.1"
|
||||||
resvg = "0.28.0"
|
resvg = "0.28.0"
|
||||||
rustc-hash = "1.1.0"
|
rustc-hash = "1.1.0"
|
||||||
stardust-xr-molecules = "0.10.1"
|
stardust-xr-molecules = "0.16.0"
|
||||||
tokio = { version = "1.22.0", features = ["full"] }
|
tokio = { version = "1.24.1", features = ["full"] }
|
||||||
tween = "1.0.1"
|
tracing-subscriber = { version = "0.3.16", features = ["env-filter"] }
|
||||||
|
tween = "2.0.0"
|
||||||
ustr = "0.9.0"
|
ustr = "0.9.0"
|
||||||
walkdir = "2.3.2"
|
walkdir = "2.3.2"
|
||||||
|
|
||||||
|
|||||||
BIN
assets/cartridge.blend
Normal file
BIN
assets/cartridge.blend
Normal file
Binary file not shown.
BIN
assets/circuit.png
Normal file
BIN
assets/circuit.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 236 KiB |
BIN
assets/circuit_grayscale.png
Normal file
BIN
assets/circuit_grayscale.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 197 KiB |
BIN
assets/icon_test.png
Normal file
BIN
assets/icon_test.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.0 MiB |
116
examples/app_grid.rs
Normal file
116
examples/app_grid.rs
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
use color_eyre::eyre::Result;
|
||||||
|
use manifest_dir_macros::directory_relative_path;
|
||||||
|
use mint::Vector3;
|
||||||
|
use protostar::{
|
||||||
|
protostar::ProtoStar,
|
||||||
|
xdg::{get_desktop_files, parse_desktop_file, DesktopFile},
|
||||||
|
};
|
||||||
|
use stardust_xr_molecules::fusion::{
|
||||||
|
client::{Client, LifeCycleHandler, LogicStepInfo},
|
||||||
|
spatial::Spatial,
|
||||||
|
};
|
||||||
|
|
||||||
|
const APP_LIMIT: usize = 50;
|
||||||
|
const APP_SIZE: f32 = 0.05;
|
||||||
|
const GRID_PADDING: f32 = 0.01;
|
||||||
|
|
||||||
|
#[tokio::main(flavor = "current_thread")]
|
||||||
|
async fn main() -> Result<()> {
|
||||||
|
color_eyre::install().unwrap();
|
||||||
|
tracing_subscriber::fmt()
|
||||||
|
.with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
|
||||||
|
.pretty()
|
||||||
|
.init();
|
||||||
|
let (client, event_loop) = Client::connect_with_async_loop().await?;
|
||||||
|
client.set_base_prefixes(&[directory_relative_path!("res")]);
|
||||||
|
|
||||||
|
let _root = client.wrap_root(AppGrid::new(&client));
|
||||||
|
|
||||||
|
tokio::select! {
|
||||||
|
_ = tokio::signal::ctrl_c() => (),
|
||||||
|
e = event_loop => e??,
|
||||||
|
};
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AppGrid {
|
||||||
|
apps: Vec<App>,
|
||||||
|
}
|
||||||
|
impl AppGrid {
|
||||||
|
fn new(client: &Client) -> Self {
|
||||||
|
let apps = get_desktop_files()
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|d| parse_desktop_file(d).ok())
|
||||||
|
.enumerate()
|
||||||
|
.filter(|(i, _)| *i <= APP_LIMIT)
|
||||||
|
.filter_map(|(i, a)| {
|
||||||
|
App::new(
|
||||||
|
client.get_root(),
|
||||||
|
[
|
||||||
|
(i % 10) as f32 * (APP_SIZE + GRID_PADDING),
|
||||||
|
(i / 10) as f32 * (APP_SIZE + GRID_PADDING),
|
||||||
|
0.0,
|
||||||
|
],
|
||||||
|
a,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
AppGrid { apps }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl LifeCycleHandler for AppGrid {
|
||||||
|
fn logic_step(&mut self, info: LogicStepInfo) {
|
||||||
|
for app in &mut self.apps {
|
||||||
|
app.logic_step(info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
struct App {
|
||||||
|
// _text: Text,
|
||||||
|
_desktop_file: DesktopFile,
|
||||||
|
protostar: ProtoStar,
|
||||||
|
}
|
||||||
|
impl App {
|
||||||
|
fn new(
|
||||||
|
parent: &Spatial,
|
||||||
|
position: impl Into<Vector3<f32>>,
|
||||||
|
desktop_file: DesktopFile,
|
||||||
|
) -> Option<Self> {
|
||||||
|
let position = position.into();
|
||||||
|
|
||||||
|
let protostar = ProtoStar::create_from_desktop_file(parent, desktop_file.clone()).ok()?;
|
||||||
|
// let text = Text::create(
|
||||||
|
// protostar.content_parent(),
|
||||||
|
// Transform::from_position_rotation(
|
||||||
|
// [0.0, 0.0, APP_SIZE / 2.0],
|
||||||
|
// Quat::from_rotation_y(PI),
|
||||||
|
// ),
|
||||||
|
// desktop_file.name.as_deref().unwrap_or("Unknown"),
|
||||||
|
// TextStyle {
|
||||||
|
// character_height: APP_SIZE * 0.1,
|
||||||
|
// bounds: Some(Bounds {
|
||||||
|
// bounds: [APP_SIZE; 2].into(),
|
||||||
|
// fit: TextFit::Wrap,
|
||||||
|
// bounds_align: Alignment::XCenter | Alignment::YCenter,
|
||||||
|
// }),
|
||||||
|
// text_align: Alignment::XCenter | Alignment::YCenter,
|
||||||
|
// ..Default::default()
|
||||||
|
// },
|
||||||
|
// )
|
||||||
|
// .unwrap();
|
||||||
|
protostar
|
||||||
|
.content_parent()
|
||||||
|
.set_position(None, position)
|
||||||
|
.unwrap();
|
||||||
|
Some(App {
|
||||||
|
// _text: text,
|
||||||
|
_desktop_file: desktop_file,
|
||||||
|
protostar,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl LifeCycleHandler for App {
|
||||||
|
fn logic_step(&mut self, info: LogicStepInfo) {
|
||||||
|
self.protostar.logic_step(info);
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
res/protostar/cartridge.glb
Normal file
BIN
res/protostar/cartridge.glb
Normal file
Binary file not shown.
2
src/lib.rs
Normal file
2
src/lib.rs
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
pub mod protostar;
|
||||||
|
pub mod xdg;
|
||||||
67
src/main.rs
67
src/main.rs
@@ -1,29 +1,56 @@
|
|||||||
mod desktop_file;
|
use clap::Parser;
|
||||||
mod protostar;
|
use color_eyre::{
|
||||||
|
eyre::{bail, Result},
|
||||||
use manifest_dir_macros::directory_relative_path;
|
Report,
|
||||||
use protostar::ProtoStar;
|
|
||||||
use stardust_xr_molecules::fusion::client::Client;
|
|
||||||
use std::{
|
|
||||||
env::{args, current_dir},
|
|
||||||
path::Path,
|
|
||||||
};
|
};
|
||||||
|
use manifest_dir_macros::directory_relative_path;
|
||||||
|
use protostar::{protostar::ProtoStar, xdg::parse_desktop_file};
|
||||||
|
use stardust_xr_molecules::fusion::client::Client;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
#[derive(Debug, Parser)]
|
||||||
|
#[clap(author, version, about, long_about = None)]
|
||||||
|
struct Args {
|
||||||
|
#[clap(short, long, default_value_t = 0.1)]
|
||||||
|
size: f32,
|
||||||
|
#[clap(
|
||||||
|
short,
|
||||||
|
long,
|
||||||
|
conflicts_with = "command",
|
||||||
|
required_unless_present = "command",
|
||||||
|
conflicts_with = "icon",
|
||||||
|
required_unless_present = "icon"
|
||||||
|
)]
|
||||||
|
desktop_file: Option<PathBuf>,
|
||||||
|
#[clap(short, long, conflicts_with = "desktop_file", requires = "command")]
|
||||||
|
icon: Option<PathBuf>,
|
||||||
|
#[clap(short, long, conflicts_with = "desktop_file", requires = "icon")]
|
||||||
|
command: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::main(flavor = "current_thread")]
|
#[tokio::main(flavor = "current_thread")]
|
||||||
async fn main() {
|
async fn main() -> Result<()> {
|
||||||
let (client, event_loop) = Client::connect_with_async_loop().await.unwrap();
|
color_eyre::install()?;
|
||||||
|
let args = Args::parse();
|
||||||
|
let (client, event_loop) = Client::connect_with_async_loop().await?;
|
||||||
client.set_base_prefixes(&[directory_relative_path!("res")]);
|
client.set_base_prefixes(&[directory_relative_path!("res")]);
|
||||||
|
|
||||||
let _root = client.wrap_root(ProtoStar::new(
|
let protostar = if let Some(desktop_file) = args.desktop_file {
|
||||||
client.clone(),
|
ProtoStar::create_from_desktop_file(
|
||||||
0.1,
|
client.get_root(),
|
||||||
current_dir()
|
parse_desktop_file(desktop_file).map_err(|e| Report::msg(e))?,
|
||||||
.unwrap()
|
)?
|
||||||
.join(Path::new(&args().nth(1).unwrap())),
|
} else if let Some(command) = args.command {
|
||||||
));
|
ProtoStar::new_raw(client.get_root(), None, command)?
|
||||||
|
} else {
|
||||||
|
bail!("No command or desktop file, nothing to launch.");
|
||||||
|
};
|
||||||
|
|
||||||
|
let _root = client.wrap_root(protostar);
|
||||||
|
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
_ = tokio::signal::ctrl_c() => (),
|
_ = tokio::signal::ctrl_c() => (),
|
||||||
e = event_loop => e.unwrap().unwrap(),
|
e = event_loop => e??,
|
||||||
}
|
};
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
137
src/protostar.rs
137
src/protostar.rs
@@ -1,3 +1,5 @@
|
|||||||
|
use crate::xdg::{DesktopFile, Icon, RawIconType};
|
||||||
|
use color_eyre::eyre::{eyre, Result};
|
||||||
use glam::Quat;
|
use glam::Quat;
|
||||||
use mint::Vector3;
|
use mint::Vector3;
|
||||||
use nix::unistd::{execv, fork};
|
use nix::unistd::{execv, fork};
|
||||||
@@ -5,56 +7,110 @@ use stardust_xr_molecules::{
|
|||||||
fusion::{
|
fusion::{
|
||||||
client::{Client, LifeCycleHandler, LogicStepInfo},
|
client::{Client, LifeCycleHandler, LogicStepInfo},
|
||||||
core::values::Transform,
|
core::values::Transform,
|
||||||
drawable::Model,
|
drawable::{MaterialParameter, Model, ResourceID},
|
||||||
fields::SphereField,
|
fields::BoxField,
|
||||||
node::NodeType,
|
node::NodeType,
|
||||||
resource::NamespacedResource,
|
spatial::Spatial,
|
||||||
startup_settings::StartupSettings,
|
startup_settings::StartupSettings,
|
||||||
},
|
},
|
||||||
GrabData, Grabbable,
|
GrabData, Grabbable,
|
||||||
};
|
};
|
||||||
use std::{env::args, ffi::CString, path::PathBuf, sync::Arc};
|
use std::{f32::consts::PI, ffi::CStr, sync::Arc};
|
||||||
use tween::{QuartInOut, Tweener};
|
use tween::{QuartInOut, Tweener};
|
||||||
use ustr::ustr;
|
use ustr::ustr;
|
||||||
|
|
||||||
|
fn model_from_icon(parent: &Spatial, icon: &Icon) -> Result<Model> {
|
||||||
|
let model = match icon {
|
||||||
|
Icon::Png(path) => {
|
||||||
|
let model = Model::create(
|
||||||
|
parent,
|
||||||
|
Transform::from_rotation(Quat::from_rotation_y(PI)),
|
||||||
|
&ResourceID::new_namespaced("protostar", "cartridge"),
|
||||||
|
)?;
|
||||||
|
model.set_material_parameter(
|
||||||
|
0,
|
||||||
|
"diffuse",
|
||||||
|
MaterialParameter::Texture(ResourceID::Direct(path.clone())),
|
||||||
|
)?;
|
||||||
|
model
|
||||||
|
}
|
||||||
|
Icon::Gltf(path) => Model::create(
|
||||||
|
parent,
|
||||||
|
Transform::from_scale([0.05; 3]),
|
||||||
|
&ResourceID::new_direct(path)?,
|
||||||
|
)?,
|
||||||
|
};
|
||||||
|
Ok(model)
|
||||||
|
}
|
||||||
|
|
||||||
pub struct ProtoStar {
|
pub struct ProtoStar {
|
||||||
client: Arc<Client>,
|
client: Arc<Client>,
|
||||||
grabbable: Grabbable,
|
grabbable: Grabbable,
|
||||||
field: SphereField,
|
field: BoxField,
|
||||||
icon: Model,
|
icon: Model,
|
||||||
icon_shrink: Option<Tweener<QuartInOut<f32, f64>>>,
|
icon_shrink: Option<Tweener<f32, f64, QuartInOut>>,
|
||||||
size: f32,
|
execute_command: String,
|
||||||
executable_path: PathBuf,
|
|
||||||
}
|
}
|
||||||
impl ProtoStar {
|
impl ProtoStar {
|
||||||
pub fn new(client: Arc<Client>, size: f32, executable_path: PathBuf) -> Self {
|
pub fn create_from_desktop_file(parent: &Spatial, desktop_file: DesktopFile) -> Result<Self> {
|
||||||
let field =
|
// dbg!(&desktop_file);
|
||||||
SphereField::create(client.get_root(), Vector3::from([0.0; 3]), size * 0.5).unwrap();
|
let mut raw_icons = desktop_file.get_raw_icons();
|
||||||
|
let last_icon = raw_icons.pop();
|
||||||
|
let icon = raw_icons
|
||||||
|
.into_iter()
|
||||||
|
.find(|i| match i {
|
||||||
|
RawIconType::Png(_) => false,
|
||||||
|
RawIconType::Svg(_) => false,
|
||||||
|
RawIconType::Gltf(_) => true,
|
||||||
|
})
|
||||||
|
.or(last_icon)
|
||||||
|
.map(|i| dbg!(i.process(64)).ok())
|
||||||
|
.ok_or_else(|| eyre!("No compatible icons found"))?;
|
||||||
|
Self::new_raw(
|
||||||
|
parent,
|
||||||
|
icon,
|
||||||
|
desktop_file.command.ok_or_else(|| eyre!("No command"))?,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pub fn new_raw(parent: &Spatial, icon: Option<Icon>, execute_command: String) -> Result<Self> {
|
||||||
|
let field = BoxField::create(
|
||||||
|
parent,
|
||||||
|
Transform::default(),
|
||||||
|
match icon.as_ref() {
|
||||||
|
Some(Icon::Png(_)) => [0.05, 0.0665, 0.005],
|
||||||
|
_ => [0.05; 3],
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
|
)?;
|
||||||
let grabbable = Grabbable::new(
|
let grabbable = Grabbable::new(
|
||||||
client.get_root(),
|
parent,
|
||||||
Transform::default(),
|
Transform::default(),
|
||||||
&field,
|
&field,
|
||||||
GrabData { max_distance: 0.05 },
|
GrabData {
|
||||||
)
|
max_distance: 0.025,
|
||||||
.unwrap();
|
},
|
||||||
field
|
)?;
|
||||||
.set_spatial_parent(grabbable.content_parent())
|
field.set_spatial_parent(grabbable.content_parent())?;
|
||||||
.unwrap();
|
let icon = icon
|
||||||
let icon = Model::create(
|
.map(|i| model_from_icon(grabbable.content_parent(), &i))
|
||||||
grabbable.content_parent(),
|
.unwrap_or_else(|| {
|
||||||
Transform::from_scale([size; 3]),
|
Ok(Model::create(
|
||||||
&NamespacedResource::new("protostar", "default_icon"),
|
grabbable.content_parent(),
|
||||||
)
|
Transform::from_scale([0.05; 3]),
|
||||||
.unwrap();
|
&ResourceID::new_namespaced("protostar", "default_icon"),
|
||||||
ProtoStar {
|
)?)
|
||||||
client,
|
})?;
|
||||||
|
Ok(ProtoStar {
|
||||||
|
client: parent.client()?,
|
||||||
grabbable,
|
grabbable,
|
||||||
field,
|
field,
|
||||||
icon,
|
icon,
|
||||||
icon_shrink: None,
|
icon_shrink: None,
|
||||||
size,
|
execute_command,
|
||||||
executable_path,
|
})
|
||||||
}
|
}
|
||||||
|
pub fn content_parent(&self) -> &Spatial {
|
||||||
|
self.grabbable.content_parent()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl LifeCycleHandler for ProtoStar {
|
impl LifeCycleHandler for ProtoStar {
|
||||||
@@ -62,7 +118,8 @@ impl LifeCycleHandler for ProtoStar {
|
|||||||
self.grabbable.update();
|
self.grabbable.update();
|
||||||
|
|
||||||
if let Some(icon_shrink) = &mut self.icon_shrink {
|
if let Some(icon_shrink) = &mut self.icon_shrink {
|
||||||
if let Some(scale) = icon_shrink.update(info.delta) {
|
if !icon_shrink.is_finished() {
|
||||||
|
let scale = icon_shrink.move_by(info.delta);
|
||||||
self.icon
|
self.icon
|
||||||
.set_scale(None, Vector3::from([scale; 3]))
|
.set_scale(None, Vector3::from([scale; 3]))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -84,19 +141,21 @@ impl LifeCycleHandler for ProtoStar {
|
|||||||
startup_settings
|
startup_settings
|
||||||
.set_root(self.grabbable.content_parent())
|
.set_root(self.grabbable.content_parent())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
self.icon_shrink = Some(Tweener::new(QuartInOut::new(self.size..=0.0, 0.25)));
|
self.icon_shrink = Some(Tweener::quart_in_out(1.0, 0.0, 0.25));
|
||||||
let future = startup_settings.generate_startup_token().unwrap();
|
let future = startup_settings.generate_startup_token().unwrap();
|
||||||
let executable = self.executable_path.clone();
|
let executable = dbg!(self.execute_command.clone());
|
||||||
tokio::task::spawn(async move {
|
tokio::task::spawn(async move {
|
||||||
std::env::set_var("STARDUST_STARTUP_TOKEN", future.await.unwrap());
|
std::env::set_var("STARDUST_STARTUP_TOKEN", future.await.unwrap());
|
||||||
if unsafe { fork() }.unwrap().is_parent() {
|
if unsafe { fork() }.unwrap().is_parent() {
|
||||||
let executable = ustr(executable.to_str().unwrap());
|
execv::<&CStr>(
|
||||||
let args = args()
|
ustr("/bin/sh").as_cstr(),
|
||||||
.skip(1)
|
&[
|
||||||
.map(|arg| CString::new(arg))
|
ustr("/bin/sh").as_cstr(),
|
||||||
.collect::<Result<Vec<_>, _>>()
|
ustr("-c").as_cstr(),
|
||||||
.unwrap();
|
ustr(&executable).as_cstr(),
|
||||||
execv::<CString>(executable.as_cstr(), args.as_slice()).unwrap();
|
],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,18 @@
|
|||||||
use std::ffi::OsString;
|
use color_eyre::eyre::Result;
|
||||||
use std::io::{BufRead, BufReader};
|
|
||||||
use std::path::{Path, PathBuf};
|
|
||||||
use std::str::FromStr;
|
|
||||||
use std::{env, fs};
|
|
||||||
|
|
||||||
use anyhow::Result;
|
|
||||||
use resvg::render;
|
use resvg::render;
|
||||||
use resvg::tiny_skia::{Pixmap, Transform};
|
use resvg::tiny_skia::{Pixmap, Transform};
|
||||||
use resvg::usvg::{FitTo, Tree};
|
use resvg::usvg::{FitTo, Tree};
|
||||||
|
use std::ffi::OsString;
|
||||||
|
use std::fs::create_dir_all;
|
||||||
|
use std::io::{BufRead, BufReader, ErrorKind};
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::str::FromStr;
|
||||||
|
use std::{env, fs};
|
||||||
use walkdir::WalkDir;
|
use walkdir::WalkDir;
|
||||||
|
|
||||||
fn get_desktop_files() -> Vec<PathBuf> {
|
const ICON_SIZES: &[&str] = &["128x128", "scalable", "256x256", "64x64", "32x32"];
|
||||||
|
|
||||||
|
pub fn get_desktop_files() -> Vec<PathBuf> {
|
||||||
// Get the XDG data directories
|
// Get the XDG data directories
|
||||||
let xdg_data_dirs =
|
let xdg_data_dirs =
|
||||||
std::env::var("XDG_DATA_DIRS").unwrap_or("/usr/local/share:/usr/share".to_string());
|
std::env::var("XDG_DATA_DIRS").unwrap_or("/usr/local/share:/usr/share".to_string());
|
||||||
@@ -55,9 +57,13 @@ fn test_get_desktop_files() {
|
|||||||
.any(|file| file.ends_with("gimp.desktop")));
|
.any(|file| file.ends_with("gimp.desktop")));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_desktop_file(path: &Path) -> Result<DesktopFile, String> {
|
pub fn parse_desktop_file(path: PathBuf) -> Result<DesktopFile, String> {
|
||||||
// Open the file in read-only mode
|
// Open the file in read-only mode
|
||||||
let file = match fs::File::open(path) {
|
let file = match fs::File::open(
|
||||||
|
env::current_dir()
|
||||||
|
.map_err(|e| e.to_string())?
|
||||||
|
.join(path.clone()),
|
||||||
|
) {
|
||||||
Ok(file) => file,
|
Ok(file) => file,
|
||||||
Err(err) => return Err(format!("Failed to open file: {}", err)),
|
Err(err) => return Err(format!("Failed to open file: {}", err)),
|
||||||
};
|
};
|
||||||
@@ -93,7 +99,13 @@ fn parse_desktop_file(path: &Path) -> Result<DesktopFile, String> {
|
|||||||
match key {
|
match key {
|
||||||
"Name" => name = Some(value.to_string()),
|
"Name" => name = Some(value.to_string()),
|
||||||
"Exec" => command = Some(value.to_string()),
|
"Exec" => command = Some(value.to_string()),
|
||||||
"Categories" => categories = value.split(';').map(|s| s.to_string()).collect(),
|
"Categories" => {
|
||||||
|
categories = value
|
||||||
|
.split(';')
|
||||||
|
.map(|s| s.to_string())
|
||||||
|
.filter(|s| !s.is_empty())
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
"Icon" => icon = Some(value.to_string()),
|
"Icon" => icon = Some(value.to_string()),
|
||||||
_ => (), // Ignore unknown keys
|
_ => (), // Ignore unknown keys
|
||||||
}
|
}
|
||||||
@@ -101,6 +113,7 @@ fn parse_desktop_file(path: &Path) -> Result<DesktopFile, String> {
|
|||||||
|
|
||||||
// Create and return a new DesktopFile instance with the parsed values
|
// Create and return a new DesktopFile instance with the parsed values
|
||||||
Ok(DesktopFile {
|
Ok(DesktopFile {
|
||||||
|
path,
|
||||||
name,
|
name,
|
||||||
command,
|
command,
|
||||||
categories,
|
categories,
|
||||||
@@ -117,7 +130,7 @@ fn test_parse_desktop_file() {
|
|||||||
fs::write(&file, data).unwrap();
|
fs::write(&file, data).unwrap();
|
||||||
|
|
||||||
// Parse the test desktop file
|
// Parse the test desktop file
|
||||||
let desktop_file = parse_desktop_file(&file).unwrap();
|
let desktop_file = parse_desktop_file(file).unwrap();
|
||||||
|
|
||||||
// Check the parsed values
|
// Check the parsed values
|
||||||
assert_eq!(desktop_file.name, Some("Test".to_string()));
|
assert_eq!(desktop_file.name, Some("Test".to_string()));
|
||||||
@@ -129,31 +142,130 @@ fn test_parse_desktop_file() {
|
|||||||
assert_eq!(desktop_file.icon, Some("test.png".to_string()));
|
assert_eq!(desktop_file.icon, Some("test.png".to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct DesktopFile {
|
||||||
|
path: PathBuf,
|
||||||
|
pub name: Option<String>,
|
||||||
|
pub command: Option<String>,
|
||||||
|
pub categories: Vec<String>,
|
||||||
|
pub icon: Option<String>,
|
||||||
|
}
|
||||||
|
impl DesktopFile {
|
||||||
|
pub fn get_raw_icons(&self) -> Vec<RawIconType> {
|
||||||
|
// Get the name of the icon from the DesktopFile struct
|
||||||
|
let Some(icon_name) = self.icon.as_ref() else { return Vec::new(); };
|
||||||
|
let test_icon_path = self.path.join(Path::new(icon_name));
|
||||||
|
if test_icon_path.exists() {
|
||||||
|
return RawIconType::from_path(test_icon_path)
|
||||||
|
.map(|i| vec![i])
|
||||||
|
.unwrap_or_default();
|
||||||
|
}
|
||||||
|
|
||||||
|
let Ok(icon_name) = OsString::from_str(icon_name) else { return Vec::new(); };
|
||||||
|
|
||||||
|
// Get the current icon theme from the XDG_ICON_THEME environment variable, or use "hicolor" as the default theme if the variable is not defined
|
||||||
|
let icon_theme = env::var_os("XDG_ICON_THEME").unwrap_or("hicolor".into());
|
||||||
|
|
||||||
|
// Get the XDG_DATA_HOME and XDG_DATA_DIRS environment variables, and split the XDG_DATA_DIRS variable into a list of directories
|
||||||
|
let Some(xdg_data_dirs) = env::var_os("XDG_DATA_DIRS") else { return Vec::new(); };
|
||||||
|
let Ok(binding) = xdg_data_dirs.into_string() else { return Vec::new(); };
|
||||||
|
let xdg_data_dirs = binding.split(":").map(Path::new);
|
||||||
|
|
||||||
|
// Concatenate the XDG_DATA_HOME and XDG_DATA_DIRS directories with the default path for icon themes
|
||||||
|
xdg_data_dirs // XDG_DATA_DIRS directories
|
||||||
|
.flat_map(|dir| {
|
||||||
|
let icons_path = dir.join("icons").join(&icon_theme);
|
||||||
|
ICON_SIZES
|
||||||
|
.iter()
|
||||||
|
.map(|path| icons_path.join(path).join("apps"))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
})
|
||||||
|
.filter_map(|dir| {
|
||||||
|
let dir = fs::read_dir(dir).ok()?;
|
||||||
|
Some(
|
||||||
|
dir.filter_map(|e| e.ok())
|
||||||
|
.map(|file| file.path())
|
||||||
|
.filter(|file| file.file_stem() == Some(&icon_name)),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.flatten()
|
||||||
|
.filter_map(RawIconType::from_path)
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
enum IconType {
|
pub enum RawIconType {
|
||||||
Png(PathBuf),
|
Png(PathBuf),
|
||||||
Svg(PathBuf),
|
Svg(PathBuf),
|
||||||
Gltf(PathBuf),
|
Gltf(PathBuf),
|
||||||
}
|
}
|
||||||
impl IconType {
|
impl RawIconType {
|
||||||
fn to_png(&self, size: u32) -> Option<PathBuf> {
|
pub fn from_path(path: PathBuf) -> Option<RawIconType> {
|
||||||
match self {
|
match path.extension().and_then(|ext| ext.to_str()) {
|
||||||
IconType::Png(path) => Some(path.clone()),
|
Some("png") => Some(RawIconType::Png(path)),
|
||||||
IconType::Svg(path) => {
|
Some("svg") => Some(RawIconType::Svg(path)),
|
||||||
let png_path = path.with_extension("png");
|
Some("glb") | Some("gltf") => Some(RawIconType::Gltf(path)),
|
||||||
render_svg_to_png(path, &png_path, size).ok()?;
|
|
||||||
Some(png_path)
|
|
||||||
}
|
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn process(self, size: u32) -> Result<Icon, std::io::Error> {
|
||||||
|
match self {
|
||||||
|
RawIconType::Png(path) => Ok(Icon::Png(path)),
|
||||||
|
RawIconType::Svg(path) => {
|
||||||
|
let png_path = path.with_extension("png");
|
||||||
|
render_svg_to_png(path, &png_path, size)?;
|
||||||
|
Ok(Icon::Png(png_path))
|
||||||
|
}
|
||||||
|
RawIconType::Gltf(path) => Ok(Icon::Gltf(path)),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_svg_to_png(svg_path: &PathBuf, png_path: &PathBuf, size: u32) -> Result<()> {
|
#[test]
|
||||||
|
fn test_get_icon_path() {
|
||||||
|
// Create an instance of the DesktopFile struct with some dummy data
|
||||||
|
let desktop_file = DesktopFile {
|
||||||
|
path: PathBuf::new(),
|
||||||
|
name: None,
|
||||||
|
command: None,
|
||||||
|
categories: vec![],
|
||||||
|
icon: Some("krita".into()),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Call the get_icon_path() function with a size argument and store the result
|
||||||
|
let icon_paths = desktop_file.get_raw_icons();
|
||||||
|
dbg!(&icon_paths);
|
||||||
|
|
||||||
|
// Assert that the get_icon_path() function returns the expected result
|
||||||
|
assert!(icon_paths.contains(&RawIconType::Png(PathBuf::from(
|
||||||
|
"/usr/share/icons/hicolor/16x16/apps/krita.png"
|
||||||
|
))));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub enum Icon {
|
||||||
|
Png(PathBuf),
|
||||||
|
Gltf(PathBuf),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render_svg_to_png(
|
||||||
|
cache_dir: impl AsRef<Path>,
|
||||||
|
svg_path: impl AsRef<Path>,
|
||||||
|
size: u32,
|
||||||
|
) -> Result<PathBuf, std::io::Error> {
|
||||||
|
let svg_path = fs::canonicalize(svg_path)?;
|
||||||
let tree = Tree::from_data(
|
let tree = Tree::from_data(
|
||||||
fs::read(svg_path)?.as_slice(),
|
fs::read(svg_path.as_path())?.as_slice(),
|
||||||
&resvg::usvg::Options::default(),
|
&resvg::usvg::Options::default(),
|
||||||
)?;
|
)
|
||||||
|
.map_err(|_| ErrorKind::InvalidData)?;
|
||||||
|
create_dir_all(cache_dir.as_ref())?;
|
||||||
|
let png_path = cache_dir
|
||||||
|
.as_ref()
|
||||||
|
.join(svg_path.file_name().unwrap())
|
||||||
|
.with_extension("png");
|
||||||
let mut pixmap = Pixmap::new(size, size).unwrap();
|
let mut pixmap = Pixmap::new(size, size).unwrap();
|
||||||
render(
|
render(
|
||||||
&tree,
|
&tree,
|
||||||
@@ -161,101 +273,40 @@ fn render_svg_to_png(svg_path: &PathBuf, png_path: &PathBuf, size: u32) -> Resul
|
|||||||
Transform::identity(),
|
Transform::identity(),
|
||||||
pixmap.as_mut(),
|
pixmap.as_mut(),
|
||||||
);
|
);
|
||||||
pixmap.save_png(png_path)?;
|
pixmap
|
||||||
Ok(())
|
.save_png(&png_path)
|
||||||
|
.map_err(|_| ErrorKind::InvalidData)?;
|
||||||
|
Ok(png_path)
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn test_render_svg_to_png() {
|
fn test_render_svg_to_png() {
|
||||||
use image::GenericImageView;
|
use image::GenericImageView;
|
||||||
// Create temporary input and output paths
|
// Create temporary input and output paths
|
||||||
let input_path = PathBuf::from("test_input.svg");
|
let svg_path = env::current_dir().unwrap().join("test_input.svg");
|
||||||
let output_path = PathBuf::from("test_output.png");
|
|
||||||
|
|
||||||
// Write some test SVG data to the input path
|
// Write some test SVG data to the input path
|
||||||
let test_svg_data = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 100 100\">
|
let test_svg_data = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 100 100\">
|
||||||
<ellipse cx=\"50\" cy=\"80\" rx=\"46\" ry=\"19\" fill=\"#07c\"/>
|
<ellipse cx=\"50\" cy=\"80\" rx=\"46\" ry=\"19\" fill=\"#07c\"/>
|
||||||
<path d=\"M43,0c-6,25,16,22,1,52c11,3,19,0,19-22c38,18,16,63-12,64c-25,2-55-39-8-94\" fill=\"#e34\"/>
|
<path d=\"M43,0c-6,25,16,22,1,52c11,3,19,0,19-22c38,18,16,63-12,64c-25,2-55-39-8-94\" fill=\"#e34\"/>
|
||||||
<path d=\"M34,41c-6,39,29,32,33,7c39,42-69,63-33-7\" fill=\"#fc2\"/>
|
<path d=\"M34,41c-6,39,29,32,33,7c39,42-69,63-33-7\" fill=\"#fc2\"/>
|
||||||
</svg>";
|
</svg>";
|
||||||
fs::write(&input_path, test_svg_data).unwrap();
|
fs::write(&svg_path, test_svg_data).unwrap();
|
||||||
|
|
||||||
// Call the function with the test input and output paths and a size of 200
|
// Call the function with the test input and output paths and a size of 200
|
||||||
render_svg_to_png(&input_path, &output_path, 200).unwrap();
|
let png_path = render_svg_to_png(".", &svg_path, 200).unwrap();
|
||||||
|
dbg!(&png_path);
|
||||||
|
|
||||||
// Check that the output file exists
|
// Check that the output file exists
|
||||||
assert!(output_path.exists());
|
assert!(png_path.exists());
|
||||||
|
|
||||||
// Check that the output file is a PNG file
|
// Check that the output file is a PNG file
|
||||||
assert_eq!(output_path.extension().unwrap(), "png");
|
assert_eq!(png_path.extension().unwrap(), "png");
|
||||||
|
|
||||||
// Check that the output file has the expected dimensions
|
// Check that the output file has the expected dimensions
|
||||||
let output_image = image::open(&output_path).unwrap();
|
let output_image = image::open(&png_path).unwrap();
|
||||||
assert_eq!(output_image.dimensions(), (200, 200));
|
assert_eq!(output_image.dimensions(), (200, 200));
|
||||||
|
|
||||||
// Delete the temporary input and output files
|
// Delete the temporary input and output files
|
||||||
fs::remove_file(&input_path).unwrap();
|
fs::remove_file(&svg_path).unwrap();
|
||||||
fs::remove_file(&output_path).unwrap();
|
fs::remove_file(&png_path).unwrap();
|
||||||
}
|
|
||||||
|
|
||||||
struct DesktopFile {
|
|
||||||
name: Option<String>,
|
|
||||||
command: Option<String>,
|
|
||||||
categories: Vec<String>,
|
|
||||||
icon: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DesktopFile {
|
|
||||||
fn get_icon_path(&self, size: &str) -> Option<IconType> {
|
|
||||||
// Get the name of the icon from the DesktopFile struct
|
|
||||||
let icon_name = OsString::from_str(self.icon.as_ref()?).ok()?;
|
|
||||||
|
|
||||||
// Get the current icon theme from the XDG_ICON_THEME environment variable, or use "hicolor" as the default theme if the variable is not defined
|
|
||||||
let icon_theme = env::var_os("XDG_ICON_THEME").unwrap_or("hicolor".into());
|
|
||||||
|
|
||||||
// Get the XDG_DATA_HOME and XDG_DATA_DIRS environment variables, and split the XDG_DATA_DIRS variable into a list of directories
|
|
||||||
let xdg_data_dirs = env::var_os("XDG_DATA_DIRS")?;
|
|
||||||
let binding = xdg_data_dirs.into_string().ok()?;
|
|
||||||
let xdg_data_dirs = binding.split(":").map(Path::new);
|
|
||||||
|
|
||||||
// Concatenate the XDG_DATA_HOME and XDG_DATA_DIRS directories with the default path for icon themes
|
|
||||||
let icon = xdg_data_dirs // XDG_DATA_DIRS directories
|
|
||||||
.map(|dir| dir.join("icons").join(&icon_theme).join(size).join("apps"))
|
|
||||||
.filter_map(|dir| {
|
|
||||||
fs::read_dir(dir)
|
|
||||||
.ok()?
|
|
||||||
.filter_map(|e| e.ok())
|
|
||||||
.map(|file| file.path())
|
|
||||||
.find(|file| file.file_stem() == Some(&icon_name))
|
|
||||||
})
|
|
||||||
.last()?;
|
|
||||||
|
|
||||||
// Check the file extension of the icon file and return an option containing the path to the file in an instance of the IconType enum
|
|
||||||
match icon.extension().and_then(|ext| ext.to_str()) {
|
|
||||||
Some("png") => Some(IconType::Png(icon)),
|
|
||||||
Some("svg") => Some(IconType::Svg(icon)),
|
|
||||||
Some("glb") | Some("gltf") => Some(IconType::Gltf(icon)),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn test_get_icon_path() {
|
|
||||||
// Create an instance of the DesktopFile struct with some dummy data
|
|
||||||
let desktop_file = DesktopFile {
|
|
||||||
name: Some("test".into()),
|
|
||||||
command: Some("test-command".into()),
|
|
||||||
categories: vec!["test-category".into()],
|
|
||||||
icon: Some("krita".into()),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Call the get_icon_path() function with a size argument and store the result
|
|
||||||
let icon_path = desktop_file.get_icon_path("16x16");
|
|
||||||
|
|
||||||
// Assert that the get_icon_path() function returns the expected result
|
|
||||||
assert_eq!(
|
|
||||||
icon_path,
|
|
||||||
Some(IconType::Png(PathBuf::from(
|
|
||||||
"/usr/share/icons/hicolor/16x16/apps/krita.png"
|
|
||||||
)))
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user