WIP: Add parsing of image filter strings

This commit is contained in:
Moritz Ruth 2023-12-30 01:58:02 +01:00
parent 19c62c20dd
commit 85214d6d35
Signed by: moritzruth
GPG key ID: C9BBAB79405EE56D
10 changed files with 776 additions and 53 deletions

550
Cargo.lock generated
View file

@ -26,6 +26,33 @@ dependencies = [
"memchr",
]
[[package]]
name = "android-tzdata"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
[[package]]
name = "android_system_properties"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
dependencies = [
"libc",
]
[[package]]
name = "arrayvec"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "backtrace"
version = "0.3.69"
@ -41,6 +68,12 @@ dependencies = [
"rustc-demangle",
]
[[package]]
name = "base64"
version = "0.21.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9"
[[package]]
name = "bitflags"
version = "1.3.2"
@ -53,6 +86,12 @@ version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
[[package]]
name = "bumpalo"
version = "3.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
[[package]]
name = "bytemuck"
version = "1.14.0"
@ -80,6 +119,19 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
version = "0.4.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38"
dependencies = [
"android-tzdata",
"iana-time-zone",
"num-traits",
"serde",
"windows-targets",
]
[[package]]
name = "color-eyre"
version = "0.6.2"
@ -152,6 +204,7 @@ dependencies = [
"ident_case",
"proc-macro2",
"quote",
"strsim",
"syn",
]
@ -171,8 +224,25 @@ name = "deckster"
version = "0.1.0"
dependencies = [
"color-eyre",
"humantime-serde",
"loupedeck_serial",
"piet",
"rgb",
"serde",
"serde_regex",
"serde_with",
"thiserror",
"toml",
]
[[package]]
name = "deranged"
version = "0.3.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8eb30d70a07a3b04884d2677f06bec33509dc67ca60d92949e5535352d3191dc"
dependencies = [
"powerfmt",
"serde",
]
[[package]]
@ -216,6 +286,12 @@ dependencies = [
"syn",
]
[[package]]
name = "equivalent"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
name = "eyre"
version = "0.6.11"
@ -238,6 +314,63 @@ version = "0.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
[[package]]
name = "hashbrown"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "hashbrown"
version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
[[package]]
name = "hex"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "humantime"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "humantime-serde"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57a3db5ea5923d99402c94e9feb261dc5ee9b4efa158b0315f788cf549cc200c"
dependencies = [
"humantime",
"serde",
]
[[package]]
name = "iana-time-zone"
version = "0.1.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"iana-time-zone-haiku",
"js-sys",
"wasm-bindgen",
"windows-core",
]
[[package]]
name = "iana-time-zone-haiku"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
dependencies = [
"cc",
]
[[package]]
name = "ident_case"
version = "1.0.1"
@ -250,6 +383,28 @@ version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
[[package]]
name = "indexmap"
version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
dependencies = [
"autocfg",
"hashbrown 0.12.3",
"serde",
]
[[package]]
name = "indexmap"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
dependencies = [
"equivalent",
"hashbrown 0.14.3",
"serde",
]
[[package]]
name = "io-kit-sys"
version = "0.4.0"
@ -260,6 +415,30 @@ dependencies = [
"mach2",
]
[[package]]
name = "itoa"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
[[package]]
name = "js-sys"
version = "0.3.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca"
dependencies = [
"wasm-bindgen",
]
[[package]]
name = "kurbo"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd85a5776cd9500c2e2059c8c76c3b01528566b7fcbaf8098b55a33fc298849b"
dependencies = [
"arrayvec",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
@ -292,6 +471,12 @@ dependencies = [
"pkg-config",
]
[[package]]
name = "log"
version = "0.4.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
[[package]]
name = "loupedeck_serial"
version = "0.1.0"
@ -314,6 +499,12 @@ dependencies = [
"libc",
]
[[package]]
name = "matches"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5"
[[package]]
name = "memchr"
version = "2.6.4"
@ -340,6 +531,15 @@ dependencies = [
"libc",
]
[[package]]
name = "num-traits"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
dependencies = [
"autocfg",
]
[[package]]
name = "object"
version = "0.32.2"
@ -361,6 +561,16 @@ version = "3.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f"
[[package]]
name = "piet"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e381186490a3e2017a506d62b759ea8eaf4be14666b13ed53973e8ae193451b1"
dependencies = [
"kurbo",
"unic-bidi",
]
[[package]]
name = "pin-project-lite"
version = "0.2.13"
@ -373,6 +583,12 @@ version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69d3587f8a9e599cc7ec2c00e331f71c4e69a5f9a4b8a6efd5b07466b9736f9a"
[[package]]
name = "powerfmt"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
[[package]]
name = "proc-macro2"
version = "1.0.71"
@ -435,12 +651,97 @@ version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
[[package]]
name = "ryu"
version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "serde"
version = "1.0.193"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.193"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.108"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "serde_regex"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8136f1a4ea815d7eac4101cfd0b16dc0cb5e1fe1b8609dfd728058656b7badf"
dependencies = [
"regex",
"serde",
]
[[package]]
name = "serde_spanned"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1"
dependencies = [
"serde",
]
[[package]]
name = "serde_with"
version = "3.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64cd236ccc1b7a29e7e2739f27c0b2dd199804abc4290e32f59f3b68d6405c23"
dependencies = [
"base64",
"chrono",
"hex",
"indexmap 1.9.3",
"indexmap 2.1.0",
"serde",
"serde_json",
"serde_with_macros",
"time",
]
[[package]]
name = "serde_with_macros"
version = "3.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93634eb5f75a2323b16de4748022ac4297f9e76b6dced2be287a099f41b5e788"
dependencies = [
"darling",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serialport"
version = "4.3.0"
@ -469,6 +770,12 @@ dependencies = [
"lazy_static",
]
[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "syn"
version = "2.0.43"
@ -510,6 +817,69 @@ dependencies = [
"once_cell",
]
[[package]]
name = "time"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f657ba42c3f86e7680e53c8cd3af8abbe56b5491790b46e22e19c0d57463583e"
dependencies = [
"deranged",
"itoa",
"powerfmt",
"serde",
"time-core",
"time-macros",
]
[[package]]
name = "time-core"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
[[package]]
name = "time-macros"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26197e33420244aeb70c3e8c78376ca46571bc4e701e4791c2cd9f57dcb3a43f"
dependencies = [
"time-core",
]
[[package]]
name = "toml"
version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35"
dependencies = [
"serde",
"serde_spanned",
"toml_datetime",
"toml_edit",
]
[[package]]
name = "toml_datetime"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1"
dependencies = [
"serde",
]
[[package]]
name = "toml_edit"
version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03"
dependencies = [
"indexmap 2.1.0",
"serde",
"serde_spanned",
"toml_datetime",
"winnow",
]
[[package]]
name = "tracing"
version = "0.1.40"
@ -560,6 +930,57 @@ dependencies = [
"thiserror",
]
[[package]]
name = "unic-bidi"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1356b759fb6a82050666f11dce4b6fe3571781f1449f3ef78074e408d468ec09"
dependencies = [
"matches",
"unic-ucd-bidi",
]
[[package]]
name = "unic-char-property"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221"
dependencies = [
"unic-char-range",
]
[[package]]
name = "unic-char-range"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc"
[[package]]
name = "unic-common"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc"
[[package]]
name = "unic-ucd-bidi"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d1d568b51222484e1f8209ce48caa6b430bf352962b877d592c29ab31fb53d8c"
dependencies = [
"unic-char-property",
"unic-char-range",
"unic-ucd-version",
]
[[package]]
name = "unic-ucd-version"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4"
dependencies = [
"unic-common",
]
[[package]]
name = "unicode-ident"
version = "1.0.12"
@ -572,6 +993,60 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
[[package]]
name = "wasm-bindgen"
version = "0.2.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826"
dependencies = [
"bumpalo",
"log",
"once_cell",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283"
dependencies = [
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f"
[[package]]
name = "winapi"
version = "0.3.9"
@ -593,3 +1068,78 @@ name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-core"
version = "0.51.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "winnow"
version = "0.5.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97a4882e6b134d6c28953a387571f1acdd3496830d5e36c5e3a1075580ea641c"
dependencies = [
"memchr",
]

View file

@ -4,6 +4,13 @@ version = "0.1.0"
edition = "2021"
[dependencies]
loupedeck_serial = { path = "../loupedeck_serial" }
color-eyre = "0.6.2"
humantime-serde = "1.1.1"
loupedeck_serial = { path = "../loupedeck_serial" }
piet = "0.6.2"
rgb = "0.8.37"
serde = { version = "1.0.193", features = ["derive"] }
serde_regex = "1.1.0"
serde_with = "3.4.0"
thiserror = "1.0.52"
toml = "0.8.8"

View file

@ -1,5 +1,6 @@
key_pages = ["./key-pages/*"]
button_pages = ["./button-page.toml"]
button_pages = ["./key-pages/*"]
knob_pages = ["./button-page.toml"]
[initial]
key_page = "default"

View file

@ -3,7 +3,7 @@ icon = "@ph/microphone-light"
mode.audio_volume.mode = "input"
mode.audio_volume.regex = "Microphone"
mode.audio_volume.label.muted = "Muted"
mode.audio_volume.icon.inactive = "@ph/microphone-sllash-light[color=red,opacity=90]"
mode.audio_volume.icon.inactive = "@ph/microphone-sllash-light[brighten=50,huerotate=red,opacity=90]"
mode.audio_volume.circle_indicator.color = "#ffffff"
mode.audio_volume.circle_indicator.width = 2
mode.audio_volume.circle_indicator.radius = 40

View file

@ -1,3 +1,5 @@
mod model;
use std::thread::sleep;
use std::time::{Duration, Instant};
use color_eyre::eyre::ContextCompat;

View file

@ -0,0 +1,25 @@
use serde::Deserialize;
#[derive(Debug, Deserialize)]
pub struct DecksterFile {
key_pages: Vec<String>,
button_pages: Vec<String>,
knob_pages: Vec<String>,
initial: DecksterFileInitial,
icon_packs: Vec<DecksterFileIconPack>
}
#[derive(Debug, Deserialize)]
pub struct DecksterFileInitial {
key_page: String,
button_page: String,
knob_page: String
}
#[derive(Debug, Deserialize)]
pub struct DecksterFileIconPack {
id: String,
path: String,
global_filter: String
}

View file

@ -0,0 +1,138 @@
use piet::kurbo::Rect;
use serde_with::DeserializeFromStr;
use std::fmt::{Display, Formatter, Write};
use std::str::FromStr;
use thiserror::Error;
#[derive(Debug, Clone)]
pub enum ImageTransform {
Invert,
Brighten(f32),
Crop(Rect),
HorizontalFlip,
VerticalFlip,
Rotate { quarter_clockwise_turns: u8 },
}
impl Display for ImageTransform {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
ImageTransform::Invert => f.write_str("invert"),
ImageTransform::Brighten(value) => f.write_fmt(format_args!("brighten={}", value)),
ImageTransform::Crop(_) => f.write_str("crop=<...>"),
ImageTransform::HorizontalFlip => f.write_str("horizontal_flip"),
ImageTransform::VerticalFlip => f.write_str("vertical_flip"),
ImageTransform::Rotate { quarter_clockwise_turns } => f.write_fmt(format_args!("rotate={}", quarter_clockwise_turns)),
}?;
Ok(())
}
}
#[derive(DeserializeFromStr)]
pub struct ImageFilter {
scale: f32,
alpha: f32,
blur: f32,
transforms: Vec<ImageTransform>,
}
#[derive(Debug, Error)]
pub enum ImageFilterFromStringError {
#[error("Unknown filter: {name}")]
UnknownFilter { name: String },
#[error("Filter {name} can only be used once.")]
SingletonSpecifiedMoreThanOnce { name: String },
#[error("All singleton filters must be placed before any transforms, but {singleton} was placed after {transform}.")]
SingletonSpecifiedAfterTransform { singleton: String, transform: ImageTransform },
#[error("{quarter_clockwise_turns} 90° turns can be simplified.")]
PointlessRotation { quarter_clockwise_turns: u8 },
#[error("Filter {filter_name} requires a value ({filter_name}=<value>).")]
FilterValueMissing { filter_name: String },
#[error("The following value supplied to {filter_name} could not be parsed: {raw_value}")]
FilterValueNotParsable { filter_name: String, raw_value: String },
#[error("{value} is not in the range ({range}) required by {filter_name}.")]
FilterValueNotInRange { filter_name: String, value: String, range: String },
}
impl FromStr for ImageFilter {
type Err = ImageFilterFromStringError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let filters: Vec<&str> = s.split('|').map(|f| f.trim()).collect();
let scale: Option<f32> = None;
let alpha: Option<f32> = None;
let blur: Option<f32> = None;
let mut transforms: Vec<ImageTransform> = Vec::new();
for filter in filters {
let split_filter = filter.split_once('=');
let (filter_name, optional_raw_value) = if let Some((filter_name, raw_value)) = split_filter {
(filter_name.to_owned(), Some(raw_value.to_owned()))
} else {
(filter.to_owned(), None)
};
let use_raw_value = || -> Result<String, ImageFilterFromStringError> {
optional_raw_value.ok_or_else(|| ImageFilterFromStringError::FilterValueMissing {
filter_name: filter_name.clone(),
})
};
match filter_name.as_str() {
"scale" | "alpha" | "blur" => {
if let Some(transform) = transforms.first() {
return Err(ImageFilterFromStringError::SingletonSpecifiedAfterTransform {
singleton: filter_name.clone(),
transform: transform.clone(),
});
}
#[allow(clippy::type_complexity)]
let (mut variable, check_range, range_string): (Option<f32>, Box<dyn Fn(&f32) -> bool>, &'static str) = match filter_name.as_str() {
"scale" => (scale, Box::new(|v| (0.0..=10.0_f32).contains(v)), "0..=10"),
"alpha" => (alpha, Box::new(|v| (0.0..1.0_f32).contains(v)), "0..<1"),
"blur" => (blur, Box::new(|v| (0.0..=10.0_f32).contains(v)), "0..=10"),
_ => unreachable!("filter_name is narrowed down in the outer match statement"),
};
if variable.is_some() {
return Err(ImageFilterFromStringError::SingletonSpecifiedMoreThanOnce { name: filter_name.clone() });
}
let raw_value = use_raw_value()?;
let value = f32::from_str(&raw_value).map_err(|_| ImageFilterFromStringError::FilterValueNotParsable {
filter_name: filter_name.clone(),
raw_value,
})?;
if !check_range(&value) {
return Err(ImageFilterFromStringError::FilterValueNotInRange {
filter_name: filter_name.clone(),
range: range_string.to_owned(),
value: value.to_string(),
});
}
let _ = variable.insert(value);
}
_ => return Err(ImageFilterFromStringError::UnknownFilter { name: filter_name }),
}
}
Ok(ImageFilter {
scale: scale.unwrap_or(1.0),
alpha: alpha.unwrap_or(1.0),
blur: blur.unwrap_or(0.0),
transforms,
})
}
}

View file

@ -0,0 +1,2 @@
mod deckster_file;
mod image_filter;

View file

@ -1,17 +1,17 @@
use std::{io, thread};
use std::io::{Read, Write};
use std::sync::mpsc;
use std::thread::{sleep, spawn, Thread};
use std::time::Duration;
use bytes::Bytes;
use rgb::{ComponentSlice, RGB8};
use serialport::{ClearBuffer, DataBits, FlowControl, Parity, SerialPortType, StopBits};
use thiserror::Error;
use crate::characteristics::{CHARACTERISTICS, LoupedeckButton, LoupedeckDeviceCharacteristics, LoupedeckDeviceDisplayConfiguration};
use crate::characteristics::{LoupedeckButton, LoupedeckDeviceCharacteristics, LoupedeckDeviceDisplayConfiguration, CHARACTERISTICS};
use crate::commands::{LoupedeckCommand, VibrationPattern};
use crate::events::{LoupedeckEvent, LoupedeckInternalEvent};
use crate::messages::{read_messages_worker, write_messages_worker, WS_UPGRADE_REQUEST, WS_UPGRADE_RESPONSE_START};
use crate::util::convert_rgb888_to_rgb565;
use bytes::Bytes;
use rgb::{ComponentSlice, RGB8};
use serialport::{ClearBuffer, DataBits, FlowControl, Parity, SerialPortType, StopBits};
use std::io::{Read, Write};
use std::sync::mpsc;
use std::thread::sleep;
use std::time::Duration;
use std::{io, thread};
use thiserror::Error;
#[derive(Debug)]
pub struct AvailableLoupedeckDevice {
@ -72,7 +72,7 @@ pub enum SetButtonColorError {
UnknownButton,
#[error("The button does not allow setting a color.")]
ColorNotSupported
ColorNotSupported,
}
#[derive(Debug, Error)]
@ -84,10 +84,7 @@ pub enum ReplaceFramebufferAreaError {
OutOfBounds,
#[error("Given the specified dimensions, the buffer size must be {expected} but it was {actual}.")]
WrongBufferSize {
expected: usize,
actual: usize,
},
WrongBufferSize { expected: usize, actual: usize },
}
impl LoupedeckDevice {
@ -139,10 +136,10 @@ impl LoupedeckDevice {
y: u16,
width: u16,
height: u16,
buffer: &[RGB8]
buffer: &[RGB8],
) -> Result<(), ReplaceFramebufferAreaError> {
if !std::ptr::eq(display, &self.characteristics.key_grid_display) &&
!self.characteristics.additional_displays.iter().any(|d| std::ptr::eq(display, d)) {
if !std::ptr::eq(display, &self.characteristics.key_grid_display) && !self.characteristics.additional_displays.iter().any(|d| std::ptr::eq(display, d))
{
return Err(ReplaceFramebufferAreaError::UnknownDisplay);
}
@ -171,55 +168,55 @@ impl LoupedeckDevice {
let local_x = display.local_offset_x + x;
let local_y = display.local_offset_y + y;
self.commands_sender.send(LoupedeckCommand::ReplaceFramebufferArea {
display_id: display.id,
x: local_x,
y: local_y,
width,
height,
buffer: converted_buffer.freeze(),
}).unwrap();
self.commands_sender
.send(LoupedeckCommand::ReplaceFramebufferArea {
display_id: display.id,
x: local_x,
y: local_y,
width,
height,
buffer: converted_buffer.freeze(),
})
.unwrap();
Ok(())
}
pub fn refresh_display(&self, display: &LoupedeckDeviceDisplayConfiguration) -> Result<(), RefreshDisplayError>{
if !std::ptr::eq(display, &self.characteristics.key_grid_display) &&
!self.characteristics.additional_displays.iter().any(|d| std::ptr::eq(display, d)) {
pub fn refresh_display(&self, display: &LoupedeckDeviceDisplayConfiguration) -> Result<(), RefreshDisplayError> {
if !std::ptr::eq(display, &self.characteristics.key_grid_display) && !self.characteristics.additional_displays.iter().any(|d| std::ptr::eq(display, d))
{
return Err(RefreshDisplayError::UnknownDisplay);
}
self.commands_sender.send(LoupedeckCommand::RefreshDisplay {
display_id: display.id
}).unwrap();
self.commands_sender.send(LoupedeckCommand::RefreshDisplay { display_id: display.id }).unwrap();
Ok(())
}
pub fn vibrate(&self, pattern: VibrationPattern) {
self.commands_sender.send(LoupedeckCommand::Vibrate {
pattern
}).unwrap();
self.commands_sender.send(LoupedeckCommand::Vibrate { pattern }).unwrap();
}
pub fn discover() -> Result<Vec<AvailableLoupedeckDevice>, serialport::Error> {
let ports = serialport::available_ports()?;
Ok(ports.iter().filter_map(|port| {
if let SerialPortType::UsbPort(info) = &port.port_type {
let characteristics = CHARACTERISTICS.iter()
.find(|c| c.vendor_id == info.vid && c.product_id == info.pid);
Ok(ports
.iter()
.filter_map(|port| {
if let SerialPortType::UsbPort(info) = &port.port_type {
let characteristics = CHARACTERISTICS.iter().find(|c| c.vendor_id == info.vid && c.product_id == info.pid);
if let Some(characteristics) = characteristics {
return Some(AvailableLoupedeckDevice {
port_name: port.port_name.clone(),
characteristics,
});
if let Some(characteristics) = characteristics {
return Some(AvailableLoupedeckDevice {
port_name: port.port_name.clone(),
characteristics,
});
}
}
}
None
}).collect::<Vec<_>>())
None
})
.collect::<Vec<_>>())
}
pub(crate) fn connect(AvailableLoupedeckDevice { port_name, characteristics }: &AvailableLoupedeckDevice) -> Result<LoupedeckDevice, ConnectError> {
@ -262,13 +259,13 @@ impl LoupedeckDevice {
commands_sender.send(LoupedeckCommand::RequestSerialNumber).unwrap();
let serial_number = match internal_events_receiver.recv_timeout(Duration::from_secs(1)) {
Ok(LoupedeckInternalEvent::GetSerialNumberResponse { serial_number }) => Ok(serial_number),
_ => Err(ConnectError::WrongLateHandshakeResponse)
_ => Err(ConnectError::WrongLateHandshakeResponse),
}?;
commands_sender.send(LoupedeckCommand::RequestFirmwareVersion).unwrap();
let firmware_version = match internal_events_receiver.recv_timeout(Duration::from_secs(1)) {
Ok(LoupedeckInternalEvent::GetFirmwareVersionResponse { firmware_version }) => Ok(firmware_version),
_ => Err(ConnectError::WrongLateHandshakeResponse)
_ => Err(ConnectError::WrongLateHandshakeResponse),
}?;
drop(internal_events_receiver);

1
rustfmt.toml Normal file
View file

@ -0,0 +1 @@
max_width = 160