mirror of
https://github.com/nekename/OpenDeck.git
synced 2026-10-28 09:44:01 +00:00
feat: implement rendering encoder feedback layouts to the touchstrip of the Stream Deck Plus (#356)
Co-authored-by: nekename <63245705+nekename@users.noreply.github.com>
This commit is contained in:
1 parent
2eaebe60d5
commit
a53dbe58d0
16 files changed
+897
-6
No files matched your search
Generated
+355
-4
@@ -2,6 +2,22 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "ab_glyph"
|
||||
version = "0.2.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "01c0457472c38ea5bd1c3b5ada5e368271cb550be7a4ca4a0b4634e9913f6cc2"
|
||||
dependencies = [
|
||||
"ab_glyph_rasterizer",
|
||||
"owned_ttf_parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ab_glyph_rasterizer"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "366ffbaa4442f4684d91e2cd7c5ea7c4ed8add41959a31447066e279e432b618"
|
||||
|
||||
[[package]]
|
||||
name = "active-win-pos-rs"
|
||||
version = "0.10.1"
|
||||
@@ -109,6 +125,12 @@ dependencies = [
|
||||
"derive_arbitrary",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arrayref"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.7.6"
|
||||
@@ -922,6 +944,15 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core_maths"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77745e017f5edba1a9c1d854f6f3a52dac8a12dd5af5d2f54aecf61e43d80d30"
|
||||
dependencies = [
|
||||
"libm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.17"
|
||||
@@ -1099,6 +1130,12 @@ version = "2.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea"
|
||||
|
||||
[[package]]
|
||||
name = "data-url"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be1e0bca6c3637f992fc1cc7cbc52a78c1ef6db076dbf1059c4323d6a2048376"
|
||||
|
||||
[[package]]
|
||||
name = "dbus"
|
||||
version = "0.9.10"
|
||||
@@ -1442,6 +1479,15 @@ dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "euclid"
|
||||
version = "0.22.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1a05365e3b1c6d1650318537c7460c6923f1abdd272ad6842baa2b509957a06"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "event-listener"
|
||||
version = "5.4.1"
|
||||
@@ -1540,6 +1586,12 @@ dependencies = [
|
||||
"zlib-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "float-cmp"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4"
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
@@ -1559,6 +1611,28 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fontconfig-parser"
|
||||
version = "0.5.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbc773e24e02d4ddd8395fd30dc147524273a83e54e0f312d986ea30de5f5646"
|
||||
dependencies = [
|
||||
"roxmltree 0.20.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fontdb"
|
||||
version = "0.23.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "457e789b3d1202543297a350643cf459f836cade38934e7a4cf6a39e7cde2905"
|
||||
dependencies = [
|
||||
"fontconfig-parser",
|
||||
"log",
|
||||
"slotmap",
|
||||
"tinyvec",
|
||||
"ttf-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types"
|
||||
version = "0.3.2"
|
||||
@@ -2332,7 +2406,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e795dff5605e0f04bff85ca41b51a96b83e80b281e96231bcaaf1ac35103371"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"png",
|
||||
"png 0.17.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2453,10 +2527,17 @@ dependencies = [
|
||||
"byteorder-lite",
|
||||
"moxcms",
|
||||
"num-traits",
|
||||
"png 0.18.1",
|
||||
"zune-core",
|
||||
"zune-jpeg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "imagesize"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09e54e57b4c48b40f7aec75635392b12b3421fa26fe8b4332e63138ed278459c"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.9.3"
|
||||
@@ -2679,6 +2760,18 @@ dependencies = [
|
||||
"selectors",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kurbo"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b60dfc32f652b926df6192e55525b16d186c69d47876c3ead4da5cc9f8450e2"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"euclid",
|
||||
"polycool",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.5.0"
|
||||
@@ -2762,6 +2855,12 @@ dependencies = [
|
||||
"windows-link 0.2.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libm"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
|
||||
|
||||
[[package]]
|
||||
name = "libredox"
|
||||
version = "0.1.12"
|
||||
@@ -2960,7 +3059,7 @@ dependencies = [
|
||||
"objc2-core-foundation",
|
||||
"objc2-foundation",
|
||||
"once_cell",
|
||||
"png",
|
||||
"png 0.17.16",
|
||||
"serde",
|
||||
"thiserror 2.0.18",
|
||||
"windows-sys 0.60.2",
|
||||
@@ -3424,6 +3523,7 @@ dependencies = [
|
||||
"serde-inline-default",
|
||||
"serde_json",
|
||||
"serde_with",
|
||||
"streamdeck-strip-render",
|
||||
"sysinfo",
|
||||
"tauri",
|
||||
"tauri-build",
|
||||
@@ -3534,6 +3634,15 @@ dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "owned_ttf_parser"
|
||||
version = "0.25.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "36820e9051aca1014ddc75770aab4d68bc1e9e632f0f5627c4086bc216fb583b"
|
||||
dependencies = [
|
||||
"ttf-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pango"
|
||||
version = "0.18.3"
|
||||
@@ -3842,6 +3951,12 @@ dependencies = [
|
||||
"siphasher 1.0.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pico-args"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315"
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.16"
|
||||
@@ -3897,6 +4012,19 @@ dependencies = [
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "png"
|
||||
version = "0.18.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"crc32fast",
|
||||
"fdeflate",
|
||||
"flate2",
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "polling"
|
||||
version = "3.11.0"
|
||||
@@ -3911,6 +4039,15 @@ dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "polycool"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50596ddc09eb5ad5f75cacd40209568e66df71baf86e1499a0e99c4cff12a5a6"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "potential_utf"
|
||||
version = "0.1.4"
|
||||
@@ -4467,6 +4604,20 @@ dependencies = [
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "resvg"
|
||||
version = "0.47.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9be183ad6a216aa96f33e4c8033b0988b8b3ea6fd2359d19af5bac4643fd8e81"
|
||||
dependencies = [
|
||||
"log",
|
||||
"pico-args",
|
||||
"rgb",
|
||||
"svgtypes",
|
||||
"tiny-skia",
|
||||
"usvg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rfd"
|
||||
version = "0.16.0"
|
||||
@@ -4491,6 +4642,15 @@ dependencies = [
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rgb"
|
||||
version = "0.8.53"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "47b34b781b31e5d73e9fbc8689c70551fd1ade9a19e3e28cfec8580a79290cc4"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
version = "0.17.14"
|
||||
@@ -4534,6 +4694,21 @@ dependencies = [
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "roxmltree"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97"
|
||||
|
||||
[[package]]
|
||||
name = "roxmltree"
|
||||
version = "0.21.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1964b10c76125c36f8afe190065a4bf9a87bf324842c05701330bba9f1cacbb"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-ini"
|
||||
version = "0.21.3"
|
||||
@@ -4689,6 +4864,24 @@ version = "1.0.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
|
||||
|
||||
[[package]]
|
||||
name = "rustybuzz"
|
||||
version = "0.20.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd3c7c96f8a08ee34eff8857b11b49b07d71d1c3f4e88f8a88d4c9e9f90b1702"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bytemuck",
|
||||
"core_maths",
|
||||
"log",
|
||||
"smallvec",
|
||||
"ttf-parser",
|
||||
"unicode-bidi-mirroring",
|
||||
"unicode-ccc",
|
||||
"unicode-properties",
|
||||
"unicode-script",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.22"
|
||||
@@ -5092,6 +5285,15 @@ version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e"
|
||||
|
||||
[[package]]
|
||||
name = "simplecss"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a9c6883ca9c3c7c90e888de77b7a5c849c779d25d74a1269b0218b14e8b136c"
|
||||
dependencies = [
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "siphasher"
|
||||
version = "0.3.11"
|
||||
@@ -5110,6 +5312,15 @@ version = "0.4.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
|
||||
|
||||
[[package]]
|
||||
name = "slotmap"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bdd58c3c93c3d278ca835519292445cb4b0d4dc59ccfdf7ceadaab3f8aeb4038"
|
||||
dependencies = [
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.15.1"
|
||||
@@ -5180,6 +5391,31 @@ version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
|
||||
|
||||
[[package]]
|
||||
name = "streamdeck-strip-render"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/FrostyCoolSlug/streamdeck-strip-render?rev=948c4653#948c4653ec310539e081fbdec334463a72766d89"
|
||||
dependencies = [
|
||||
"ab_glyph",
|
||||
"anyhow",
|
||||
"base64 0.22.1",
|
||||
"image",
|
||||
"log",
|
||||
"resvg",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_repr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strict-num"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731"
|
||||
dependencies = [
|
||||
"float-cmp",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "string_cache"
|
||||
version = "0.8.9"
|
||||
@@ -5226,6 +5462,16 @@ version = "2.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
||||
|
||||
[[package]]
|
||||
name = "svgtypes"
|
||||
version = "0.16.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "695b5790b3131dafa99b3bbfd25a216edb3d216dad9ca208d4657bfb8f2abc3d"
|
||||
dependencies = [
|
||||
"kurbo",
|
||||
"siphasher 1.0.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "swift-rs"
|
||||
version = "1.0.7"
|
||||
@@ -5483,7 +5729,7 @@ dependencies = [
|
||||
"ico",
|
||||
"json-patch 3.0.1",
|
||||
"plist",
|
||||
"png",
|
||||
"png 0.17.16",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"semver",
|
||||
@@ -5888,6 +6134,32 @@ dependencies = [
|
||||
"crunchy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tiny-skia"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "47ffee5eaaf5527f630fb0e356b90ebdec84d5d18d937c5e440350f88c5a91ea"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"arrayvec",
|
||||
"bytemuck",
|
||||
"cfg-if",
|
||||
"log",
|
||||
"png 0.18.1",
|
||||
"tiny-skia-path",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tiny-skia-path"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "edca365c3faccca67d06593c5980fa6c57687de727a03131735bb85f01fdeeb9"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"bytemuck",
|
||||
"strict-num",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tiny_http"
|
||||
version = "0.12.0"
|
||||
@@ -6186,7 +6458,7 @@ dependencies = [
|
||||
"objc2-core-graphics",
|
||||
"objc2-foundation",
|
||||
"once_cell",
|
||||
"png",
|
||||
"png 0.17.16",
|
||||
"serde",
|
||||
"thiserror 2.0.18",
|
||||
"windows-sys 0.60.2",
|
||||
@@ -6198,6 +6470,15 @@ version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
|
||||
|
||||
[[package]]
|
||||
name = "ttf-parser"
|
||||
version = "0.25.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31"
|
||||
dependencies = [
|
||||
"core_maths",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tungstenite"
|
||||
version = "0.28.0"
|
||||
@@ -6285,18 +6566,54 @@ dependencies = [
|
||||
"unic-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi-mirroring"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5dfa6e8c60bb66d49db113e0125ee8711b7647b5579dc7f5f19c42357ed039fe"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ccc"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce61d488bcdc9bc8b5d1772c404828b17fc481c0a582b5581e95fb233aef503e"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-properties"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-script"
|
||||
version = "0.5.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "383ad40bb927465ec0ce7720e033cb4ca06912855fc35db31b5755d0de75b1ee"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-vo"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1d386ff53b415b7fe27b50bb44679e2cc4660272694b7b6f3326d8480823a94"
|
||||
|
||||
[[package]]
|
||||
name = "untrusted"
|
||||
version = "0.9.0"
|
||||
@@ -6334,6 +6651,34 @@ dependencies = [
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "usvg"
|
||||
version = "0.47.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d46cf96c5f498d36b7a9693bc6a7075c0bb9303189d61b2249b0dc3d309c07de"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"data-url",
|
||||
"flate2",
|
||||
"fontdb",
|
||||
"imagesize",
|
||||
"kurbo",
|
||||
"log",
|
||||
"pico-args",
|
||||
"roxmltree 0.21.1",
|
||||
"rustybuzz",
|
||||
"simplecss",
|
||||
"siphasher 1.0.2",
|
||||
"strict-num",
|
||||
"svgtypes",
|
||||
"tiny-skia-path",
|
||||
"ttf-parser",
|
||||
"unicode-bidi",
|
||||
"unicode-script",
|
||||
"unicode-vo",
|
||||
"xmlwriter",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utf-8"
|
||||
version = "0.7.6"
|
||||
@@ -7376,6 +7721,12 @@ dependencies = [
|
||||
"quick-xml 0.30.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xmlwriter"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9"
|
||||
|
||||
[[package]]
|
||||
name = "yoke"
|
||||
version = "0.8.1"
|
||||
|
||||
@@ -23,6 +23,8 @@ tiny_http = "0.12"
|
||||
elgato-streamdeck = { version = "0.12", default-features = false, features = ["async"] }
|
||||
hidapi = "2.6"
|
||||
image = { version = "0.25", default-features = false, features = ["bmp", "jpeg"] }
|
||||
streamdeck-strip-render = { git = "https://github.com/FrostyCoolSlug/streamdeck-strip-render", rev = "948c4653" }
|
||||
|
||||
# Smaller utility libraries
|
||||
dashmap = { version = "6.1", features = ["serde"] }
|
||||
futures = "0.3"
|
||||
|
||||
+59
-1
@@ -1,4 +1,6 @@
|
||||
use crate::events::inbound;
|
||||
use crate::shared::{ActionInstance, Encoder, config_dir};
|
||||
use crate::store::profiles::{acquire_locks, get_slot};
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
@@ -10,7 +12,8 @@ use elgato_streamdeck::{
|
||||
images::{ImageRect, convert_image_with_format_async},
|
||||
info::Kind,
|
||||
};
|
||||
use image::GenericImageView as _;
|
||||
use image::{DynamicImage, GenericImageView as _};
|
||||
use serde_json::Value;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
static ELGATO_DEVICES: LazyLock<RwLock<HashMap<String, AsyncStreamDeck>>> = LazyLock::new(|| RwLock::new(HashMap::new()));
|
||||
@@ -25,6 +28,51 @@ fn extract_average_colour(img: &image::DynamicImage) -> (u8, u8, u8) {
|
||||
((r_sum / count) as u8, (g_sum / count) as u8, (b_sum / count) as u8)
|
||||
}
|
||||
|
||||
fn get_encoder_image(encoder: &Encoder, instance: &ActionInstance) -> Result<DynamicImage, anyhow::Error> {
|
||||
// Clone the layout so we can mutate it for rendering without persisting
|
||||
let mut layout = encoder.layout_parsed.clone();
|
||||
let path = config_dir().join("plugins").join(&instance.action.plugin);
|
||||
|
||||
// We need to validate whether title text and icon images are defined; if not, pull them from the state/action
|
||||
if let Some(items_array) = layout.get_mut("items").and_then(Value::as_array_mut) {
|
||||
// If the title is missing, provide it from the state/action
|
||||
if let Some(title_item) = items_array.iter_mut().find(|item| item.get("key").and_then(Value::as_str) == Some("title")) {
|
||||
let title_value = title_item.get("value").and_then(Value::as_str).unwrap_or("").trim();
|
||||
|
||||
if title_value.is_empty() {
|
||||
// Try to pull the title from the state
|
||||
let state_text = instance.states.get(instance.current_state as usize).and_then(|s| {
|
||||
let t = s.text.trim();
|
||||
if t.is_empty() { None } else { Some(t) }
|
||||
});
|
||||
|
||||
// If the state title is empty, fall back to the action name
|
||||
let title = state_text.unwrap_or(instance.action.name.as_str());
|
||||
title_item["value"] = Value::String(title.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
// If the icon is missing, provide it from the state/action
|
||||
if let Some(icon_item) = items_array.iter_mut().find(|item| item.get("key").and_then(Value::as_str) == Some("icon")) {
|
||||
let icon_empty = icon_item.get("value").and_then(Value::as_str).is_none_or(str::is_empty);
|
||||
if icon_empty {
|
||||
let icon = instance
|
||||
.states
|
||||
.get(instance.current_state as usize)
|
||||
.map(|state| &state.image)
|
||||
.filter(|image| !image.is_empty())
|
||||
.unwrap_or(&instance.action.icon);
|
||||
|
||||
if !icon.is_empty() {
|
||||
icon_item["value"] = Value::String(icon.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
streamdeck_strip_render::render_to_image(layout, &path, None)
|
||||
}
|
||||
|
||||
pub async fn update_image(context: &crate::shared::Context, image: Option<&str>) -> Result<(), anyhow::Error> {
|
||||
if let Some(device) = ELGATO_DEVICES.read().await.get(&context.device) {
|
||||
let kind = device.kind();
|
||||
@@ -38,6 +86,15 @@ pub async fn update_image(context: &crate::shared::Context, image: Option<&str>)
|
||||
let data = image.split_once(',').unwrap().1;
|
||||
let bytes = base64::engine::general_purpose::STANDARD.decode(data)?;
|
||||
if context.controller == "Encoder" {
|
||||
let locks = acquire_locks().await;
|
||||
if let Some(instance) = get_slot(context, &locks).await?
|
||||
&& let Some(encoder) = &instance.action.encoder
|
||||
{
|
||||
let img = get_encoder_image(encoder, instance)?;
|
||||
device.write_lcd(context.position as u16 * 200, 0, &ImageRect::from_image_async(img.clone())?).await?;
|
||||
} else {
|
||||
// If this encoder doesn't have a layout assigned to it, fall back and just render the icon.
|
||||
// This shouldn't happen and is a safety fallback behaviour.
|
||||
device
|
||||
.write_lcd(
|
||||
(context.position as u16 * 200) + 64,
|
||||
@@ -45,6 +102,7 @@ pub async fn update_image(context: &crate::shared::Context, image: Option<&str>)
|
||||
&ImageRect::from_image_async(image::load_from_memory(&bytes)?.resize(72, 72, image::imageops::FilterType::Nearest))?,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
} else if context.controller == "Infobar" {
|
||||
let img = image::load_from_memory(&bytes)?;
|
||||
let Some(format) = device.kind().lcd_image_format() else {
|
||||
|
||||
@@ -58,6 +58,8 @@ pub enum InboundEventType {
|
||||
LogMessage(PayloadEvent<misc::LogMessageEvent>),
|
||||
SetTitle(ContextAndPayloadEvent<states::SetTitlePayload>),
|
||||
SetImage(ContextAndPayloadEvent<states::SetImagePayload>),
|
||||
SetFeedbackLayout(ContextAndPayloadEvent<states::SetFeedbackLayoutPayload>),
|
||||
SetFeedback(ContextAndPayloadEvent<serde_json::Value>),
|
||||
SetState(ContextAndPayloadEvent<states::SetStatePayload>),
|
||||
ShowAlert(ContextEvent),
|
||||
ShowOk(ContextEvent),
|
||||
@@ -126,6 +128,8 @@ pub async fn process_incoming_message(data: Result<Message, Error>, uuid: &str,
|
||||
InboundEventType::LogMessage(event) => misc::log_message(Some(uuid), event).await,
|
||||
InboundEventType::SetTitle(event) => states::set_title(event).await,
|
||||
InboundEventType::SetImage(event) => states::set_image(event).await,
|
||||
InboundEventType::SetFeedbackLayout(event) => states::set_feedback_layout(event).await,
|
||||
InboundEventType::SetFeedback(event) => states::set_feedback(event).await,
|
||||
InboundEventType::SetState(event) => states::set_state(event).await,
|
||||
InboundEventType::ShowAlert(event) => misc::show_alert(event).await,
|
||||
InboundEventType::ShowOk(event) => misc::show_ok(event).await,
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
use super::ContextAndPayloadEvent;
|
||||
|
||||
use crate::events::frontend::instances::update_state;
|
||||
use crate::shared::{config_dir, load_encoder_layout};
|
||||
use crate::store::profiles::{acquire_locks_mut, debounce_profile_save, get_instance_mut, save_profile};
|
||||
|
||||
use anyhow::bail;
|
||||
use log::warn;
|
||||
use serde::Deserialize;
|
||||
use serde_json::Value;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct SetTitlePayload {
|
||||
@@ -22,6 +26,11 @@ pub struct SetStatePayload {
|
||||
state: u16,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct SetFeedbackLayoutPayload {
|
||||
layout: String,
|
||||
}
|
||||
|
||||
pub async fn set_title(event: ContextAndPayloadEvent<SetTitlePayload>) -> Result<(), anyhow::Error> {
|
||||
let mut locks = acquire_locks_mut().await;
|
||||
|
||||
@@ -101,6 +110,147 @@ pub async fn set_image(mut event: ContextAndPayloadEvent<SetImagePayload>) -> Re
|
||||
Ok(())
|
||||
}
|
||||
|
||||
const COMMON_KEYS: &[&str] = &["enabled", "opacity", "background"];
|
||||
const BAR_KEYS: &[&str] = &["bar_bg_c", "bar_border_c", "bar_fill_c", "border_w", "range", "subtype", "value"];
|
||||
pub async fn set_feedback(event: ContextAndPayloadEvent<Value>) -> Result<(), anyhow::Error> {
|
||||
let mut locks = acquire_locks_mut().await;
|
||||
|
||||
if let Some(instance) = get_instance_mut(&event.context, &mut locks).await?
|
||||
&& let Some(encoder) = &mut instance.action.encoder
|
||||
&& let Value::Object(map) = event.payload
|
||||
{
|
||||
let layout = &mut encoder.layout_parsed;
|
||||
|
||||
let Some(items_array) = layout.get_mut("items").and_then(Value::as_array_mut) else {
|
||||
bail!("Layout has no items array");
|
||||
};
|
||||
|
||||
for (key, payload_value) in &map {
|
||||
// Grab the item from the layout
|
||||
let Some(item) = items_array.iter_mut().find(|item| {
|
||||
matches!(
|
||||
item.get("key").and_then(|v| v.as_str()),
|
||||
Some(k) if k == key
|
||||
)
|
||||
}) else {
|
||||
warn!("setFeedback: no layout item found for key '{key}'");
|
||||
continue;
|
||||
};
|
||||
|
||||
match payload_value {
|
||||
// We have a direct value; find the key, and set it
|
||||
Value::String(_) | Value::Number(_) => {
|
||||
// Get the item type
|
||||
let Some(item_type) = item.get("type").and_then(Value::as_str) else {
|
||||
warn!("setFeedback: no type found for key '{key}'");
|
||||
continue;
|
||||
};
|
||||
|
||||
match item_type {
|
||||
"text" => {
|
||||
// We need to map the value to a string
|
||||
if let Value::Number(number) = payload_value {
|
||||
item["value"] = Value::String(number.to_string());
|
||||
} else {
|
||||
// Clone the string
|
||||
item["value"] = payload_value.clone();
|
||||
}
|
||||
}
|
||||
|
||||
"bar" | "gbar" => {
|
||||
if let Value::Number(value) = payload_value {
|
||||
if key == "value" {
|
||||
item["value"] = Value::Number(value.clone());
|
||||
}
|
||||
} else {
|
||||
warn!("setFeedback: bar/gbar expected number for key '{key}'");
|
||||
}
|
||||
}
|
||||
|
||||
"pixmap" => {
|
||||
// Update the pixmap value; this should already be a string
|
||||
item["value"] = payload_value.clone();
|
||||
}
|
||||
|
||||
// Ignore anything else
|
||||
_ => {
|
||||
warn!("setFeedback: unknown item type '{item_type}' for key '{key}'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We have an object, so we need to locate and map the change
|
||||
Value::Object(obj) => {
|
||||
// Get the item type
|
||||
let Some(item_type) = item.get("type").and_then(Value::as_str) else {
|
||||
warn!("setFeedback: missing or invalid 'type' field in item: {:?}", item);
|
||||
continue;
|
||||
};
|
||||
|
||||
// Get the valid keys for this item type
|
||||
let type_keys: Vec<&str> = match item_type {
|
||||
"text" => vec!["value", "color", "alignment", "font", "text-overflow"],
|
||||
"pixmap" => vec!["value"],
|
||||
"bar" => BAR_KEYS.to_vec(),
|
||||
"gbar" => BAR_KEYS.iter().copied().chain(["bar_h"]).collect(),
|
||||
unknown => {
|
||||
warn!("setFeedback: unknown item type '{unknown}' for key '{key}'");
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
// Add the common keys
|
||||
let valid_keys: Vec<&str> = COMMON_KEYS.iter().copied().chain(type_keys).collect();
|
||||
|
||||
// Iterate over the values in the object
|
||||
for (field, field_value) in obj {
|
||||
if valid_keys.contains(&field.as_str()) {
|
||||
item[field] = field_value.clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
warn!("setFeedback: key '{key}' has unexpected payload type, ignoring");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
update_state(crate::APP_HANDLE.get().unwrap(), instance.context.clone(), &mut locks).await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn set_feedback_layout(event: ContextAndPayloadEvent<SetFeedbackLayoutPayload>) -> Result<(), anyhow::Error> {
|
||||
let mut locks = acquire_locks_mut().await;
|
||||
if let Some(instance) = get_instance_mut(&event.context, &mut locks).await?
|
||||
&& let Some(encoder) = &mut instance.action.encoder
|
||||
{
|
||||
// We need to replace the existing parsed layout with the new one
|
||||
encoder.layout = event.payload.layout.clone();
|
||||
|
||||
// Make sure the layout is a full path to the JSON file
|
||||
if !encoder.layout.starts_with("$") {
|
||||
let path = config_dir().join("plugins").join(&instance.action.plugin);
|
||||
|
||||
let layout_path = path.join(&encoder.layout).canonicalize()?;
|
||||
if layout_path.starts_with(&path) {
|
||||
encoder.layout = layout_path.to_string_lossy().to_string();
|
||||
} else {
|
||||
// SetFeedbackLayout is sending a path outside our plugin; abort
|
||||
bail!("Encoder layout path is outside plugin directory: {}", encoder.layout);
|
||||
}
|
||||
}
|
||||
|
||||
encoder.layout_parsed = load_encoder_layout(&encoder.layout)?;
|
||||
|
||||
// Trigger a state update; should cause a redraw
|
||||
update_state(crate::APP_HANDLE.get().unwrap(), instance.context.clone(), &mut locks).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn set_state(event: ContextAndPayloadEvent<SetStatePayload>) -> Result<(), anyhow::Error> {
|
||||
let mut locks = acquire_locks_mut().await;
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ mod webserver;
|
||||
|
||||
use crate::APP_HANDLE;
|
||||
use crate::built_info::TARGET;
|
||||
use crate::shared::{CATEGORIES, Category, config_dir, convert_icon, is_flatpak, log_dir};
|
||||
use crate::shared::{CATEGORIES, Category, config_dir, convert_icon, is_flatpak, load_encoder_layout, log_dir};
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::process::{Child, Command, Stdio};
|
||||
@@ -91,6 +91,46 @@ pub async fn initialise_plugin(path: path::PathBuf, spawner_tx: mpsc::Sender<Spa
|
||||
action.property_inspector = path.join(property_inspector).to_string_lossy().to_string();
|
||||
}
|
||||
|
||||
if let Some(encoder) = &mut action.encoder {
|
||||
if !encoder.icon.is_empty() {
|
||||
let encoder_icon_path = path.join(encoder.icon.clone());
|
||||
encoder.icon = convert_icon(encoder_icon_path.to_str().unwrap().to_owned());
|
||||
}
|
||||
|
||||
if !encoder.background.is_empty() {
|
||||
let encoder_background_path = path.join(encoder.background.clone());
|
||||
encoder.background = convert_icon(encoder_background_path.to_str().unwrap().to_owned());
|
||||
}
|
||||
|
||||
if !encoder.layout.is_empty() {
|
||||
// Internal layouts start with $; custom layouts don't
|
||||
if !encoder.layout.starts_with("$") {
|
||||
let layout_path = path.join(&encoder.layout).canonicalize()?;
|
||||
|
||||
if layout_path.starts_with(&path) {
|
||||
encoder.layout = layout_path.to_string_lossy().to_string();
|
||||
} else {
|
||||
warn!("Encoder layout path is outside plugin directory: {}", encoder.layout);
|
||||
encoder.layout = String::new();
|
||||
}
|
||||
}
|
||||
|
||||
if !encoder.layout.is_empty() {
|
||||
// Parse out the initial layout
|
||||
let initial = load_encoder_layout(&encoder.layout);
|
||||
match initial {
|
||||
Ok(value) => {
|
||||
encoder.layout_parsed = value;
|
||||
}
|
||||
Err(e) => {
|
||||
warn!("Failed to load initial encoder layout: {}", e);
|
||||
encoder.layout_parsed = serde_json::Value::Null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for state in &mut action.states {
|
||||
if state.image == "actionDefaultImage" {
|
||||
state.image.clone_from(&action.icon);
|
||||
|
||||
@@ -6,6 +6,7 @@ use std::sync::LazyLock;
|
||||
use serde::{Deserialize, Deserializer, Serialize, de::Visitor};
|
||||
use serde_inline_default::serde_inline_default;
|
||||
|
||||
use anyhow::{Result, bail};
|
||||
use dashmap::DashMap;
|
||||
use tauri::Manager;
|
||||
use tokio::sync::RwLock;
|
||||
@@ -218,10 +219,91 @@ pub struct Action {
|
||||
#[serde(alias = "Controllers")]
|
||||
pub controllers: Vec<String>,
|
||||
|
||||
#[serde(default, alias = "Encoder")]
|
||||
pub encoder: Option<Encoder>,
|
||||
|
||||
#[serde(alias = "States")]
|
||||
pub states: Vec<ActionState>,
|
||||
}
|
||||
|
||||
/// An encoder, deserialised from the plugin manifest.
|
||||
#[serde_inline_default]
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub struct Encoder {
|
||||
#[serde_inline_default(String::new())]
|
||||
#[serde(alias = "Icon")]
|
||||
pub icon: String,
|
||||
|
||||
#[serde_inline_default(String::new())]
|
||||
#[serde(alias = "StackColor")]
|
||||
pub stack_color: String,
|
||||
|
||||
#[serde(default, alias = "TriggerDescription")]
|
||||
pub trigger_description: TriggerDescription,
|
||||
|
||||
#[serde_inline_default(String::new())]
|
||||
pub background: String,
|
||||
|
||||
#[serde_inline_default(String::new())]
|
||||
pub layout: String,
|
||||
|
||||
// Note: this is not a real manifest property; it is only used internally.
|
||||
#[serde_inline_default(serde_json::Value::Null)]
|
||||
pub layout_parsed: serde_json::Value,
|
||||
}
|
||||
|
||||
// This can be called from plugins/mod.rs; it can also be called from a setFeedbackLayout request
|
||||
pub fn load_encoder_layout(layout: &str) -> Result<serde_json::Value> {
|
||||
match layout {
|
||||
"$A0" => Ok(serde_json::from_str(include_str!("../../static/encoder_layouts/A0.json"))?),
|
||||
"$A1" => Ok(serde_json::from_str(include_str!("../../static/encoder_layouts/A1.json"))?),
|
||||
"$B1" => Ok(serde_json::from_str(include_str!("../../static/encoder_layouts/B1.json"))?),
|
||||
"$B2" => Ok(serde_json::from_str(include_str!("../../static/encoder_layouts/B2.json"))?),
|
||||
"$C1" => Ok(serde_json::from_str(include_str!("../../static/encoder_layouts/C1.json"))?),
|
||||
"$X1" => Ok(serde_json::from_str(include_str!("../../static/encoder_layouts/X1.json"))?),
|
||||
|
||||
path_str => {
|
||||
if path_str.is_empty() {
|
||||
bail!("Encoder layout path is blank, ignoring");
|
||||
}
|
||||
|
||||
// This doesn't match an existing built-in layout
|
||||
if path_str.starts_with('$') {
|
||||
bail!("Invalid encoder layout type: {}", path_str);
|
||||
}
|
||||
|
||||
let path = Path::new(path_str);
|
||||
if !path.extension().and_then(|e| e.to_str()).is_some_and(|e| e.eq_ignore_ascii_case("json")) {
|
||||
bail!("Invalid encoder layout type: {}", path_str);
|
||||
}
|
||||
|
||||
let content = std::fs::read_to_string(path)?;
|
||||
Ok(serde_json::from_str(&content)?)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Descriptions of touchstrip interaction response behaviours, to be shown to the user in the PI
|
||||
#[serde_inline_default]
|
||||
#[derive(Clone, Serialize, Deserialize, Default)]
|
||||
pub struct TriggerDescription {
|
||||
#[serde_inline_default(String::new())]
|
||||
#[serde(alias = "LongTouch")]
|
||||
pub long_touch: String,
|
||||
|
||||
#[serde_inline_default(String::new())]
|
||||
#[serde(alias = "Push")]
|
||||
pub push: String,
|
||||
|
||||
#[serde_inline_default(String::new())]
|
||||
#[serde(alias = "Rotate")]
|
||||
pub rotate: String,
|
||||
|
||||
#[serde_inline_default(String::new())]
|
||||
#[serde(alias = "Touch")]
|
||||
pub touch: String,
|
||||
}
|
||||
|
||||
/// Location metadata of a slot.
|
||||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct Context {
|
||||
|
||||
@@ -64,6 +64,18 @@ impl ProfileStores {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We need to populate instances from a profile without encoders with them
|
||||
for slot in store.value.sliders.iter_mut() {
|
||||
if let Some(instance) = slot
|
||||
&& instance.action.encoder.is_none()
|
||||
&& let Some(action) = actions.iter().find(|a| a.uuid == *instance.action.uuid)
|
||||
&& action.encoder.is_some()
|
||||
{
|
||||
instance.action.encoder = action.encoder.clone();
|
||||
}
|
||||
}
|
||||
|
||||
store.save()?;
|
||||
|
||||
self.stores.insert(canonical_id.clone(), store);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { ActionState } from "./ActionState.ts";
|
||||
import type { Encoder } from "./Encoder.ts";
|
||||
|
||||
export type Action = {
|
||||
name: string;
|
||||
@@ -10,5 +11,6 @@ export type Action = {
|
||||
supported_in_multi_actions: boolean;
|
||||
property_inspector: string;
|
||||
controllers: string[];
|
||||
encoder?: Encoder | null;
|
||||
states: ActionState[];
|
||||
};
|
||||
@@ -0,0 +1,15 @@
|
||||
export type Encoder = {
|
||||
icon: string;
|
||||
stack_color: string;
|
||||
trigger_description: TriggerDescription;
|
||||
background: string;
|
||||
layout: string;
|
||||
layout_parsed: object;
|
||||
};
|
||||
|
||||
export type TriggerDescription = {
|
||||
long_touch: string;
|
||||
push: string;
|
||||
rotate: string;
|
||||
touch: string;
|
||||
};
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"$schema": "https://schemas.elgato.com/streamdeck/plugins/layout.json",
|
||||
"id": "$A0",
|
||||
"items": [
|
||||
{
|
||||
"key": "full-canvas",
|
||||
"type": "pixmap",
|
||||
"rect": [0, 0, 200, 100]
|
||||
},
|
||||
{
|
||||
"key": "title",
|
||||
"type": "text",
|
||||
"rect": [16, 10, 168, 24],
|
||||
"zOrder": 1,
|
||||
"font": { "size": 16, "weight": 600 },
|
||||
"alignment": "left"
|
||||
},
|
||||
{
|
||||
"key": "canvas",
|
||||
"type": "pixmap",
|
||||
"rect": [16, 34, 168, 54],
|
||||
"zOrder": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"$schema": "https://schemas.elgato.com/streamdeck/plugins/layout.json",
|
||||
"id": "$A1",
|
||||
"items": [
|
||||
{
|
||||
"key": "title",
|
||||
"type": "text",
|
||||
"rect": [16, 10, 136, 24],
|
||||
"font": { "size": 16, "weight": 600 },
|
||||
"alignment": "left"
|
||||
},
|
||||
{
|
||||
"key": "icon",
|
||||
"type": "pixmap",
|
||||
"rect": [16, 40, 48, 48]
|
||||
},
|
||||
{
|
||||
"key": "value",
|
||||
"type": "text",
|
||||
"rect": [76, 40, 108, 32],
|
||||
"font": { "size": 24, "weight": 600 },
|
||||
"alignment": "right"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"$schema": "https://schemas.elgato.com/streamdeck/plugins/layout.json",
|
||||
"id": "$B1",
|
||||
"items": [
|
||||
{
|
||||
"key": "title",
|
||||
"type": "text",
|
||||
"rect": [16, 10, 136, 24],
|
||||
"font": { "size": 16, "weight": 600 },
|
||||
"alignment": "left"
|
||||
},
|
||||
{
|
||||
"key": "icon",
|
||||
"type": "pixmap",
|
||||
"rect": [16, 40, 48, 48]
|
||||
},
|
||||
{
|
||||
"key": "value",
|
||||
"type": "text",
|
||||
"rect": [76, 40, 108, 32],
|
||||
"font": { "size": 24, "weight": 600 },
|
||||
"alignment": "right"
|
||||
},
|
||||
{
|
||||
"key": "indicator",
|
||||
"type": "bar",
|
||||
"rect": [76, 74, 108, 12],
|
||||
"value": 20,
|
||||
"subtype": 4,
|
||||
"border_w": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"$schema": "https://schemas.elgato.com/streamdeck/plugins/layout.json",
|
||||
"id": "$B2",
|
||||
"items": [
|
||||
{
|
||||
"key": "title",
|
||||
"type": "text",
|
||||
"rect": [16, 10, 136, 24],
|
||||
"font": { "size": 16, "weight": 600 },
|
||||
"alignment": "left"
|
||||
},
|
||||
{
|
||||
"key": "icon",
|
||||
"type": "pixmap",
|
||||
"rect": [16, 40, 48, 48]
|
||||
},
|
||||
{
|
||||
"key": "value",
|
||||
"type": "text",
|
||||
"rect": [76, 40, 108, 32],
|
||||
"font": { "size": 24, "weight": 600 },
|
||||
"alignment": "right"
|
||||
},
|
||||
{
|
||||
"key": "indicator",
|
||||
"type": "gbar",
|
||||
"rect": [76, 74, 108, 20],
|
||||
"value": 20,
|
||||
"subtype": 4,
|
||||
"bar_h": 12,
|
||||
"border_w": 0,
|
||||
"bar_bg_c": "0:#ff0000,0.33:#a6d4ec,0.66:#f4b675,1:#00ff00"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"$schema": "https://schemas.elgato.com/streamdeck/plugins/layout.json",
|
||||
"id": "$C1",
|
||||
"items": [
|
||||
{
|
||||
"key": "title",
|
||||
"type": "text",
|
||||
"rect": [16, 10, 136, 24],
|
||||
"font": { "size": 16, "weight": 600 },
|
||||
"alignment": "left"
|
||||
},
|
||||
{
|
||||
"key": "icon1",
|
||||
"type": "pixmap",
|
||||
"rect": [16, 40, 24, 24]
|
||||
},
|
||||
{
|
||||
"key": "icon2",
|
||||
"type": "pixmap",
|
||||
"rect": [16, 68, 24, 24]
|
||||
},
|
||||
{
|
||||
"key": "indicator1",
|
||||
"type": "bar",
|
||||
"rect": [48, 46, 136, 12],
|
||||
"value": 70,
|
||||
"subtype": 4,
|
||||
"border_w": 0
|
||||
},
|
||||
{
|
||||
"key": "indicator2",
|
||||
"type": "bar",
|
||||
"rect": [48, 74, 136, 12],
|
||||
"value": 40,
|
||||
"subtype": 4,
|
||||
"border_w": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"$schema": "https://schemas.elgato.com/streamdeck/plugins/layout.json",
|
||||
"id": "$X1",
|
||||
"items": [
|
||||
{
|
||||
"key": "title",
|
||||
"type": "text",
|
||||
"rect": [16, 10, 136, 24],
|
||||
"font": { "size": 16, "weight": 600 },
|
||||
"alignment": "left"
|
||||
},
|
||||
{
|
||||
"key": "icon",
|
||||
"type": "pixmap",
|
||||
"rect": [76, 40, 48, 48]
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in new issue
Block a user