From 1d584771d0461934b2af2ceb005808eae59fbe5e Mon Sep 17 00:00:00 2001 From: Jordan Doyle Date: Sun, 22 Oct 2023 23:03:16 +0100 Subject: [PATCH] Initial commit --- .gitattributes | 1 + .gitignore | 2 ++ Cargo.lock | 3732 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 8 ++++++++ README.md | 8 ++++++++ assets/icons/README.md | 3 +++ assets/icons/back.svg | 3 +++ assets/icons/backward.svg | 3 +++ assets/icons/forward.svg | 3 +++ assets/icons/hamburger.svg | 3 +++ assets/icons/home.svg | 3 +++ assets/icons/light-bulb.svg | 3 +++ assets/icons/pause.svg | 3 +++ assets/icons/play.svg | 3 +++ assets/icons/repeat.svg | 3 +++ assets/icons/speaker-muted.svg | 3 +++ assets/icons/speaker.svg | 3 +++ assets/images/bathroom.jpg | 3 +++ assets/images/bedroom.jpg | 3 +++ assets/images/dining_room.jpg | 3 +++ assets/images/kitchen.jpg | 3 +++ assets/images/living_room.jpg | 3 +++ config-example.toml | 3 +++ rustfmt.toml | 7 +++++++ shalom/Cargo.toml | 19 +++++++++++++++++++ shalom/src/config.rs | 16 ++++++++++++++++ shalom/src/hass_client.rs | 142 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ shalom/src/main.rs | 202 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ shalom/src/oracle.rs | 1 + shalom/src/pages/mod.rs | 2 ++ shalom/src/pages/omni.rs | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ shalom/src/pages/room.rs | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ shalom/src/theme.rs | 126 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ shalom/src/widgets/context_menu.rs | 458 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ shalom/src/widgets/image_card.rs | 237 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ shalom/src/widgets/media_player.rs | 233 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ shalom/src/widgets/mod.rs | 6 ++++++ shalom/src/widgets/mouse_area.rs | 347 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ shalom/src/widgets/toggle_card.rs | 240 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ shalom/src/widgets/track_card.rs | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 40 files changed, 6089 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 README.md create mode 100644 assets/icons/README.md create mode 100644 assets/icons/back.svg create mode 100644 assets/icons/backward.svg create mode 100644 assets/icons/forward.svg create mode 100644 assets/icons/hamburger.svg create mode 100644 assets/icons/home.svg create mode 100644 assets/icons/light-bulb.svg create mode 100644 assets/icons/pause.svg create mode 100644 assets/icons/play.svg create mode 100644 assets/icons/repeat.svg create mode 100644 assets/icons/speaker-muted.svg create mode 100644 assets/icons/speaker.svg create mode 100644 assets/images/bathroom.jpg create mode 100644 assets/images/bedroom.jpg create mode 100644 assets/images/dining_room.jpg create mode 100644 assets/images/kitchen.jpg create mode 100644 assets/images/living_room.jpg create mode 100644 config-example.toml create mode 100644 rustfmt.toml create mode 100644 shalom/Cargo.toml create mode 100644 shalom/src/config.rs create mode 100644 shalom/src/hass_client.rs create mode 100644 shalom/src/main.rs create mode 100644 shalom/src/oracle.rs create mode 100644 shalom/src/pages/mod.rs create mode 100644 shalom/src/pages/omni.rs create mode 100644 shalom/src/pages/room.rs create mode 100644 shalom/src/theme.rs create mode 100644 shalom/src/widgets/context_menu.rs create mode 100644 shalom/src/widgets/image_card.rs create mode 100644 shalom/src/widgets/media_player.rs create mode 100644 shalom/src/widgets/mod.rs create mode 100644 shalom/src/widgets/mouse_area.rs create mode 100644 shalom/src/widgets/toggle_card.rs create mode 100644 shalom/src/widgets/track_card.rs diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..4fae6dc --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.jpg filter=lfs diff=lfs merge=lfs -text diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fabfb87 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +/config.toml diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..9b5d1f8 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,3732 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ab_glyph" +version = "0.2.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1061f3ff92c2f65800df1f12fc7b4ff44ee14783104187dd04dfee6f11b0fd2" +dependencies = [ + "ab_glyph_rasterizer", + "owned_ttf_parser", +] + +[[package]] +name = "ab_glyph_rasterizer" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046" + +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "ahash" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", +] + +[[package]] +name = "aliasable" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" + +[[package]] +name = "allocator-api2" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" + +[[package]] +name = "android-activity" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64529721f27c2314ced0890ce45e469574a73e5e6fdd6e9da1860eb29285f5e0" +dependencies = [ + "android-properties", + "bitflags 1.3.2", + "cc", + "jni-sys", + "libc", + "log", + "ndk", + "ndk-context", + "ndk-sys", + "num_enum 0.6.1", +] + +[[package]] +name = "android-properties" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04" + +[[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 = "approx" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits", +] + +[[package]] +name = "arrayref" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "ash" +version = "0.37.3+1.3.251" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e9c3835d686b0a6084ab4234fcd1b07dbf6e4767dce60874b12356a25ecd4a" +dependencies = [ + "libloading 0.7.4", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base64" +version = "0.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bit_field" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" + +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-sys" +version = "0.1.0-beta.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa55741ee90902547802152aaf3f8e5248aab7e21468089560d4c8840561146" +dependencies = [ + "objc-sys", +] + +[[package]] +name = "block2" +version = "0.2.0-alpha.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dd9e63c1744f755c2f60332b88de39d341e5e86239014ad839bd71c106dec42" +dependencies = [ + "block-sys", + "objc2-encode", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "965ab7eb5f8f97d2a083c799f3a1b994fc397b2fe2da5d1da1626ce15a39f2b1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" + +[[package]] +name = "calloop" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e0d00eb1ea24371a97d2da6201c6747a633dc6dc1988ef503403b4c59504a8" +dependencies = [ + "bitflags 1.3.2", + "log", + "nix 0.25.1", + "slotmap", + "thiserror", + "vec_map", +] + +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "jobserver", + "libc", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + +[[package]] +name = "clipboard-win" +version = "4.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7191c27c2357d9b7ef96baac1773290d4ca63b24205b82a3fd8a0637afcf0362" +dependencies = [ + "error-code", + "str-buf", + "winapi", +] + +[[package]] +name = "clipboard_macos" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "145a7f9e9b89453bc0a5e32d166456405d389cea5b578f57f1274b1397588a95" +dependencies = [ + "objc", + "objc-foundation", + "objc_id", +] + +[[package]] +name = "clipboard_wayland" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f6364a9f7a66f2ac1a1a098aa1c7f6b686f2496c6ac5e5c0d773445df912747" +dependencies = [ + "smithay-clipboard", +] + +[[package]] +name = "clipboard_x11" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "983a7010836ecd04dde2c6d27a0cb56ec5d21572177e782bdcb24a600124e921" +dependencies = [ + "thiserror", + "x11rb 0.9.0", +] + +[[package]] +name = "cocoa" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f425db7937052c684daec3bd6375c8abe2d146dca4b8b143d6db777c39138f3a" +dependencies = [ + "bitflags 1.3.2", + "block", + "cocoa-foundation", + "core-foundation", + "core-graphics", + "foreign-types", + "libc", + "objc", +] + +[[package]] +name = "cocoa-foundation" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c6234cbb2e4c785b456c0644748b1ac416dd045799740356f8363dfe00c93f7" +dependencies = [ + "bitflags 1.3.2", + "block", + "core-foundation", + "core-graphics-types", + "libc", + "objc", +] + +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + +[[package]] +name = "com-rs" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf43edc576402991846b093a7ca18a3477e0ef9c588cde84964b5d3e43016642" + +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" + +[[package]] +name = "core-graphics" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-graphics-types", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bb142d41022986c1d8ff29103a1411c8a3dfad3552f87a4f8dc50d61d4f4e33" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "libc", +] + +[[package]] +name = "cosmic-text" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0b68966c2543609f8d92f9d33ac3b719b2a67529b0c6c0b3e025637b477eef9" +dependencies = [ + "aliasable", + "fontdb", + "libm", + "log", + "rangemap", + "rustybuzz 0.8.0", + "swash", + "sys-locale", + "unicode-bidi", + "unicode-linebreak", + "unicode-script", + "unicode-segmentation", +] + +[[package]] +name = "cpufeatures" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fbc60abd742b35f2492f808e1abbb83d45f72db402e14c55057edc9c7b1e9e4" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset 0.9.0", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "d3d12" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8f0de2f5a8e7bd4a9eec0e3c781992a4ce1724f68aec7d7a3715344de8b39da" +dependencies = [ + "bitflags 1.3.2", + "libloading 0.7.4", + "winapi", +] + +[[package]] +name = "data-encoding" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" + +[[package]] +name = "data-url" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d7439c3735f405729d52c3fbbe4de140eaf938a1fe47d227c27f8254d4302a5" + +[[package]] +name = "deranged" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f32d04922c60427da6f9fef14d042d9edddef64cb9d4ce0d64d0685fbeb1fd3" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "dispatch" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" + +[[package]] +name = "dlib" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" +dependencies = [ + "libloading 0.8.1", +] + +[[package]] +name = "downcast-rs" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "error-code" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64f18991e7bf11e7ffee451b5318b5c1a73c52d0d0ada6e5a3017c8c1ced6a21" +dependencies = [ + "libc", + "str-buf", +] + +[[package]] +name = "etagere" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcf22f748754352918e082e0039335ee92454a5d62bcaf69b5e8daf5907d9644" +dependencies = [ + "euclid", + "svg_fmt", +] + +[[package]] +name = "euclid" +version = "0.22.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f253bc5c813ca05792837a0ff4b3a580336b224512d48f7eda1d7dd9210787" +dependencies = [ + "num-traits", +] + +[[package]] +name = "exr" +version = "1.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "279d3efcc55e19917fff7ab3ddd6c14afb6a90881a0078465196fe2f99d08c56" +dependencies = [ + "bit_field", + "flume", + "half", + "lebe", + "miniz_oxide", + "rayon-core", + "smallvec", + "zune-inflate", +] + +[[package]] +name = "fast-srgb8" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd2e7510819d6fbf51a5545c8f922716ecfb14df168a3242f7d33e0239efe6a1" + +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + +[[package]] +name = "fdeflate" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d329bdeac514ee06249dabc27877490f17f5d371ec693360768b838e19f3ae10" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "flate2" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "float-cmp" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" + +[[package]] +name = "flume" +version = "0.10.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577" +dependencies = [ + "futures-core", + "futures-sink", + "nanorand", + "pin-project", + "spin", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "fontconfig-parser" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "674e258f4b5d2dcd63888c01c68413c51f565e8af99d2f7701c7b81d79ef41c4" +dependencies = [ + "roxmltree", +] + +[[package]] +name = "fontdb" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af8d8cbea8f21307d7e84bca254772981296f058a1d36b461bf4d83a7499fc9e" +dependencies = [ + "fontconfig-parser", + "log", + "memmap2 0.6.2", + "slotmap", + "tinyvec", + "ttf-parser 0.19.2", +] + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" + +[[package]] +name = "futures-executor" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", + "num_cpus", +] + +[[package]] +name = "futures-io" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" + +[[package]] +name = "futures-macro" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + +[[package]] +name = "futures-sink" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" + +[[package]] +name = "futures-task" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" + +[[package]] +name = "futures-util" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "gethostname" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1ebd34e35c46e00bb73e81363248d627782724609fe1b6396f553f68fe3862e" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "gif" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80792593675e051cf94a4b111980da2ba60d4a83e43e0048c5693baab3977045" +dependencies = [ + "color_quant", + "weezl", +] + +[[package]] +name = "gimli" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" + +[[package]] +name = "glam" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5418c17512bdf42730f9032c74e1ae39afc408745ebb2acf72fbc4691c17945" + +[[package]] +name = "glow" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca0fe580e4b60a8ab24a868bc08e2f03cbcb20d3d676601fa909386713333728" +dependencies = [ + "js-sys", + "slotmap", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "glyphon" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e87caa7459145f5e5f167bf34db4532901404c679e62339fb712a0e3ccf722a" +dependencies = [ + "cosmic-text", + "etagere", + "lru", + "wgpu", +] + +[[package]] +name = "gpu-alloc" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22beaafc29b38204457ea030f6fb7a84c9e4dd1b86e311ba0542533453d87f62" +dependencies = [ + "bitflags 1.3.2", + "gpu-alloc-types", +] + +[[package]] +name = "gpu-alloc-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54804d0d6bc9d7f26db4eaec1ad10def69b599315f487d32c334a80d1efe67a5" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "gpu-allocator" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce95f9e2e11c2c6fadfce42b5af60005db06576f231f5c92550fdded43c423e8" +dependencies = [ + "backtrace", + "log", + "thiserror", + "winapi", + "windows", +] + +[[package]] +name = "gpu-descriptor" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc11df1ace8e7e564511f53af41f3e42ddc95b56fd07b3f4445d2a6048bc682c" +dependencies = [ + "bitflags 2.4.1", + "gpu-descriptor-types", + "hashbrown 0.14.2", +] + +[[package]] +name = "gpu-descriptor-types" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bf0b36e6f090b7e1d8a4b49c0cb81c1f8376f72198c65dd3ad9ff3556b8b78c" +dependencies = [ + "bitflags 2.4.1", +] + +[[package]] +name = "guillotiere" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b62d5865c036cb1393e23c50693df631d3f5d7bcca4c04fe4cc0fd592e74a782" +dependencies = [ + "euclid", + "svg_fmt", +] + +[[package]] +name = "half" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc52e53916c08643f1b56ec082790d1e86a32e58dc5268f897f313fbae7b4872" +dependencies = [ + "cfg-if", + "crunchy", +] + +[[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.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" +dependencies = [ + "ahash", + "allocator-api2", +] + +[[package]] +name = "hassle-rs" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1397650ee315e8891a0df210707f0fc61771b0cc518c3023896064c5407cb3b0" +dependencies = [ + "bitflags 1.3.2", + "com-rs", + "libc", + "libloading 0.7.4", + "thiserror", + "widestring", + "winapi", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" + +[[package]] +name = "hexf-parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" + +[[package]] +name = "http" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "iced" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c708807ec86f99dd729dc4d42db5239acf118cec14d3c5f57679dcfdbbc472b1" +dependencies = [ + "iced_core", + "iced_futures", + "iced_renderer", + "iced_widget", + "iced_winit", + "image", + "thiserror", +] + +[[package]] +name = "iced_core" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64d0bc4fbf018576d08d93f838e6058cc6f10bbc05e04ae249a2a44dffb4ebc8" +dependencies = [ + "bitflags 1.3.2", + "instant", + "log", + "palette", + "thiserror", + "twox-hash", +] + +[[package]] +name = "iced_futures" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14dab0054a9c7a1cbce227a8cd9ee4a094497b3d06094551ac6c1488d563802e" +dependencies = [ + "futures", + "iced_core", + "log", + "tokio", + "wasm-bindgen-futures", + "wasm-timer", +] + +[[package]] +name = "iced_graphics" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67ff14447a221e9e9205a13d84d7bbdf0636a3b1daa02cfca690ed09689c4d2b" +dependencies = [ + "bitflags 1.3.2", + "bytemuck", + "glam", + "half", + "iced_core", + "image", + "kamadak-exif", + "log", + "raw-window-handle", + "thiserror", +] + +[[package]] +name = "iced_renderer" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1033385b0db0099a0d13178c9ff93c1ce11e7d0177522acf578bf79febdb2af8" +dependencies = [ + "iced_graphics", + "iced_tiny_skia", + "iced_wgpu", + "log", + "raw-window-handle", + "thiserror", +] + +[[package]] +name = "iced_runtime" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c6c89853e1250c6fac82c5015fa2144517be9b33d4b8e456f10e198b23e28bd" +dependencies = [ + "iced_core", + "iced_futures", + "thiserror", +] + +[[package]] +name = "iced_style" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d85c47d9d13e2281f75ddf98c865daf2101632bd2b855c401dd0b1c8b81a31a0" +dependencies = [ + "iced_core", + "once_cell", + "palette", +] + +[[package]] +name = "iced_tiny_skia" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7715f6222c9470bbbd75a39f70478fa0d1bdfb81a377a34fd1b090ffccc480b" +dependencies = [ + "bytemuck", + "cosmic-text", + "iced_graphics", + "kurbo", + "log", + "raw-window-handle", + "resvg", + "rustc-hash", + "softbuffer", + "tiny-skia 0.10.0", + "twox-hash", +] + +[[package]] +name = "iced_wgpu" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703f7c5de46b997ed7b18e05ec67059dcdf3beeac51e917c21071b021bb848b9" +dependencies = [ + "bitflags 1.3.2", + "bytemuck", + "futures", + "glam", + "glyphon", + "guillotiere", + "iced_graphics", + "log", + "once_cell", + "raw-window-handle", + "resvg", + "rustc-hash", + "twox-hash", + "wgpu", +] + +[[package]] +name = "iced_widget" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a177219ae51c3ba08f228ab932354b360cc669e94aec50c01e7c9b675f074c7c" +dependencies = [ + "iced_renderer", + "iced_runtime", + "iced_style", + "num-traits", + "ouroboros", + "thiserror", + "unicode-segmentation", +] + +[[package]] +name = "iced_winit" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ecea26fcc8074373f6011d2193d63445617d900a428eb4df66c0e5658408fb6" +dependencies = [ + "iced_graphics", + "iced_runtime", + "iced_style", + "log", + "raw-window-handle", + "thiserror", + "web-sys", + "winapi", + "window_clipboard", + "winit", +] + +[[package]] +name = "idna" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "image" +version = "0.24.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f3dfdbdd72063086ff443e297b61695500514b1e41095b6fb9a5ab48a70a711" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "exr", + "gif", + "jpeg-decoder", + "num-rational", + "num-traits", + "png", + "qoi", + "tiff", +] + +[[package]] +name = "imagesize" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "029d73f573d8e8d63e6d5020011d3255b28c3ba85d6cf870a07184ed23de9284" + +[[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", +] + +[[package]] +name = "indexmap" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" +dependencies = [ + "equivalent", + "hashbrown 0.14.2", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "jobserver" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" +dependencies = [ + "libc", +] + +[[package]] +name = "jpeg-decoder" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc0000e42512c92e31c2252315bda326620a4e034105e900c98ec492fa077b3e" +dependencies = [ + "rayon", +] + +[[package]] +name = "js-sys" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "kamadak-exif" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef4fc70d0ab7e5b6bafa30216a6b48705ea964cdfc29c050f2412295eba58077" +dependencies = [ + "mutate_once", +] + +[[package]] +name = "keyframe" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60708bf7981518d09095d6f5673ce5cf6a64f1e0d9708b554f670e6d9d2bd9a9" +dependencies = [ + "mint", + "num-traits", +] + +[[package]] +name = "khronos-egl" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c2352bd1d0bceb871cb9d40f24360c8133c11d7486b68b5381c1dd1a32015e3" +dependencies = [ + "libc", + "libloading 0.7.4", + "pkg-config", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "lebe" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" + +[[package]] +name = "libc" +version = "0.2.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" + +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "libloading" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "lock_api" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "lru" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a83fb7698b3643a0e34f9ae6f2e8f0178c0fd42f8b59d493aa271ff3a5bf21" +dependencies = [ + "hashbrown 0.14.2", +] + +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + +[[package]] +name = "memchr" +version = "2.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" + +[[package]] +name = "memmap2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" +dependencies = [ + "libc", +] + +[[package]] +name = "memmap2" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d28bba84adfe6646737845bc5ebbfa2c08424eb1c37e94a1fd2a82adb56a872" +dependencies = [ + "libc", +] + +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + +[[package]] +name = "memoffset" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +dependencies = [ + "autocfg", +] + +[[package]] +name = "memoffset" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "metal" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de11355d1f6781482d027a3b4d4de7825dcedb197bf573e0596d00008402d060" +dependencies = [ + "bitflags 1.3.2", + "block", + "core-graphics-types", + "foreign-types", + "log", + "objc", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", + "simd-adler32", +] + +[[package]] +name = "mint" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e53debba6bda7a793e5f99b8dacf19e626084f525f7829104ba9898f367d85ff" + +[[package]] +name = "mio" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +dependencies = [ + "libc", + "log", + "wasi", + "windows-sys 0.48.0", +] + +[[package]] +name = "mutate_once" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16cf681a23b4d0a43fc35024c176437f9dcd818db34e0f42ab456a0ee5ad497b" + +[[package]] +name = "naga" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbcc2e0513220fd2b598e6068608d4462db20322c0e77e47f6f488dfcfc279cb" +dependencies = [ + "bit-set", + "bitflags 1.3.2", + "codespan-reporting", + "hexf-parse", + "indexmap 1.9.3", + "log", + "num-traits", + "rustc-hash", + "spirv", + "termcolor", + "thiserror", + "unicode-xid", +] + +[[package]] +name = "nanorand" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" +dependencies = [ + "getrandom", +] + +[[package]] +name = "ndk" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "451422b7e4718271c8b5b3aadf5adedba43dc76312454b387e98fae0fc951aa0" +dependencies = [ + "bitflags 1.3.2", + "jni-sys", + "ndk-sys", + "num_enum 0.5.11", + "raw-window-handle", + "thiserror", +] + +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + +[[package]] +name = "ndk-sys" +version = "0.4.1+23.1.7779620" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cf2aae958bd232cac5069850591667ad422d263686d75b52a065f9badeee5a3" +dependencies = [ + "jni-sys", +] + +[[package]] +name = "nix" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4916f159ed8e5de0082076562152a76b7a1f64a01fd9d1e0fea002c37624faf" +dependencies = [ + "bitflags 1.3.2", + "cc", + "cfg-if", + "libc", + "memoffset 0.6.5", +] + +[[package]] +name = "nix" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "libc", + "memoffset 0.6.5", +] + +[[package]] +name = "nix" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4" +dependencies = [ + "autocfg", + "bitflags 1.3.2", + "cfg-if", + "libc", + "memoffset 0.6.5", +] + +[[package]] +name = "nix" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "libc", + "memoffset 0.7.1", + "pin-utils", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" +dependencies = [ + "num_enum_derive 0.5.11", +] + +[[package]] +name = "num_enum" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a015b430d3c108a207fd776d2e2196aaf8b1cf8cf93253e3a097ff3085076a1" +dependencies = [ + "num_enum_derive 0.6.1", +] + +[[package]] +name = "num_enum_derive" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "num_enum_derive" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96667db765a921f7b295ffee8b60472b686a51d4f21c2ee4ffdb94c7013b65a6" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.38", +] + +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", + "objc_exception", +] + +[[package]] +name = "objc-foundation" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" +dependencies = [ + "block", + "objc", + "objc_id", +] + +[[package]] +name = "objc-sys" +version = "0.2.0-beta.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b9834c1e95694a05a828b59f55fa2afec6288359cda67146126b3f90a55d7" + +[[package]] +name = "objc2" +version = "0.3.0-beta.3.patch-leaks.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e01640f9f2cb1220bbe80325e179e532cb3379ebcd1bf2279d703c19fe3a468" +dependencies = [ + "block2", + "objc-sys", + "objc2-encode", +] + +[[package]] +name = "objc2-encode" +version = "2.0.0-pre.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abfcac41015b00a120608fdaa6938c44cb983fee294351cc4bac7638b4e50512" +dependencies = [ + "objc-sys", +] + +[[package]] +name = "objc_exception" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4" +dependencies = [ + "cc", +] + +[[package]] +name = "objc_id" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" +dependencies = [ + "objc", +] + +[[package]] +name = "object" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "orbclient" +version = "0.3.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8378ac0dfbd4e7895f2d2c1f1345cab3836910baf3a300b000d04250f0c8428f" +dependencies = [ + "redox_syscall 0.3.5", +] + +[[package]] +name = "ouroboros" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2ba07320d39dfea882faa70554b4bd342a5f273ed59ba7c1c6b4c840492c954" +dependencies = [ + "aliasable", + "ouroboros_macro", + "static_assertions", +] + +[[package]] +name = "ouroboros_macro" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec4c6225c69b4ca778c0aea097321a64c421cf4577b331c61b229267edabb6f8" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.38", +] + +[[package]] +name = "owned_ttf_parser" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "706de7e2214113d63a8238d1910463cfce781129a6f263d13fdb09ff64355ba4" +dependencies = [ + "ttf-parser 0.19.2", +] + +[[package]] +name = "palette" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2e2f34147767aa758aa649415b50a69eeb46a67f9dc7db8011eeb3d84b351dc" +dependencies = [ + "approx", + "fast-srgb8", + "palette_derive", + "phf", +] + +[[package]] +name = "palette_derive" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7db010ec5ff3d4385e4f133916faacd9dad0f6a09394c92d825b3aed310fa0a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core 0.8.6", +] + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core 0.9.9", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall 0.2.16", + "smallvec", + "winapi", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.4.1", + "smallvec", + "windows-targets 0.48.5", +] + +[[package]] +name = "percent-encoding" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" + +[[package]] +name = "phf" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +dependencies = [ + "phf_macros", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +dependencies = [ + "phf_shared", + "rand", +] + +[[package]] +name = "phf_macros" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn 2.0.38", +] + +[[package]] +name = "phf_shared" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pico-args" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" + +[[package]] +name = "pin-project" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" + +[[package]] +name = "png" +version = "0.17.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd75bf2d8dd3702b9707cdbc56a5b9ef42cec752eb8b3bafc01234558442aa64" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit 0.19.15", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "profiling" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f89dff0959d98c9758c88826cc002e2c3d0b9dfac4139711d1f30de442f1139b" + +[[package]] +name = "qoi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "quick-xml" +version = "0.28.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce5e73202a820a31f8a0ee32ada5e21029c81fd9e3ebf668a40832e4219d9d1" +dependencies = [ + "memchr", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "range-alloc" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8a99fddc9f0ba0a85884b8d14e3592853e787d581ca1816c91349b10e4eeab" + +[[package]] +name = "rangemap" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "977b1e897f9d764566891689e642653e5ed90c6895106acd005eb4c1d0203991" + +[[package]] +name = "raw-window-handle" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" + +[[package]] +name = "rayon" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "rctree" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b42e27ef78c35d3998403c1d26f3efd9e135d3e5121b0a4845cc5cc27547f4f" + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "renderdoc-sys" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "216080ab382b992234dda86873c18d4c48358f5cfcb70fd693d7f6f2131b628b" + +[[package]] +name = "resvg" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6554f47c38eca56827eea7f285c2a3018b4e12e0e195cc105833c008be338f1" +dependencies = [ + "gif", + "jpeg-decoder", + "log", + "pico-args", + "png", + "rgb", + "svgtypes", + "tiny-skia 0.10.0", + "usvg", +] + +[[package]] +name = "rgb" +version = "0.8.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20ec2d3e3fc7a92ced357df9cebd5a10b6fb2aa1ee797bf7e9ce2f17dffc8f59" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "roxmltree" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "862340e351ce1b271a378ec53f304a5558f7db87f3769dc655a8f6ecbb68b302" +dependencies = [ + "xmlparser", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustybuzz" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162bdf42e261bee271b3957691018634488084ef577dddeb6420a9684cab2a6a" +dependencies = [ + "bitflags 1.3.2", + "bytemuck", + "smallvec", + "ttf-parser 0.18.1", + "unicode-bidi-mirroring", + "unicode-ccc", + "unicode-general-category", + "unicode-script", +] + +[[package]] +name = "rustybuzz" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82eea22c8f56965eeaf3a209b3d24508256c7b920fb3b6211b8ba0f7c0583250" +dependencies = [ + "bitflags 1.3.2", + "bytemuck", + "libm", + "smallvec", + "ttf-parser 0.19.2", + "unicode-bidi-mirroring", + "unicode-ccc", + "unicode-general-category", + "unicode-script", +] + +[[package]] +name = "ryu" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" + +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sctk-adwaita" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda4e97be1fd174ccc2aae81c8b694e803fa99b34e8fd0f057a9d70698e3ed09" +dependencies = [ + "ab_glyph", + "log", + "memmap2 0.5.10", + "smithay-client-toolkit", + "tiny-skia 0.8.4", +] + +[[package]] +name = "serde" +version = "1.0.189" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.189" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + +[[package]] +name = "serde_json" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_spanned" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80" +dependencies = [ + "serde", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shalom" +version = "0.1.0" +dependencies = [ + "iced", + "image", + "itertools", + "keyframe", + "once_cell", + "serde", + "serde_json", + "time", + "tokio", + "tokio-tungstenite", + "toml", +] + +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + +[[package]] +name = "simplecss" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a11be7c62927d9427e9f40f3444d5499d868648e2edbc4e2116de69e7ec0e89d" +dependencies = [ + "log", +] + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "slotmap" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1e08e261d0e8f5c43123b7adf3e4ca1690d655377ac93a03b2c9d3e98de1342" +dependencies = [ + "version_check", +] + +[[package]] +name = "smallvec" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" + +[[package]] +name = "smithay-client-toolkit" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "870427e30b8f2cbe64bf43ec4b86e88fe39b0a84b3f15efd9c9c2d020bc86eb9" +dependencies = [ + "bitflags 1.3.2", + "calloop", + "dlib", + "lazy_static", + "log", + "memmap2 0.5.10", + "nix 0.24.3", + "pkg-config", + "wayland-client 0.29.5", + "wayland-cursor", + "wayland-protocols", +] + +[[package]] +name = "smithay-clipboard" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a345c870a1fae0b1b779085e81b51e614767c239e93503588e54c5b17f4b0e8" +dependencies = [ + "smithay-client-toolkit", + "wayland-client 0.29.5", +] + +[[package]] +name = "socket2" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "softbuffer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2b953f6ba7285f0af131eb748aabd8ddaf53e0b81dda3ba5d803b0847d6559f" +dependencies = [ + "bytemuck", + "cfg_aliases", + "cocoa", + "core-graphics", + "fastrand", + "foreign-types", + "log", + "nix 0.26.4", + "objc", + "raw-window-handle", + "redox_syscall 0.3.5", + "thiserror", + "wasm-bindgen", + "wayland-backend", + "wayland-client 0.30.2", + "wayland-sys 0.30.1", + "web-sys", + "windows-sys 0.48.0", + "x11-dl", + "x11rb 0.11.1", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spirv" +version = "0.2.0+1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "246bfa38fe3db3f1dfc8ca5a2cdeb7348c78be2112740cc0ec8ef18b6d94f830" +dependencies = [ + "bitflags 1.3.2", + "num-traits", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "str-buf" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e08d8363704e6c71fc928674353e6b7c23dcea9d82d7012c8faf2a3a025f8d0" + +[[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 = "svg_fmt" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fb1df15f412ee2e9dfc1c504260fa695c1c3f10fe9f4a6ee2d2184d7d6450e2" + +[[package]] +name = "svgtypes" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed4b0611e7f3277f68c0fa18e385d9e2d26923691379690039548f867cef02a7" +dependencies = [ + "kurbo", + "siphasher", +] + +[[package]] +name = "swash" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b7c73c813353c347272919aa1af2885068b05e625e5532b43049e4f641ae77f" +dependencies = [ + "yazi", + "zeno", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sys-locale" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e801cf239ecd6ccd71f03d270d67dd53d13e90aab208bf4b8fe4ad957ea949b0" +dependencies = [ + "libc", +] + +[[package]] +name = "termcolor" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + +[[package]] +name = "tiff" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d172b0f4d3fba17ba89811858b9d3d97f928aece846475bbda076ca46736211" +dependencies = [ + "flate2", + "jpeg-decoder", + "weezl", +] + +[[package]] +name = "time" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5" +dependencies = [ + "deranged", + "powerfmt", + "serde", + "time-core", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "tiny-skia" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df8493a203431061e901613751931f047d1971337153f96d0e5e363d6dbf6a67" +dependencies = [ + "arrayref", + "arrayvec", + "bytemuck", + "cfg-if", + "png", + "tiny-skia-path 0.8.4", +] + +[[package]] +name = "tiny-skia" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7db11798945fa5c3e5490c794ccca7c6de86d3afdd54b4eb324109939c6f37bc" +dependencies = [ + "arrayref", + "arrayvec", + "bytemuck", + "cfg-if", + "log", + "png", + "tiny-skia-path 0.10.0", +] + +[[package]] +name = "tiny-skia-path" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adbfb5d3f3dd57a0e11d12f4f13d4ebbbc1b5c15b7ab0a156d030b21da5f677c" +dependencies = [ + "arrayref", + "bytemuck", + "strict-num", +] + +[[package]] +name = "tiny-skia-path" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f60aa35c89ac2687ace1a2556eaaea68e8c0d47408a2e3e7f5c98a489e7281c" +dependencies = [ + "arrayref", + "bytemuck", + "strict-num", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f38200e3ef7995e5ef13baec2f432a6da0aa9ac495b2c0e8f3b7eec2c92d653" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", + "pin-project-lite", + "socket2", + "tokio-macros", + "windows-sys 0.48.0", +] + +[[package]] +name = "tokio-macros" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" +dependencies = [ + "futures-util", + "log", + "tokio", + "tungstenite", +] + +[[package]] +name = "toml" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ff9e3abce27ee2c9a37f9ad37238c1bdd4e789c84ba37df76aa4d528f5072cc" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.20.7", +] + +[[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.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap 2.0.2", + "toml_datetime", + "winnow", +] + +[[package]] +name = "toml_edit" +version = "0.20.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" +dependencies = [ + "indexmap 2.0.2", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[package]] +name = "ttf-parser" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0609f771ad9c6155384897e1df4d948e692667cc0588548b68eb44d052b27633" + +[[package]] +name = "ttf-parser" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49d64318d8311fc2668e48b63969f4343e0a85c4a109aa8460d6672e364b8bd1" + +[[package]] +name = "tungstenite" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http", + "httparse", + "log", + "rand", + "sha1", + "thiserror", + "url", + "utf-8", +] + +[[package]] +name = "twox-hash" +version = "1.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" +dependencies = [ + "cfg-if", + "rand", + "static_assertions", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-bidi" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" + +[[package]] +name = "unicode-bidi-mirroring" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56d12260fb92d52f9008be7e4bca09f584780eb2266dc8fecc6a192bec561694" + +[[package]] +name = "unicode-ccc" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc2520efa644f8268dce4dcd3050eaa7fc044fca03961e9998ac7e2e92b77cf1" + +[[package]] +name = "unicode-general-category" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2281c8c1d221438e373249e065ca4989c4c36952c211ff21a0ee91c44a3869e7" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-linebreak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-script" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d817255e1bed6dfd4ca47258685d14d2bdcfbc64fdc9e3819bd5848057b8ecc" + +[[package]] +name = "unicode-segmentation" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" + +[[package]] +name = "unicode-vo" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d386ff53b415b7fe27b50bb44679e2cc4660272694b7b6f3326d8480823a94" + +[[package]] +name = "unicode-width" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "url" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "usvg" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14d09ddfb0d93bf84824c09336d32e42f80961a9d1680832eb24fdf249ce11e6" +dependencies = [ + "base64", + "log", + "pico-args", + "usvg-parser", + "usvg-text-layout", + "usvg-tree", + "xmlwriter", +] + +[[package]] +name = "usvg-parser" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d19bf93d230813599927d88557014e0908ecc3531666d47c634c6838bc8db408" +dependencies = [ + "data-url", + "flate2", + "imagesize", + "kurbo", + "log", + "roxmltree", + "simplecss", + "siphasher", + "svgtypes", + "usvg-tree", +] + +[[package]] +name = "usvg-text-layout" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "035044604e89652c0a2959b8b356946997a52649ba6cade45928c2842376feb4" +dependencies = [ + "fontdb", + "kurbo", + "log", + "rustybuzz 0.7.0", + "unicode-bidi", + "unicode-script", + "unicode-vo", + "usvg-tree", +] + +[[package]] +name = "usvg-tree" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7939a7e4ed21cadb5d311d6339730681c3e24c3e81d60065be80e485d3fc8b92" +dependencies = [ + "rctree", + "strict-num", + "svgtypes", + "tiny-skia-path 0.10.0", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.38", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" + +[[package]] +name = "wasm-timer" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f" +dependencies = [ + "futures", + "js-sys", + "parking_lot 0.11.2", + "pin-utils", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "wayland-backend" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41b48e27457e8da3b2260ac60d0a94512f5cba36448679f3747c0865b7893ed8" +dependencies = [ + "cc", + "downcast-rs", + "io-lifetimes", + "nix 0.26.4", + "scoped-tls", + "smallvec", + "wayland-sys 0.30.1", +] + +[[package]] +name = "wayland-client" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f3b068c05a039c9f755f881dc50f01732214f5685e379829759088967c46715" +dependencies = [ + "bitflags 1.3.2", + "downcast-rs", + "libc", + "nix 0.24.3", + "scoped-tls", + "wayland-commons", + "wayland-scanner 0.29.5", + "wayland-sys 0.29.5", +] + +[[package]] +name = "wayland-client" +version = "0.30.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "489c9654770f674fc7e266b3c579f4053d7551df0ceb392f153adb1f9ed06ac8" +dependencies = [ + "bitflags 1.3.2", + "nix 0.26.4", + "wayland-backend", + "wayland-scanner 0.30.1", +] + +[[package]] +name = "wayland-commons" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8691f134d584a33a6606d9d717b95c4fa20065605f798a3f350d78dced02a902" +dependencies = [ + "nix 0.24.3", + "once_cell", + "smallvec", + "wayland-sys 0.29.5", +] + +[[package]] +name = "wayland-cursor" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6865c6b66f13d6257bef1cd40cbfe8ef2f150fb8ebbdb1e8e873455931377661" +dependencies = [ + "nix 0.24.3", + "wayland-client 0.29.5", + "xcursor", +] + +[[package]] +name = "wayland-protocols" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b950621f9354b322ee817a23474e479b34be96c2e909c14f7bc0100e9a970bc6" +dependencies = [ + "bitflags 1.3.2", + "wayland-client 0.29.5", + "wayland-commons", + "wayland-scanner 0.29.5", +] + +[[package]] +name = "wayland-scanner" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f4303d8fa22ab852f789e75a967f0a2cdc430a607751c0499bada3e451cbd53" +dependencies = [ + "proc-macro2", + "quote", + "xml-rs", +] + +[[package]] +name = "wayland-scanner" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9b873b257fbc32ec909c0eb80dea312076a67014e65e245f5eb69a6b8ab330e" +dependencies = [ + "proc-macro2", + "quick-xml", + "quote", +] + +[[package]] +name = "wayland-sys" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be12ce1a3c39ec7dba25594b97b42cb3195d54953ddb9d3d95a7c3902bc6e9d4" +dependencies = [ + "dlib", + "lazy_static", + "pkg-config", +] + +[[package]] +name = "wayland-sys" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96b2a02ac608e07132978689a6f9bf4214949c85998c247abadd4f4129b1aa06" +dependencies = [ + "dlib", + "lazy_static", + "log", + "pkg-config", +] + +[[package]] +name = "web-sys" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "weezl" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb" + +[[package]] +name = "wgpu" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "480c965c9306872eb6255fa55e4b4953be55a8b64d57e61d7ff840d3dcc051cd" +dependencies = [ + "arrayvec", + "cfg-if", + "js-sys", + "log", + "naga", + "parking_lot 0.12.1", + "profiling", + "raw-window-handle", + "smallvec", + "static_assertions", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "wgpu-core", + "wgpu-hal", + "wgpu-types", +] + +[[package]] +name = "wgpu-core" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f478237b4bf0d5b70a39898a66fa67ca3a007d79f2520485b8b0c3dfc46f8c2" +dependencies = [ + "arrayvec", + "bit-vec", + "bitflags 2.4.1", + "codespan-reporting", + "log", + "naga", + "parking_lot 0.12.1", + "profiling", + "raw-window-handle", + "rustc-hash", + "smallvec", + "thiserror", + "web-sys", + "wgpu-hal", + "wgpu-types", +] + +[[package]] +name = "wgpu-hal" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ecb3258078e936deee14fd4e0febe1cfe9bbb5ffef165cb60218d2ee5eb4448" +dependencies = [ + "android_system_properties", + "arrayvec", + "ash", + "bit-set", + "bitflags 2.4.1", + "block", + "core-graphics-types", + "d3d12", + "foreign-types", + "glow", + "gpu-alloc", + "gpu-allocator", + "gpu-descriptor", + "hassle-rs", + "js-sys", + "khronos-egl", + "libc", + "libloading 0.8.1", + "log", + "metal", + "naga", + "objc", + "parking_lot 0.12.1", + "profiling", + "range-alloc", + "raw-window-handle", + "renderdoc-sys", + "rustc-hash", + "smallvec", + "thiserror", + "wasm-bindgen", + "web-sys", + "wgpu-types", + "winapi", +] + +[[package]] +name = "wgpu-types" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0c153280bb108c2979eb5c7391cb18c56642dd3c072e55f52065e13e2a1252a" +dependencies = [ + "bitflags 2.4.1", + "js-sys", + "web-sys", +] + +[[package]] +name = "widestring" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-wsapoll" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c17110f57155602a80dca10be03852116403c9ff3cd25b079d666f2aa3df6e" +dependencies = [ + "winapi", +] + +[[package]] +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 = "window_clipboard" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63287c9c4396ccf5346d035a9b0fcaead9e18377637f5eaa78b7ac65c873ff7d" +dependencies = [ + "clipboard-win", + "clipboard_macos", + "clipboard_wayland", + "clipboard_x11", + "raw-window-handle", + "thiserror", +] + +[[package]] +name = "windows" +version = "0.44.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e745dab35a0c4c77aa3ce42d595e13d2003d6902d6b08c9ef5fc326d08da12b" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[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.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[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.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[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.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[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.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[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.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[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.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "winit" +version = "0.28.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9596d90b45384f5281384ab204224876e8e8bf7d58366d9b795ad99aa9894b94" +dependencies = [ + "android-activity", + "bitflags 1.3.2", + "cfg_aliases", + "core-foundation", + "core-graphics", + "dispatch", + "instant", + "libc", + "log", + "mio", + "ndk", + "objc2", + "once_cell", + "orbclient", + "percent-encoding", + "raw-window-handle", + "redox_syscall 0.3.5", + "sctk-adwaita", + "smithay-client-toolkit", + "wasm-bindgen", + "wayland-client 0.29.5", + "wayland-commons", + "wayland-protocols", + "wayland-scanner 0.29.5", + "web-sys", + "windows-sys 0.45.0", + "x11-dl", +] + +[[package]] +name = "winnow" +version = "0.5.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3b801d0e0a6726477cc207f60162da452f3a95adb368399bef20a946e06f65c" +dependencies = [ + "memchr", +] + +[[package]] +name = "x11-dl" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f" +dependencies = [ + "libc", + "once_cell", + "pkg-config", +] + +[[package]] +name = "x11rb" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e99be55648b3ae2a52342f9a870c0e138709a3493261ce9b469afe6e4df6d8a" +dependencies = [ + "gethostname", + "nix 0.22.3", + "winapi", + "winapi-wsapoll", +] + +[[package]] +name = "x11rb" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdf3c79412dd91bae7a7366b8ad1565a85e35dd049affc3a6a2c549e97419617" +dependencies = [ + "gethostname", + "libc", + "libloading 0.7.4", + "nix 0.25.1", + "once_cell", + "winapi", + "winapi-wsapoll", + "x11rb-protocol", +] + +[[package]] +name = "x11rb-protocol" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0b1513b141123073ce54d5bb1d33f801f17508fbd61e02060b1214e96d39c56" +dependencies = [ + "nix 0.25.1", +] + +[[package]] +name = "xcursor" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "463705a63313cd4301184381c5e8042f0a7e9b4bb63653f216311d4ae74690b7" +dependencies = [ + "nom", +] + +[[package]] +name = "xml-rs" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fcb9cbac069e033553e8bb871be2fbdffcab578eb25bd0f7c508cedc6dcd75a" + +[[package]] +name = "xmlparser" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4" + +[[package]] +name = "xmlwriter" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9" + +[[package]] +name = "yazi" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c94451ac9513335b5e23d7a8a2b61a7102398b8cca5160829d313e84c9d98be1" + +[[package]] +name = "zeno" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd15f8e0dbb966fd9245e7498c7e9e5055d9e5c8b676b95bd67091cd11a1e697" + +[[package]] +name = "zune-inflate" +version = "0.2.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" +dependencies = [ + "simd-adler32", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..277348f --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,8 @@ +[workspace] +resolver = "2" +members = [ + "shalom" +] + +[profile.dev.package.image] +opt-level = 3 diff --git a/README.md b/README.md new file mode 100644 index 0000000..83d5fa6 --- /dev/null +++ b/README.md @@ -0,0 +1,8 @@ +# shalom + +A work-in-progress native UI for Home Manager, designed to +be ran on a Raspberry Pi with a touch-screen for a "home +automation tablet" experience, but can also be used on the +desktop if so desired. + +Written in Rust using [iced](https://github.com/iced-rs/iced). diff --git a/assets/icons/README.md b/assets/icons/README.md new file mode 100644 index 0000000..2aa9bfb --- /dev/null +++ b/assets/icons/README.md @@ -0,0 +1,3 @@ +# Resources + +- https://heroicons.com/ diff --git a/assets/icons/back.svg b/assets/icons/back.svg new file mode 100644 index 0000000..8572e1d --- /dev/null +++ b/assets/icons/back.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icons/backward.svg b/assets/icons/backward.svg new file mode 100644 index 0000000..a358c55 --- /dev/null +++ b/assets/icons/backward.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icons/forward.svg b/assets/icons/forward.svg new file mode 100644 index 0000000..7366fe5 --- /dev/null +++ b/assets/icons/forward.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icons/hamburger.svg b/assets/icons/hamburger.svg new file mode 100644 index 0000000..f1788e7 --- /dev/null +++ b/assets/icons/hamburger.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icons/home.svg b/assets/icons/home.svg new file mode 100644 index 0000000..4cf85cc --- /dev/null +++ b/assets/icons/home.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icons/light-bulb.svg b/assets/icons/light-bulb.svg new file mode 100644 index 0000000..f77dcf0 --- /dev/null +++ b/assets/icons/light-bulb.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icons/pause.svg b/assets/icons/pause.svg new file mode 100644 index 0000000..68225b1 --- /dev/null +++ b/assets/icons/pause.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icons/play.svg b/assets/icons/play.svg new file mode 100644 index 0000000..cecf998 --- /dev/null +++ b/assets/icons/play.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icons/repeat.svg b/assets/icons/repeat.svg new file mode 100644 index 0000000..e63b652 --- /dev/null +++ b/assets/icons/repeat.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icons/speaker-muted.svg b/assets/icons/speaker-muted.svg new file mode 100644 index 0000000..e98295a --- /dev/null +++ b/assets/icons/speaker-muted.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icons/speaker.svg b/assets/icons/speaker.svg new file mode 100644 index 0000000..804f3f6 --- /dev/null +++ b/assets/icons/speaker.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/bathroom.jpg b/assets/images/bathroom.jpg new file mode 100644 index 0000000..4a200d3 --- /dev/null +++ b/assets/images/bathroom.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ae50401046451ca72968d1b242a8ab35cb01396980880f3eece801d2f5f0fbc0 +size 37142 diff --git a/assets/images/bedroom.jpg b/assets/images/bedroom.jpg new file mode 100644 index 0000000..61c5f50 --- /dev/null +++ b/assets/images/bedroom.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7d5c47ab43f8e0cd77524a5dad1c9acaffa09d453d965fdc8f23629b22a7efd8 +size 45824 diff --git a/assets/images/dining_room.jpg b/assets/images/dining_room.jpg new file mode 100644 index 0000000..0367f26 --- /dev/null +++ b/assets/images/dining_room.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:70c09703929f74abd0318dd81acf62f8ab63daeec50caed0ade9d0f8bfc2689a +size 57022 diff --git a/assets/images/kitchen.jpg b/assets/images/kitchen.jpg new file mode 100644 index 0000000..b756ae7 --- /dev/null +++ b/assets/images/kitchen.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b3cbb2be83046cea19ed0942c536f3fe41cb9a5382cbdcfd25cbe0efc5c94671 +size 37129 diff --git a/assets/images/living_room.jpg b/assets/images/living_room.jpg new file mode 100644 index 0000000..f2988a3 --- /dev/null +++ b/assets/images/living_room.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8444deae7567063002173fdfe848ea2f6f3ebe116b4f2007207df43c41caf9ab +size 66944 diff --git a/config-example.toml b/config-example.toml new file mode 100644 index 0000000..135142d --- /dev/null +++ b/config-example.toml @@ -0,0 +1,3 @@ +[home-assistant] +uri = "http://192.168.1.100/" +token = "abcdef" diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..fd4d8a5 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,7 @@ +edition = "2021" +unstable_features = true +imports_granularity = "Crate" +group_imports = "StdExternalCrate" +normalize_comments = true +comment_width = 100 +wrap_comments = true diff --git a/shalom/Cargo.toml b/shalom/Cargo.toml new file mode 100644 index 0000000..99447ad --- /dev/null +++ b/shalom/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "shalom" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +iced = { version = "0.10", features = ["tokio", "svg", "lazy", "advanced", "image"] } +image = "0.24" +once_cell = "1.18" +itertools = "0.11" +keyframe = "1.1" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +tokio = { version = "1.33", features = ["net", "sync", "rt", "macros", "time", "fs"] } +tokio-tungstenite = "0.20" +toml = "0.8" +time = { version = "0.3", features = ["std"] } diff --git a/shalom/src/config.rs b/shalom/src/config.rs new file mode 100644 index 0000000..520a98a --- /dev/null +++ b/shalom/src/config.rs @@ -0,0 +1,16 @@ +#![allow(clippy::module_name_repetitions)] + +use serde::Deserialize; + +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case")] +pub struct Config { + pub home_assistant: HomeAssistantConfig, +} + +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case")] +pub struct HomeAssistantConfig { + pub uri: String, + pub token: String, +} diff --git a/shalom/src/hass_client.rs b/shalom/src/hass_client.rs new file mode 100644 index 0000000..4c23919 --- /dev/null +++ b/shalom/src/hass_client.rs @@ -0,0 +1,142 @@ +use std::{fs::File, io::Write, time::Duration}; + +use iced::futures::{SinkExt, StreamExt}; +use serde::{Deserialize, Serialize}; +use time::OffsetDateTime; +use tokio::{net::TcpStream, sync::mpsc}; +use tokio_tungstenite::{tungstenite::Message, MaybeTlsStream, WebSocketStream}; + +use crate::config::HomeAssistantConfig; + +type SocketStream = WebSocketStream>; + +pub enum ClientMessage { + // Ready, +} + +pub async fn create(config: HomeAssistantConfig) -> mpsc::Receiver { + let (_send, recv) = mpsc::channel(10); + + let uri = format!("ws://{}/api/websocket", config.uri); + let (mut connection, _response) = tokio_tungstenite::connect_async(&uri).await.unwrap(); + + tokio::spawn(async move { + let mut interval = tokio::time::interval(Duration::from_secs(10)); + + loop { + tokio::select! { + Some(message) = connection.next() => { + let message = message.unwrap(); + eprintln!("recv: {message:?}"); + + #[allow(clippy::match_same_arms)] + match message { + Message::Pong(ts) => { + let ts = i128::from_be_bytes(ts.try_into().unwrap()); + let ts = OffsetDateTime::from_unix_timestamp_nanos(ts).unwrap(); + + eprintln!("rtt: {}", OffsetDateTime::now_utc() - ts); + } + Message::Text(payload) => { + handle_hass_response(&config, serde_json::from_str(&payload).unwrap(), &mut connection).await; + } + Message::Close(_) => { + // eprintln!("Reconnecting..."); + // connection = tokio_tungstenite::connect_async(&uri).await.unwrap().0; + } + _ => {} + } + } + _ = interval.tick() => { + connection.send(Message::Ping(OffsetDateTime::now_utc().unix_timestamp_nanos().to_be_bytes().to_vec())).await.unwrap(); + } + } + } + }); + + recv +} + +async fn handle_hass_response( + config: &HomeAssistantConfig, + v: HassResponse, + socket: &mut SocketStream, +) { + #[allow(clippy::match_same_arms)] + match v { + HassResponse::AuthRequired => { + socket + .send( + HassRequest::Auth { + access_token: config.token.clone(), + } + .to_request(), + ) + .await + .unwrap(); + } + HassResponse::AuthOk => { + // Lists: [aliases, area_id, name, picture] + // socket + // .send(HassRequest::AreaRegistry { id: 3 }.to_request()) + // .await + // .unwrap(); + + // Lists: [area_id, entity_id] + // socket.send(HassRequest::EntityRegistry { id: 3 }.to_request()) + // .await + // .unwrap(); + + // Lists: versions, area id, manufacturer, etc + // socket.send(HassRequest::DeviceRegistry { id: 3 }.to_request()) + // .await + // .unwrap(); + } + HassResponse::AuthInvalid => {} + HassResponse::Result(value) => { + File::create("test") + .unwrap() + .write_all(&serde_json::to_vec(&value).unwrap()) + .unwrap(); + } + } +} + +#[derive(Deserialize)] +#[serde(rename_all = "snake_case", tag = "type", content = "result")] +#[allow(clippy::enum_variant_names)] +enum HassResponse { + AuthRequired, + AuthOk, + AuthInvalid, + Result(serde_json::Value), +} + +#[derive(Serialize)] +#[serde(rename_all = "snake_case", tag = "type")] +enum HassRequest { + Auth { + access_token: String, + }, + GetStates { + id: u32, + }, + #[serde(rename = "config/area_registry/list")] + AreaRegistry { + id: u32, + }, + #[serde(rename = "config/entity_registry/list")] + EntityRegistry { + id: u32, + }, + #[serde(rename = "config/device_registry/list")] + DeviceRegistry { + id: u32, + }, +} + +impl HassRequest { + pub fn to_request(&self) -> Message { + Message::text(serde_json::to_string(&self).unwrap()) + } +} diff --git a/shalom/src/main.rs b/shalom/src/main.rs new file mode 100644 index 0000000..6906c64 --- /dev/null +++ b/shalom/src/main.rs @@ -0,0 +1,202 @@ +#![deny(clippy::pedantic)] + +mod config; +mod hass_client; +mod oracle; +mod pages; +mod theme; +mod widgets; + +use std::sync::Arc; + +use iced::{ + alignment::{Horizontal, Vertical}, + font::{Stretch, Weight}, + widget::{column, container, row, scrollable, svg, text, vertical_slider, Column}, + Alignment, Application, Command, ContentFit, Element, Font, Length, Renderer, Settings, Theme, +}; + +use crate::{ + config::Config, + theme::{Icon, Image}, + widgets::{context_menu::ContextMenu, mouse_area::mouse_area}, +}; + +pub struct Shalom { + page: ActivePage, + context_menu: Option, + homepage: ActivePage, +} + +impl Application for Shalom { + type Executor = iced::executor::Default; + type Message = Message; + type Theme = Theme; + type Flags = (); + + fn new(_flags: Self::Flags) -> (Self, Command) { + let this = Self { + page: ActivePage::Loading, + context_menu: None, + homepage: ActivePage::Room("Living Room"), + }; + + // this is only best-effort to try and prevent blocking when loading + // the omni-view, we don't need to block on this at boot + tokio::task::spawn_blocking(Image::preload); + + let command = Command::perform( + async { + let config = load_config().await; + let client = hass_client::create(config.home_assistant).await; + + Arc::new(client) + }, + |_client| Message::Loaded, + ); + + (this, command) + } + + fn title(&self) -> String { + String::from("Shalom") + } + + fn update(&mut self, message: Self::Message) -> Command { + match message { + Message::Loaded => { + self.page = self.homepage.clone(); + } + Message::CloseContextMenu => { + self.context_menu = None; + } + Message::OpenContextMenu(menu) => { + self.context_menu = Some(menu); + } + Message::ChangePage(page) => { + self.page = page; + } + } + + Command::none() + } + + fn view(&self) -> Element<'_, Self::Message, Renderer> { + let page_content = match &self.page { + ActivePage::Loading => Element::from(column!["Loading...",].spacing(20)), + ActivePage::Room(room) => { + Element::from(pages::room::Room::new(room, Message::OpenContextMenu)) + } + ActivePage::Omni => Element::from(pages::omni::Omni::new(Message::ChangePage)), + }; + + let mut content = Column::new().push(scrollable(page_content)); + + let (show_back, show_home) = match &self.page { + _ if self.page == self.homepage => (true, false), + ActivePage::Loading => (false, false), + ActivePage::Omni => (false, true), + ActivePage::Room(_) => (true, true), + }; + + let back = mouse_area( + svg(Icon::Back) + .height(32) + .width(32) + .content_fit(ContentFit::None), + ) + .on_press(Message::ChangePage(ActivePage::Omni)); + let home = mouse_area( + svg(Icon::Home) + .height(32) + .width(32) + .content_fit(ContentFit::None), + ) + .on_press(Message::ChangePage(self.homepage.clone())); + + let navigation = match (show_back, show_home) { + (true, true) => Some(Element::from( + row![ + back, + container(home) + .width(Length::Fill) + .align_x(Horizontal::Right), + ] + .height(32), + )), + (false, true) => Some(Element::from( + row![container(home) + .width(Length::Fill) + .align_x(Horizontal::Right),] + .height(32), + )), + (true, false) => Some(Element::from(back)), + (false, false) => None, + }; + + if let Some(navigation) = navigation { + content = content.push( + container(navigation) + .height(Length::Fill) + .width(Length::Fill) + .align_y(Vertical::Bottom) + .padding(40), + ); + } + + if let Some(context_menu) = &self.context_menu { + let context_menu = match context_menu { + ActiveContextMenu::LightOptions(name) => container(column![ + text(name).size(40).font(Font { + weight: Weight::Bold, + stretch: Stretch::Condensed, + ..Font::with_name("Helvetica Neue") + }), + row![vertical_slider(0..=100, 0, |_v| Message::Loaded).height(200)] + .align_items(Alignment::Center) + ]) + .width(Length::Fill) + .padding(40), + }; + + ContextMenu::new(content, context_menu) + .on_close(Message::CloseContextMenu) + .into() + } else { + content.into() + } + } +} + +async fn load_config() -> Config { + let content = tokio::fs::read_to_string("./config.toml").await.unwrap(); + toml::from_str(&content).unwrap() +} + +#[derive(Debug, Clone)] +pub enum Message { + Loaded, + CloseContextMenu, + ChangePage(ActivePage), + OpenContextMenu(ActiveContextMenu), +} + +#[derive(Debug, Clone, PartialEq)] +pub enum ActivePage { + Loading, + Room(&'static str), + Omni, +} + +#[derive(Clone, Debug)] +pub enum ActiveContextMenu { + LightOptions(&'static str), +} + +fn main() { + Shalom::run(Settings { + antialiasing: true, + ..Settings::default() + }) + .unwrap(); +} diff --git a/shalom/src/oracle.rs b/shalom/src/oracle.rs new file mode 100644 index 0000000..dde3cea --- /dev/null +++ b/shalom/src/oracle.rs @@ -0,0 +1 @@ +pub struct Oracle {} diff --git a/shalom/src/pages/mod.rs b/shalom/src/pages/mod.rs new file mode 100644 index 0000000..61845db --- /dev/null +++ b/shalom/src/pages/mod.rs @@ -0,0 +1,2 @@ +pub mod omni; +pub mod room; diff --git a/shalom/src/pages/omni.rs b/shalom/src/pages/omni.rs new file mode 100644 index 0000000..233a012 --- /dev/null +++ b/shalom/src/pages/omni.rs @@ -0,0 +1,83 @@ +use iced::{ + advanced::graphics::core::Element, + font::{Stretch, Weight}, + widget::{column, component, scrollable, text, Column, Component, Row}, + Font, Renderer, +}; +use itertools::Itertools; + +use crate::{theme::Image, widgets::image_card, ActivePage}; + +pub struct Omni { + open_page: fn(ActivePage) -> M, +} + +impl Omni { + pub fn new(open_page: fn(ActivePage) -> M) -> Self { + Self { open_page } + } +} + +impl Component for Omni { + type State = State; + type Event = Event; + + fn update(&mut self, _state: &mut Self::State, event: Self::Event) -> Option { + match event { + Event::OpenRoom(room) => Some((self.open_page)(ActivePage::Room(room))), + } + } + + fn view(&self, _state: &Self::State) -> Element<'_, Self::Event, Renderer> { + let header = |v| { + text(v).size(60).font(Font { + weight: Weight::Bold, + stretch: Stretch::Condensed, + ..Font::with_name("Helvetica Neue") + }) + }; + + let room = |room, image| { + image_card::image_card(image, room).on_press(Event::OpenRoom(room)) + // .height(Length::Fixed(128.0)) + // .width(Length::FillPortion(1)) + }; + + let rooms = [ + room("Living Room", Image::LivingRoom), + room("Kitchen", Image::Kitchen), + room("Bathroom", Image::Bathroom), + room("Bedroom", Image::Bedroom), + room("Dining Room", Image::DiningRoom), + ] + .into_iter() + .chunks(2) + .into_iter() + .map(|children| children.into_iter().fold(Row::new().spacing(10), Row::push)) + .fold(Column::new().spacing(10), Column::push); + + scrollable( + column![header("Cameras"), header("Rooms"), rooms,] + .spacing(20) + .padding(40), + ) + .into() + } +} + +#[derive(Default, Hash)] +pub struct State {} + +#[derive(Clone)] +pub enum Event { + OpenRoom(&'static str), +} + +impl<'a, M> From> for Element<'a, M, Renderer> +where + M: 'a + Clone, +{ + fn from(card: Omni) -> Self { + component(card) + } +} diff --git a/shalom/src/pages/room.rs b/shalom/src/pages/room.rs new file mode 100644 index 0000000..0cff432 --- /dev/null +++ b/shalom/src/pages/room.rs @@ -0,0 +1,100 @@ +use std::collections::HashMap; + +use iced::{ + advanced::graphics::core::Element, + font::{Stretch, Weight}, + widget::{column, component, container, row, text, Component}, + Font, Renderer, +}; + +use crate::{theme::Icon, widgets, ActiveContextMenu}; + +pub struct Room { + name: &'static str, + open_context_menu: fn(ActiveContextMenu) -> M, +} + +impl Room { + pub fn new(name: &'static str, open_context_menu: fn(ActiveContextMenu) -> M) -> Self { + Self { + name, + open_context_menu, + } + } +} + +impl Component for Room { + type State = State; + type Event = Event; + + fn update(&mut self, state: &mut Self::State, event: Self::Event) -> Option { + match event { + Event::LightToggle(name) => { + let x = state.lights.entry(name).or_default(); + if *x == 0 { + *x = 1; + } else { + *x = 0; + } + + None + } + Event::OpenLightOptions(name) => Some((self.open_context_menu)( + ActiveContextMenu::LightOptions(name), + )), + Event::UpdateLightAmount(name, v) => { + let x = state.lights.entry(name).or_default(); + *x = v; + None + } + } + } + + fn view(&self, state: &Self::State) -> Element<'_, Self::Event, Renderer> { + let header = text(self.name).size(60).font(Font { + weight: Weight::Bold, + stretch: Stretch::Condensed, + ..Font::with_name("Helvetica Neue") + }); + + let light = |name| { + widgets::toggle_card::toggle_card( + name, + state.lights.get(name).copied().unwrap_or_default() > 0, + ) + .icon(Icon::Bulb) + .on_press(Event::LightToggle(name)) + .on_long_press(Event::OpenLightOptions(name)) + }; + + column![ + header, + container(widgets::media_player::media_player()).padding([12, 0, 24, 0]), + row![light("Main"), light("Lamp"), light("TV")].spacing(10), + ] + .spacing(20) + .padding(40) + .into() + } +} + +#[derive(Default)] +pub struct State { + lights: HashMap<&'static str, u8>, +} + +#[derive(Clone)] +pub enum Event { + LightToggle(&'static str), + OpenLightOptions(&'static str), + UpdateLightAmount(&'static str, u8), +} + +impl<'a, M> From> for Element<'a, M, Renderer> +where + M: 'a + Clone, +{ + fn from(card: Room) -> Self { + component(card) + } +} diff --git a/shalom/src/theme.rs b/shalom/src/theme.rs new file mode 100644 index 0000000..3f57e9c --- /dev/null +++ b/shalom/src/theme.rs @@ -0,0 +1,126 @@ +use ::image::GenericImageView; +use iced::{ + advanced::svg::Handle, + widget::{image, svg}, +}; +use once_cell::sync::Lazy; + +pub mod colours { + use iced::Color; + + macro_rules! colour { + ($r:literal, $g:literal, $b:literal) => {{ + Color { + r: $r / 255.0, + g: $g / 255.0, + b: $b / 255.0, + a: 1.0, + } + }}; + } + + pub const SLATE_200: Color = colour!(226.0, 232.0, 240.0); + pub const SLATE_300: Color = colour!(203.0, 213.0, 225.0); + pub const SLATE_400: Color = colour!(148.0, 163.0, 184.0); + pub const SLATE_600: Color = colour!(71.0, 85.0, 105.0); + + pub const SKY_400: Color = colour!(56.0, 189.0, 248.0); + pub const SKY_500: Color = colour!(14.0, 165.0, 233.0); + + pub const AMBER_200: Color = colour!(253.0, 230.0, 138.0); +} + +#[derive(Copy, Clone)] +pub enum Icon { + Home, + Back, + Bulb, + Hamburger, + Speaker, + SpeakerMuted, + Backward, + Forward, + Play, + Pause, + Repeat, +} + +impl Icon { + pub fn handle(self) -> svg::Handle { + macro_rules! image { + ($path:expr) => {{ + static FILE: &[u8] = include_bytes!($path); + static HANDLE: Lazy = Lazy::new(|| svg::Handle::from_memory(FILE)); + (*HANDLE).clone() + }}; + } + + match self { + Self::Home => image!("../../assets/icons/home.svg"), + Self::Back => image!("../../assets/icons/back.svg"), + Self::Bulb => image!("../../assets/icons/light-bulb.svg"), + Self::Hamburger => image!("../../assets/icons/hamburger.svg"), + Self::Speaker => image!("../../assets/icons/speaker.svg"), + Self::SpeakerMuted => image!("../../assets/icons/speaker-muted.svg"), + Self::Backward => image!("../../assets/icons/backward.svg"), + Self::Forward => image!("../../assets/icons/forward.svg"), + Self::Play => image!("../../assets/icons/play.svg"), + Self::Pause => image!("../../assets/icons/pause.svg"), + Self::Repeat => image!("../../assets/icons/repeat.svg"), + } + } +} + +impl From for svg::Handle { + fn from(value: Icon) -> Handle { + value.handle() + } +} + +#[derive(Clone, Copy, Hash, Eq, PartialEq)] +pub enum Image { + LivingRoom, + Kitchen, + Bathroom, + Bedroom, + DiningRoom, +} + +impl Image { + fn handle(self) -> image::Handle { + macro_rules! image { + ($path:expr) => {{ + static FILE: &[u8] = include_bytes!($path); + static HANDLE: Lazy = Lazy::new(|| { + let img = ::image::load_from_memory(FILE).unwrap(); + let (h, w) = img.dimensions(); + let data = img.into_rgba8().into_raw(); + image::Handle::from_pixels(h, w, data) + }); + (*HANDLE).clone() + }}; + } + + match self { + Image::LivingRoom => image!("../../assets/images/living_room.jpg"), + Image::Kitchen => image!("../../assets/images/kitchen.jpg"), + Image::Bathroom => image!("../../assets/images/bathroom.jpg"), + Image::Bedroom => image!("../../assets/images/bedroom.jpg"), + Image::DiningRoom => image!("../../assets/images/dining_room.jpg"), + } + } + + pub fn preload() { + Self::LivingRoom.handle(); + Self::Kitchen.handle(); + Self::Bathroom.handle(); + Self::Bedroom.handle(); + Self::DiningRoom.handle(); + } +} + +impl From for image::Handle { + fn from(value: Image) -> Self { + value.handle() + } +} diff --git a/shalom/src/widgets/context_menu.rs b/shalom/src/widgets/context_menu.rs new file mode 100644 index 0000000..70200b6 --- /dev/null +++ b/shalom/src/widgets/context_menu.rs @@ -0,0 +1,458 @@ +use std::{ + cmp::Ordering, + time::{Duration, Instant}, +}; + +use iced::{ + advanced::{ + layout::{Limits, Node}, + overlay, renderer, + renderer::Style, + widget::{tree, tree::Tag, Operation, Tree}, + Clipboard, Layout, Renderer as RendererT, Shell, Widget, + }, + event::Status, + mouse, + mouse::{Button, Cursor, Interaction}, + window, + window::RedrawRequest, + Alignment, BorderRadius, Color, Element, Event, Length, Point, Rectangle, Renderer, Size, + Theme, +}; +use keyframe::{functions::EaseOutQuint, keyframes, AnimationSequence}; + +pub struct ContextMenu<'a, M> { + base: Element<'a, M, Renderer>, + content: Element<'a, M, Renderer>, + on_close: Option, + max_height: f32, +} + +impl<'a, M> ContextMenu<'a, M> { + pub fn new( + base: impl Into>, + content: impl Into>, + ) -> Self { + Self { + base: base.into(), + content: content.into(), + on_close: None, + max_height: 400., + } + } + + pub fn on_close(mut self, msg: M) -> Self { + self.on_close = Some(msg); + self + } +} + +impl<'a, M: Clone> Widget for ContextMenu<'a, M> { + fn width(&self) -> Length { + self.base.as_widget().width() + } + + fn height(&self) -> Length { + self.base.as_widget().height() + } + + fn layout(&self, renderer: &Renderer, limits: &Limits) -> Node { + self.base.as_widget().layout(renderer, limits) + } + + fn draw( + &self, + state: &Tree, + renderer: &mut Renderer, + theme: &Theme, + style: &Style, + layout: Layout<'_>, + cursor: Cursor, + viewport: &Rectangle, + ) { + self.base.as_widget().draw( + &state.children[0], + renderer, + theme, + style, + layout, + cursor, + viewport, + ); + } + + fn tag(&self) -> Tag { + Tag::of::() + } + + fn state(&self) -> tree::State { + tree::State::new(OverlayState { + max_height: self.max_height, + height: 0., + state: State::Animate(Instant::now(), keyframes![(0.0, 0.0), (400.0, 0.7)]), + }) + } + + fn children(&self) -> Vec { + vec![Tree::new(&self.base), Tree::new(&self.content)] + } + + fn diff(&self, tree: &mut Tree) { + tree.diff_children(&[&self.base, &self.content]); + } + + fn operate( + &self, + state: &mut Tree, + layout: Layout<'_>, + renderer: &Renderer, + operation: &mut dyn Operation, + ) { + self.base + .as_widget() + .operate(state, layout, renderer, operation); + } + + fn on_event( + &mut self, + state: &mut Tree, + event: Event, + layout: Layout<'_>, + cursor: Cursor, + renderer: &Renderer, + clipboard: &mut dyn Clipboard, + shell: &mut Shell<'_, M>, + viewport: &Rectangle, + ) -> Status { + self.base.as_widget_mut().on_event( + &mut state.children[0], + event, + layout, + cursor, + renderer, + clipboard, + shell, + viewport, + ) + } + + fn overlay<'b>( + &'b mut self, + state: &'b mut Tree, + layout: Layout<'_>, + _renderer: &Renderer, + ) -> Option> { + Some(overlay::Element::new( + layout.position(), + Box::new(Overlay { + content: &mut self.content, + tree: &mut state.children[1], + on_close: self.on_close.clone(), + state: state.state.downcast_mut::(), + }), + )) + } +} + +struct Overlay<'a, 'b, M> { + content: &'b mut Element<'a, M, Renderer>, + tree: &'b mut Tree, + on_close: Option, + state: &'b mut OverlayState, +} + +impl<'a, 'b, M: Clone> Overlay<'a, 'b, M> { + pub fn handle_mouse_event( + &mut self, + event: &mouse::Event, + layout: &Layout<'_>, + cursor: Cursor, + ) -> bool { + if matches!(self.state.state, State::Closed) { + return false; + } + + match (&self.state.state, event) { + (State::Dragging(_drag_start, _last_position), mouse::Event::CursorMoved { .. }) => { + true + } + (_, mouse::Event::ButtonPressed(Button::Left)) => { + self.state.state = + State::Dragging(Instant::now(), cursor.position().unwrap_or_default()); + true + } + ( + State::Dragging(drag_start, _last_position), + mouse::Event::ButtonReleased(Button::Left), + ) => { + if drag_start.elapsed() <= Duration::from_millis(100) + && !cursor.is_over(layout.children().next().unwrap().bounds()) + { + // assume all fast clicks outside of content is an intent to + // close + self.state.state = State::Animate( + Instant::now(), + keyframes![(self.state.height, 0.0, EaseOutQuint), (0.0, 0.75)], + ); + } else if self.state.height <= 0. { + // dragged all the way closed, no need to animate anything + self.state.state = State::Closed; + } else if self.state.height < (self.state.max_height / 1.25) { + // snap height reached for closing + self.state.state = State::Animate( + Instant::now(), + keyframes![ + (self.state.height, 0.0, EaseOutQuint), + ( + 0.0, + (0.75 * (self.state.height.abs() / self.state.max_height.abs())) + ) + ], + ); + } else { + // snap back to max height + self.state.state = State::Animate( + Instant::now(), + keyframes![ + (self.state.height, 0.0, EaseOutQuint), + ( + self.state.max_height, + (0.75 * (self.state.height.abs() / self.state.max_height.abs())) + ) + ], + ); + } + + true + } + _ => false, + } + } + + pub fn handle_redraw(&mut self, shell: &mut Shell, cursor: Cursor) { + match &mut self.state.state { + State::Open | State::Closed => { + // don't need to do anything here + } + State::Dragging(_, last_position) => { + if let Some(current_position) = cursor.position() { + let dy = current_position.y - last_position.y; + + match dy.total_cmp(&0.) { + Ordering::Greater => { + self.state.height -= dy; + self.state.height = self.state.height.max(0.); + } + Ordering::Less if self.state.height > self.state.max_height => { + self.state.height -= + dy / (10. * (self.state.height / self.state.max_height)); + } + Ordering::Less => { + self.state.height -= dy; + } + Ordering::Equal => {} + } + + *last_position = current_position; + } + } + State::Animate(instant, keyframes) => { + keyframes.advance_by(instant.elapsed().as_secs_f64()); + self.state.height = keyframes.now(); + *instant = Instant::now(); + + if keyframes.finished() { + if self.state.height <= 0. { + if let Some(event) = self.on_close.clone() { + shell.publish(event); + } + + self.state.state = State::Closed; + } else { + self.state.state = State::Open; + } + } else { + shell.request_redraw(RedrawRequest::NextFrame); + } + } + } + } +} + +impl<'a, 'b, M: Clone> overlay::Overlay for Overlay<'a, 'b, M> { + fn layout(&self, renderer: &Renderer, bounds: Size, position: Point) -> Node { + let limits = Limits::new(Size::ZERO, bounds) + .width(Length::Fill) + .height(Length::Fill); + + let mut child = self.content.as_widget().layout(renderer, &limits); + child.align(Alignment::Start, Alignment::Start, limits.max()); + child.move_to(Point { + x: 0.0, + y: bounds.height - self.state.height, + }); + + let mut node = Node::with_children(bounds, vec![child]); + node.move_to(position); + + node + } + + fn draw( + &self, + renderer: &mut Renderer, + theme: &Theme, + style: &Style, + layout: Layout<'_>, + cursor: Cursor, + ) { + if matches!(self.state.state, State::Closed) { + return; + } + + renderer.fill_quad( + renderer::Quad { + bounds: layout.bounds(), + border_radius: BorderRadius::default(), + border_width: 0.0, + border_color: Color::TRANSPARENT, + }, + Color { + a: (0.8 / (self.state.max_height / self.state.height)).min(0.9), + ..Color::BLACK + }, + ); + + let bounds = Rectangle::new( + Point::new(0.0, layout.bounds().height - self.state.height), + Size { + width: layout.bounds().width, + height: self.state.height, + }, + ); + + renderer.fill_quad( + renderer::Quad { + bounds, + border_radius: 0.0.into(), + border_width: 0.0, + border_color: Color::default(), + }, + Color::WHITE, + ); + + self.content.as_widget().draw( + self.tree, + renderer, + theme, + style, + layout.children().next().unwrap(), + cursor, + &bounds, + ); + } + + fn operate( + &mut self, + layout: Layout<'_>, + renderer: &Renderer, + operation: &mut dyn Operation, + ) { + self.content.as_widget().operate( + self.tree, + layout.children().next().unwrap(), + renderer, + operation, + ); + } + + fn on_event( + &mut self, + event: Event, + layout: Layout<'_>, + cursor: Cursor, + renderer: &Renderer, + clipboard: &mut dyn Clipboard, + shell: &mut Shell<'_, M>, + ) -> Status { + let mut status = self.content.as_widget_mut().on_event( + self.tree, + event.clone(), + layout.children().next().unwrap(), + cursor, + renderer, + clipboard, + shell, + &layout.bounds(), + ); + + if let (Status::Ignored, Event::Mouse(mouse_event)) = (status, &event) { + let captured = self.handle_mouse_event(mouse_event, &layout, cursor); + + if captured { + status = Status::Captured; + + if let (Some(msg), State::Closed) = (&self.on_close, &self.state.state) { + shell.publish(msg.clone()); + } else { + shell.request_redraw(RedrawRequest::NextFrame); + } + } + } else if let Event::Window(window::Event::RedrawRequested(_)) = &event { + self.handle_redraw(shell, cursor); + } + + status + } + + fn mouse_interaction( + &self, + layout: Layout<'_>, + cursor: Cursor, + viewport: &Rectangle, + renderer: &Renderer, + ) -> Interaction { + self.content.as_widget().mouse_interaction( + self.tree, + layout.children().next().unwrap(), + cursor, + viewport, + renderer, + ) + } + + fn overlay<'c>( + &'c mut self, + layout: Layout<'_>, + renderer: &Renderer, + ) -> Option> { + self.content + .as_widget_mut() + .overlay(self.tree, layout.children().next().unwrap(), renderer) + } +} + +impl<'a, M> From> for Element<'a, M> +where + M: 'a + Clone, +{ + fn from(modal: ContextMenu<'a, M>) -> Self { + Element::new(modal) + } +} + +#[derive(Default)] +pub struct OverlayState { + max_height: f32, + height: f32, + state: State, +} + +#[derive(Default)] +pub enum State { + #[default] + Open, + Animate(Instant, AnimationSequence), + Dragging(Instant, Point), + Closed, +} diff --git a/shalom/src/widgets/image_card.rs b/shalom/src/widgets/image_card.rs new file mode 100644 index 0000000..da515ec --- /dev/null +++ b/shalom/src/widgets/image_card.rs @@ -0,0 +1,237 @@ +use iced::{ + advanced::{ + image::{Data, Renderer as ImageRenderer}, + layout::{Limits, Node}, + overlay, + renderer::{Quad, Style}, + widget::Tree, + Clipboard, Layout, Renderer as IRenderer, Shell, Widget, + }, + event::Status, + font::{Stretch, Weight}, + gradient::Linear, + mouse, + mouse::{Button, Cursor}, + theme::Text, + touch, + widget::{image, text}, + Alignment, Background, Color, ContentFit, Degrees, Element, Event, Font, Gradient, Length, + Point, Rectangle, Renderer, Size, Theme, Vector, +}; + +pub fn image_card<'a, M: 'a>( + handle: impl Into, + caption: &'a str, +) -> ImageCard<'a, M> { + let image_handle = handle.into(); + + ImageCard { + image_handle: image_handle.clone(), + text: text(caption) + .size(14) + .font(Font { + weight: Weight::Bold, + stretch: Stretch::Condensed, + ..Font::with_name("Helvetica Neue") + }) + .style(Text::Color(Color::WHITE)) + .into(), + on_press: None, + width: Length::FillPortion(1), + height: Length::Fixed(128.0), + } +} + +pub struct ImageCard<'a, M> { + image_handle: image::Handle, + text: Element<'a, M, Renderer>, + on_press: Option, + width: Length, + height: Length, +} + +impl<'a, M> ImageCard<'a, M> { + pub fn on_press(mut self, msg: M) -> Self { + self.on_press = Some(msg); + self + } +} + +impl<'a, M: Clone> Widget for ImageCard<'a, M> { + fn width(&self) -> Length { + self.width + } + + fn height(&self) -> Length { + self.height + } + + fn layout(&self, _renderer: &Renderer, limits: &Limits) -> Node { + let limits = limits.width(self.width).height(self.height); + let size = limits.resolve(Size::ZERO); + + Node::new(size) + } + + fn draw( + &self, + _state: &Tree, + renderer: &mut Renderer, + _theme: &Theme, + _style: &Style, + layout: Layout<'_>, + _cursor: Cursor, + _viewport: &Rectangle, + ) { + let bounds = layout.bounds(); + + // The raw w/h of the underlying image, renderer.dimensions is _really_ + // slow so enforce the use of preparsed images from `theme`. + #[allow(clippy::cast_precision_loss)] + let image_size = match self.image_handle.data() { + Data::Rgba { width, height, .. } => Size::new(*width as f32, *height as f32), + Data::Path(_) | Data::Bytes(_) => panic!("only parsed images are supported"), + }; + + let adjusted_fit = ContentFit::Cover.fit(image_size, bounds.size()); + + renderer.with_layer(bounds, |renderer| { + let offset = Vector::new( + (bounds.width - adjusted_fit.width).min(0.0) / 1.5, + (bounds.height - adjusted_fit.height).min(0.0) / 1.5, + ); + + let drawing_bounds = Rectangle { + width: adjusted_fit.width, + height: adjusted_fit.height, + ..bounds + }; + + renderer.draw(self.image_handle.clone(), drawing_bounds + offset); + }); + } + + fn children(&self) -> Vec { + vec![Tree::new(&self.text)] + } + + fn diff(&self, tree: &mut Tree) { + tree.diff_children(&[&self.text]); + } + + fn overlay<'b>( + &'b mut self, + state: &'b mut Tree, + layout: Layout<'_>, + _renderer: &Renderer, + ) -> Option> { + Some(overlay::Element::new( + layout.position(), + Box::new(Overlay { + text: &mut self.text, + tree: &mut state.children[0], + size: layout.bounds().size(), + on_press: self.on_press.as_ref(), + }), + )) + } +} + +struct Overlay<'a, 'b, M> { + text: &'b mut Element<'a, M, Renderer>, + tree: &'b mut Tree, + size: Size, + on_press: Option<&'b M>, +} + +impl<'a, 'b, M: Clone> overlay::Overlay for Overlay<'a, 'b, M> { + fn layout(&self, renderer: &Renderer, _bounds: Size, position: Point) -> Node { + let limits = Limits::new(Size::ZERO, self.size).pad([0, 0, 10, 0].into()); + + let mut child = self.text.as_widget().layout(renderer, &limits); + child.align(Alignment::Center, Alignment::End, limits.max()); + + let mut node = Node::with_children(self.size, vec![child]); + node.move_to(position); + + node + } + + fn draw( + &self, + renderer: &mut Renderer, + theme: &Theme, + style: &Style, + layout: Layout<'_>, + cursor: Cursor, + ) { + renderer.fill_quad( + Quad { + bounds: Rectangle { + height: self.size.height + 12., + width: self.size.width + 12., + x: layout.bounds().x - 6., + y: layout.bounds().y - 6., + }, + border_radius: [20., 20., 20., 20.].into(), + border_width: 10., + border_color: Color::WHITE, + }, + Background::Gradient(Gradient::Linear( + Linear::new(Degrees(270.)) + .add_stop(0.0, Color::from_rgba8(0, 0, 0, 0.0)) + .add_stop(0.4, Color::from_rgba8(0, 0, 0, 0.0)) + .add_stop(1.0, Color::from_rgba8(0, 0, 0, 0.8)), + )), + ); + + self.text.as_widget().draw( + self.tree, + renderer, + theme, + style, + layout.children().next().unwrap(), + cursor, + &layout.bounds(), + ); + } + + fn on_event( + &mut self, + event: Event, + layout: Layout<'_>, + cursor: Cursor, + _renderer: &Renderer, + _clipboard: &mut dyn Clipboard, + shell: &mut Shell<'_, M>, + ) -> Status { + if !cursor.is_over(Rectangle { + height: self.size.height, + width: self.size.width, + ..layout.bounds() + }) { + return Status::Ignored; + } + + if let Some(on_press) = self.on_press { + if let Event::Mouse(mouse::Event::ButtonPressed(Button::Left)) + | Event::Touch(touch::Event::FingerPressed { .. }) = &event + { + shell.publish(on_press.clone()); + + return Status::Captured; + } + } + + Status::Ignored + } +} + +impl<'a, M> From> for Element<'a, M> +where + M: 'a + Clone, +{ + fn from(modal: ImageCard<'a, M>) -> Self { + Element::new(modal) + } +} diff --git a/shalom/src/widgets/media_player.rs b/shalom/src/widgets/media_player.rs new file mode 100644 index 0000000..d31a863 --- /dev/null +++ b/shalom/src/widgets/media_player.rs @@ -0,0 +1,233 @@ +use std::{fmt::Display, time::Duration}; + +use iced::{ + advanced::graphics::core::Element, + theme::{Svg, Text}, + widget::{column as icolumn, component, container, row, slider, svg, text, Component}, + Alignment, Length, Renderer, Theme, +}; + +use crate::{ + theme::{ + colours::{SKY_500, SLATE_400, SLATE_600}, + Icon, + }, + widgets::mouse_area::mouse_area, +}; + +pub fn media_player() -> MediaPlayer { + MediaPlayer::default() +} + +pub struct MediaPlayer { + height: Length, + width: Length, + now_playing: NowPlaying, + on_something: Option, + track_length: Duration, +} + +impl Default for MediaPlayer { + fn default() -> Self { + Self { + height: Length::Shrink, + width: Length::Fill, + now_playing: NowPlaying { + album_art: "https://i.scdn.co/image/ab67616d00004851d771166c366eff01950de570" + .to_string(), + song: "Almost Had to Start a Fight/In and Out of Patience".to_string(), + artist: "Parquet Court".to_string(), + loved: true, + }, + on_something: None, + track_length: Duration::from_secs(194), + } + } +} + +impl Component for MediaPlayer { + type State = State; + type Event = Event; + + fn update(&mut self, state: &mut Self::State, event: Self::Event) -> Option { + match event { + Event::VolumeChange(new) => { + state.volume = new; + None + } + Event::PositionChange(new) => { + state.track_position = Duration::from_secs_f64(new); + None + } + Event::TogglePlaying => { + state.playing = !state.playing; + None + } + Event::ToggleMute => { + state.muted = !state.muted; + None + } + Event::ToggleRepeat => { + state.repeat = !state.repeat; + None + } + } + } + + fn view(&self, state: &Self::State) -> Element<'_, Self::Event, Renderer> { + let icon_style = |v| Svg::Custom(Box::new(if v { Style::Active } else { Style::Inactive })); + + container( + row![ + container(crate::widgets::track_card::track_card( + self.now_playing.artist.clone(), + self.now_playing.song.clone(), + false, + ),) + .width(Length::FillPortion(8)), + icolumn![ + // container( + // svg(Icon::Hamburger) + // .height(30) + // .width(30), + // ) + // .align_x(Horizontal::Right) + // .align_y(Vertical::Center) + // .width(Length::Fill), + row![ + svg(Icon::Backward) + .height(24) + .width(24) + .style(icon_style(false)), + mouse_area( + svg(if state.playing { + Icon::Pause + } else { + Icon::Play + }) + .height(24) + .width(24) + .style(icon_style(false)) + ) + .on_press(Event::TogglePlaying), + svg(Icon::Forward) + .height(24) + .width(24) + .style(icon_style(false)), + mouse_area( + svg(Icon::Repeat) + .height(24) + .width(24) + .style(icon_style(state.repeat)), + ) + .on_press(Event::ToggleRepeat), + ] + .spacing(14), + row![ + text(format_time(state.track_position)) + .style(Text::Color(SLATE_400)) + .size(12), + slider( + 0.0..=self.track_length.as_secs_f64(), + state.track_position.as_secs_f64(), + Event::PositionChange + ), + text(format_time(self.track_length)) + .style(Text::Color(SLATE_400)) + .size(12), + ] + .spacing(14) + .align_items(Alignment::Center), + ] + .spacing(8) + .align_items(Alignment::Center) + .width(Length::FillPortion(12)), + row![ + mouse_area( + svg(if state.muted { + Icon::SpeakerMuted + } else { + Icon::Speaker + }) + .height(16) + .width(16) + .style(icon_style(false)), + ) + .on_press(Event::ToggleMute), + slider(0..=100, state.volume, Event::VolumeChange).width(128), + ] + .align_items(Alignment::Center) + .width(Length::FillPortion(4)) + .spacing(12), + ] + .align_items(Alignment::Center) + .spacing(48), + ) + .height(self.height) + .width(self.width) + .center_x() + .center_y() + .into() + } +} + +pub struct NowPlaying { + album_art: String, + song: String, + artist: String, + loved: bool, +} + +#[derive(Default)] +pub struct State { + muted: bool, + volume: u8, + track_position: Duration, + playing: bool, + repeat: bool, +} + +#[derive(Clone)] +pub enum Event { + TogglePlaying, + ToggleMute, + ToggleRepeat, + VolumeChange(u8), + PositionChange(f64), +} + +impl<'a, M> From> for Element<'a, M, Renderer> +where + M: 'a + Clone, +{ + fn from(card: MediaPlayer) -> Self { + component(card) + } +} + +fn format_time(duration: Duration) -> impl Display { + let secs = duration.as_secs(); + let minutes = secs / 60; + let seconds = secs % 60; + + format!("{minutes:02}:{seconds:02}") +} + +#[derive(Copy, Clone)] +pub enum Style { + Active, + Inactive, +} + +impl svg::StyleSheet for Style { + type Style = Theme; + + fn appearance(&self, _style: &Self::Style) -> svg::Appearance { + let color = match self { + Self::Active => SKY_500, + Self::Inactive => SLATE_600, + }; + + svg::Appearance { color: Some(color) } + } +} diff --git a/shalom/src/widgets/mod.rs b/shalom/src/widgets/mod.rs new file mode 100644 index 0000000..413cbd5 --- /dev/null +++ b/shalom/src/widgets/mod.rs @@ -0,0 +1,6 @@ +pub mod context_menu; +pub mod image_card; +pub mod media_player; +pub mod mouse_area; +pub mod toggle_card; +pub mod track_card; diff --git a/shalom/src/widgets/mouse_area.rs b/shalom/src/widgets/mouse_area.rs new file mode 100644 index 0000000..f6bbb59 --- /dev/null +++ b/shalom/src/widgets/mouse_area.rs @@ -0,0 +1,347 @@ +//! A container for capturing mouse events. +//! +//! Pretty much just a copy of [`iced::widget::mouse_area`] but with the ability +//! to trigger an event after a button has been held down for a set amount of +//! time. + +use std::time::{Duration, Instant}; + +use iced::{ + advanced::{ + layout, mouse, overlay, renderer, + widget::{tree, Operation, Tree}, + Clipboard, Layout, Shell, Widget, + }, + event, touch, + window::RedrawRequest, + Element, Event, Length, Rectangle, +}; + +pub fn mouse_area<'a, Message, Renderer>( + widget: impl Into>, +) -> MouseArea<'a, Message, Renderer> +where + Renderer: renderer::Renderer, +{ + MouseArea::new(widget) +} + +/// Emit messages on mouse events. +#[allow(missing_debug_implementations)] +pub struct MouseArea<'a, Message, Renderer> { + content: Element<'a, Message, Renderer>, + on_press: Option, + on_cancel: Option, + on_hold: Option<(Message, Duration)>, + on_release: Option, + on_right_press: Option, + on_right_release: Option, + on_middle_press: Option, + on_middle_release: Option, +} + +impl<'a, Message, Renderer> MouseArea<'a, Message, Renderer> { + /// The message to emit on a left button press. + #[must_use] + pub fn on_press(mut self, message: Message) -> Self { + self.on_press = Some(message); + self + } + + /// The message to emit when holding down an item. + #[must_use] + pub fn on_hold(mut self, message: Message, duration: Duration) -> Self { + self.on_hold = Some((message, duration)); + self + } + + /// The message to emit when a user "cancels" a `press`. + #[must_use] + pub fn on_cancel(mut self, message: Message) -> Self { + self.on_cancel = Some(message); + self + } + + /// The message to emit on a left button release. + #[must_use] + pub fn on_release(mut self, message: Message) -> Self { + self.on_release = Some(message); + self + } + + /// The message to emit on a right button press. + #[must_use] + pub fn on_right_press(mut self, message: Message) -> Self { + self.on_right_press = Some(message); + self + } + + /// The message to emit on a right button release. + #[must_use] + pub fn on_right_release(mut self, message: Message) -> Self { + self.on_right_release = Some(message); + self + } + + /// The message to emit on a middle button press. + #[must_use] + pub fn on_middle_press(mut self, message: Message) -> Self { + self.on_middle_press = Some(message); + self + } + + /// The message to emit on a middle button release. + #[must_use] + pub fn on_middle_release(mut self, message: Message) -> Self { + self.on_middle_release = Some(message); + self + } +} + +/// Local state of the [`MouseArea`]. +#[derive(Default)] +struct State { + // TODO: Support on_mouse_enter and on_mouse_exit + held_since: Option, +} + +impl<'a, Message, Renderer> MouseArea<'a, Message, Renderer> { + /// Creates a [`MouseArea`] with the given content. + pub fn new(content: impl Into>) -> Self { + MouseArea { + content: content.into(), + on_press: None, + on_hold: None, + on_cancel: None, + on_release: None, + on_right_press: None, + on_right_release: None, + on_middle_press: None, + on_middle_release: None, + } + } +} + +impl<'a, Message, Renderer> Widget for MouseArea<'a, Message, Renderer> +where + Renderer: renderer::Renderer, + Message: Clone, +{ + fn tag(&self) -> tree::Tag { + tree::Tag::of::() + } + + fn state(&self) -> tree::State { + tree::State::new(State::default()) + } + + fn children(&self) -> Vec { + vec![Tree::new(&self.content)] + } + + fn diff(&self, tree: &mut Tree) { + tree.diff_children(std::slice::from_ref(&self.content)); + } + + fn width(&self) -> Length { + self.content.as_widget().width() + } + + fn height(&self) -> Length { + self.content.as_widget().height() + } + + fn layout(&self, renderer: &Renderer, limits: &layout::Limits) -> layout::Node { + self.content.as_widget().layout(renderer, limits) + } + + fn operate( + &self, + tree: &mut Tree, + layout: Layout<'_>, + renderer: &Renderer, + operation: &mut dyn Operation, + ) { + self.content + .as_widget() + .operate(&mut tree.children[0], layout, renderer, operation); + } + + fn on_event( + &mut self, + tree: &mut Tree, + event: Event, + layout: Layout<'_>, + cursor: mouse::Cursor, + renderer: &Renderer, + clipboard: &mut dyn Clipboard, + shell: &mut Shell<'_, Message>, + viewport: &Rectangle, + ) -> event::Status { + if let event::Status::Captured = self.content.as_widget_mut().on_event( + &mut tree.children[0], + event.clone(), + layout, + cursor, + renderer, + clipboard, + shell, + viewport, + ) { + return event::Status::Captured; + } + + let state = tree.state.downcast_mut::(); + + update(self, state, &event, layout, cursor, shell) + } + + fn mouse_interaction( + &self, + tree: &Tree, + layout: Layout<'_>, + cursor: mouse::Cursor, + viewport: &Rectangle, + renderer: &Renderer, + ) -> mouse::Interaction { + self.content.as_widget().mouse_interaction( + &tree.children[0], + layout, + cursor, + viewport, + renderer, + ) + } + + fn draw( + &self, + tree: &Tree, + renderer: &mut Renderer, + theme: &Renderer::Theme, + renderer_style: &renderer::Style, + layout: Layout<'_>, + cursor: mouse::Cursor, + viewport: &Rectangle, + ) { + self.content.as_widget().draw( + &tree.children[0], + renderer, + theme, + renderer_style, + layout, + cursor, + viewport, + ); + } + + fn overlay<'b>( + &'b mut self, + tree: &'b mut Tree, + layout: Layout<'_>, + renderer: &Renderer, + ) -> Option> { + self.content + .as_widget_mut() + .overlay(&mut tree.children[0], layout, renderer) + } +} + +impl<'a, Message, Renderer> From> + for Element<'a, Message, Renderer> +where + Message: 'a + Clone, + Renderer: 'a + renderer::Renderer, +{ + fn from(area: MouseArea<'a, Message, Renderer>) -> Element<'a, Message, Renderer> { + Element::new(area) + } +} + +/// Processes the given [`Event`] and updates the [`State`] of an [`MouseArea`] +/// accordingly. +fn update( + widget: &mut MouseArea<'_, Message, Renderer>, + state: &mut State, + event: &Event, + layout: Layout<'_>, + cursor: mouse::Cursor, + shell: &mut Shell<'_, Message>, +) -> event::Status { + if !cursor.is_over(layout.bounds()) { + if let (Some(message), Some(_)) = (&widget.on_cancel, state.held_since) { + state.held_since = None; + shell.publish(message.clone()); + } + + return event::Status::Ignored; + } + + if let (Some((message, duration)), Some(held_since)) = + (widget.on_hold.as_ref(), state.held_since) + { + if held_since.elapsed() > *duration { + state.held_since = None; + shell.publish(message.clone()); + } + } + + if let Some(message) = widget.on_press.as_ref() { + if let Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) + | Event::Touch(touch::Event::FingerPressed { .. }) = event + { + shell.publish(message.clone()); + + if let Some((_message, duration)) = widget.on_hold.clone() { + state.held_since = Some(Instant::now()); + shell.request_redraw(RedrawRequest::At(Instant::now() + duration)); + } + + return event::Status::Captured; + } + } + + if let Some(message) = widget.on_release.as_ref() { + if let Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left)) + | Event::Touch(touch::Event::FingerLifted { .. }) = event + { + shell.publish(message.clone()); + state.held_since = None; + + return event::Status::Captured; + } + } + + if let Some(message) = widget.on_right_press.as_ref() { + if let Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Right)) = event { + shell.publish(message.clone()); + + return event::Status::Captured; + } + } + + if let Some(message) = widget.on_right_release.as_ref() { + if let Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Right)) = event { + shell.publish(message.clone()); + + return event::Status::Captured; + } + } + + if let Some(message) = widget.on_middle_press.as_ref() { + if let Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Middle)) = event { + shell.publish(message.clone()); + + return event::Status::Captured; + } + } + + if let Some(message) = widget.on_middle_release.as_ref() { + if let Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Middle)) = event { + shell.publish(message.clone()); + + return event::Status::Captured; + } + } + + event::Status::Ignored +} diff --git a/shalom/src/widgets/toggle_card.rs b/shalom/src/widgets/toggle_card.rs new file mode 100644 index 0000000..930d402 --- /dev/null +++ b/shalom/src/widgets/toggle_card.rs @@ -0,0 +1,240 @@ +#![allow(clippy::module_name_repetitions)] + +use std::time::{Duration, Instant}; + +use iced::{ + alignment::Vertical, + font::{Stretch, Weight}, + theme::{Container, Svg}, + widget::{column, component, container, svg, text}, + Alignment, Background, Color, Element, Font, Length, Renderer, Theme, +}; + +use crate::{ + theme::{ + colours::{AMBER_200, SKY_400, SKY_500, SLATE_200, SLATE_300}, + Icon, + }, + widgets::mouse_area::mouse_area, +}; + +pub const LONG_PRESS_LENGTH: Duration = Duration::from_millis(350); + +pub fn toggle_card(name: &'static str, active: bool) -> ToggleCard { + ToggleCard { + name, + active, + ..ToggleCard::default() + } +} + +pub struct ToggleCard { + icon: Option, + name: &'static str, + height: Length, + width: Length, + active: bool, + on_press: Option, + on_long_press: Option, +} + +impl Default for ToggleCard { + fn default() -> Self { + Self { + icon: None, + name: "", + height: Length::Shrink, + width: Length::Fill, + active: false, + on_press: None, + on_long_press: None, + } + } +} + +impl ToggleCard { + pub fn on_press(mut self, msg: M) -> Self { + self.on_press = Some(msg); + self + } + + pub fn on_long_press(mut self, msg: M) -> Self { + self.on_long_press = Some(msg); + self + } + + pub fn icon(mut self, icon: Icon) -> Self { + self.icon = Some(icon); + self + } + + pub fn height(mut self, height: Length) -> Self { + self.height = height; + self + } + + pub fn width(mut self, width: Length) -> Self { + self.width = width; + self + } +} + +impl iced::widget::Component for ToggleCard { + type State = State; + type Event = ToggleCardEvent; + + fn update(&mut self, state: &mut Self::State, event: Self::Event) -> Option { + match event { + ToggleCardEvent::Down => { + state.mouse_down_start = Some(Instant::now()); + + None + } + ToggleCardEvent::Up => { + let Some(start) = state.mouse_down_start.take() else { + return None; + }; + + if start.elapsed() > LONG_PRESS_LENGTH { + self.on_long_press.clone().or_else(|| self.on_press.clone()) + } else { + self.on_press.clone() + } + } + ToggleCardEvent::Hold => self.on_long_press.clone(), + ToggleCardEvent::Cancel => { + state.mouse_down_start = None; + + None + } + } + } + + fn view(&self, state: &Self::State) -> Element<'_, Self::Event, Renderer> { + let style = match (self.active, state.mouse_down_start) { + (true, None) => Style::Active, + (true, Some(_)) => Style::ActiveHover, + (false, None) => Style::Inactive, + (false, Some(_)) => Style::InactiveHover, + }; + + let icon = self.icon.map(|icon| { + svg(icon) + .height(32) + .width(32) + .style(Svg::Custom(Box::new(style))) + }); + + let name = text(self.name).size(14).font(Font { + weight: Weight::Bold, + stretch: Stretch::Condensed, + ..Font::with_name("Helvetica Neue") + }); + + let col = if let Some(icon) = icon { + column![icon, name] + } else { + column![name] + }; + + mouse_area( + container( + col.spacing(5) + .width(self.width) + .align_items(Alignment::Center), + ) + .height(self.height) + .width(self.width) + .style(Container::Custom(Box::new(style))) + .align_y(Vertical::Bottom) + .padding([20, 20]), + ) + .on_press(ToggleCardEvent::Down) + .on_release(ToggleCardEvent::Up) + .on_hold(ToggleCardEvent::Hold, LONG_PRESS_LENGTH) + .on_cancel(ToggleCardEvent::Cancel) + .into() + } +} + +impl<'a, M> From> for Element<'a, M, Renderer> +where + M: 'a + Clone, +{ + fn from(card: ToggleCard) -> Self { + component(card) + } +} + +#[derive(Default)] +pub struct State { + mouse_down_start: Option, +} + +#[derive(Clone)] +pub enum ToggleCardEvent { + Down, + Up, + Hold, + Cancel, +} + +#[derive(Copy, Clone)] +pub enum Style { + Active, + ActiveHover, + Inactive, + InactiveHover, +} + +impl container::StyleSheet for Style { + type Style = Theme; + + fn appearance(&self, _style: &Self::Style) -> container::Appearance { + match self { + Style::Inactive => container::Appearance { + text_color: Some(Color::BLACK), + background: Some(Background::Color(SLATE_200)), + border_radius: 5.0.into(), + border_width: 0.0, + border_color: Color::default(), + }, + Style::InactiveHover => container::Appearance { + text_color: Some(Color::BLACK), + background: Some(Background::Color(SLATE_300)), + border_radius: 5.0.into(), + border_width: 0.0, + border_color: Color::default(), + }, + Style::Active => container::Appearance { + text_color: Some(Color::WHITE), + background: Some(Background::Color(SKY_400)), + border_radius: 5.0.into(), + border_width: 0.0, + border_color: Color::default(), + }, + Style::ActiveHover => container::Appearance { + text_color: Some(Color::WHITE), + background: Some(Background::Color(SKY_500)), + border_radius: 5.0.into(), + border_width: 0.0, + border_color: Color::default(), + }, + } + } +} + +impl svg::StyleSheet for Style { + type Style = Theme; + + fn appearance(&self, _style: &Self::Style) -> svg::Appearance { + match self { + Style::Active | Style::ActiveHover => svg::Appearance { + color: Some(AMBER_200), + }, + Style::Inactive | Style::InactiveHover => svg::Appearance { + color: Some(Color::BLACK), + }, + } + } +} diff --git a/shalom/src/widgets/track_card.rs b/shalom/src/widgets/track_card.rs new file mode 100644 index 0000000..aaad3e2 --- /dev/null +++ b/shalom/src/widgets/track_card.rs @@ -0,0 +1,65 @@ +use iced::{ + advanced::graphics::core::Element, + theme::Text, + widget::{ + column as icolumn, component, + image::{self, Image}, + row, text, Component, + }, + Alignment, Renderer, +}; + +use crate::theme::colours::SLATE_400; + +pub fn track_card(artist: String, song: String, loved: bool) -> TrackCard { + TrackCard { + artist, + song, + loved, + } +} + +pub struct TrackCard { + artist: String, + song: String, + loved: bool, +} + +impl Component for TrackCard { + type State = State; + type Event = Event; + + fn update(&mut self, _state: &mut Self::State, event: Self::Event) -> Option { + match event {} + } + + fn view(&self, _state: &Self::State) -> Element<'_, Self::Event, Renderer> { + row![ + Image::new(image::Handle::from_path("/tmp/tmp.jpg")) + .width(64) + .height(64), + icolumn![ + text(&self.song).size(14), + text(&self.artist).style(Text::Color(SLATE_400)).size(14) + ] + ] + .align_items(Alignment::Center) + .spacing(10) + .into() + } +} + +#[derive(Default)] +pub struct State {} + +#[derive(Clone)] +pub enum Event {} + +impl<'a, M> From for Element<'a, M, Renderer> +where + M: 'a + Clone, +{ + fn from(card: TrackCard) -> Self { + component(card) + } +} -- libgit2 1.7.2