From 3dc0733cd0804932c9c860e5f1e8f2df1238c14e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Asger=20Geel=20Weirs=C3=B8e?= Date: Wed, 6 May 2026 09:28:14 +0200 Subject: [PATCH] feat: add ahfail-ui crate with animation, audio, display, config Co-Authored-By: Claude Sonnet 4.6 --- Cargo.lock | 531 ++++++++++++++++++++++++++++++ crates/ahfail-ui/Cargo.toml | 15 + crates/ahfail-ui/src/animation.rs | 43 +++ crates/ahfail-ui/src/audio.rs | 12 + crates/ahfail-ui/src/config.rs | 37 +++ crates/ahfail-ui/src/display.rs | 43 +++ crates/ahfail-ui/src/lib.rs | 9 +- crates/ahfail-ui/src/update.rs | 1 + crates/ahfail-ui/src/volume.rs | 7 + 9 files changed, 697 insertions(+), 1 deletion(-) create mode 100644 crates/ahfail-ui/src/animation.rs create mode 100644 crates/ahfail-ui/src/audio.rs create mode 100644 crates/ahfail-ui/src/config.rs create mode 100644 crates/ahfail-ui/src/display.rs create mode 100644 crates/ahfail-ui/src/update.rs create mode 100644 crates/ahfail-ui/src/volume.rs diff --git a/Cargo.lock b/Cargo.lock index 1ee236e..e7b97dd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + [[package]] name = "ahfail-display" version = "0.1.0" @@ -29,6 +35,17 @@ version = "0.1.0" [[package]] name = "ahfail-ui" version = "0.1.0" +dependencies = [ + "gdk", + "gdk-pixbuf", + "gio", + "glib", + "gstreamer", + "gstreamer-player", + "gtk", + "rand", + "ureq", +] [[package]] name = "anyhow" @@ -66,6 +83,12 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + [[package]] name = "bitflags" version = "1.3.2" @@ -96,6 +119,16 @@ dependencies = [ "system-deps", ] +[[package]] +name = "cc" +version = "1.2.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d16d90359e986641506914ba71350897565610e87ce0ad9e6f28569db3dd5c6d" +dependencies = [ + "find-msvc-tools", + "shlex", +] + [[package]] name = "cfg-expr" version = "0.15.8" @@ -112,6 +145,26 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -128,6 +181,31 @@ dependencies = [ "rustc_version", ] +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + [[package]] name = "futures-channel" version = "0.3.31" @@ -531,6 +609,108 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "icu_collections" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" + +[[package]] +name = "icu_properties" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" + +[[package]] +name = "icu_provider" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + [[package]] name = "indexmap" version = "2.12.1" @@ -547,6 +727,18 @@ version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" +[[package]] +name = "litemap" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + [[package]] name = "memchr" version = "2.7.6" @@ -562,6 +754,16 @@ dependencies = [ "autocfg", ] +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + [[package]] name = "muldiv" version = "1.0.1" @@ -642,6 +844,12 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + [[package]] name = "pin-project-lite" version = "0.2.16" @@ -660,6 +868,15 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +[[package]] +name = "potential_utf" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +dependencies = [ + "zerovec", +] + [[package]] name = "ppv-lite86" version = "0.2.21" @@ -757,6 +974,20 @@ dependencies = [ "getrandom", ] +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom", + "libc", + "untrusted", + "windows-sys", +] + [[package]] name = "rustc_version" version = "0.4.1" @@ -766,6 +997,41 @@ dependencies = [ "semver", ] +[[package]] +name = "rustls" +version = "0.23.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef86cd5876211988985292b91c96a8f2d298df24e75989a43a3c73f2d4d8168b" +dependencies = [ + "log", + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pki-types" +version = "1.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30a7197ae7eb376e574fe940d068c30fe0462554a3ddbe4eca7838e049c937a9" +dependencies = [ + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + [[package]] name = "semver" version = "1.0.27" @@ -810,6 +1076,18 @@ dependencies = [ "serde", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "simd-adler32" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" + [[package]] name = "slab" version = "0.4.11" @@ -822,6 +1100,18 @@ version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + [[package]] name = "syn" version = "1.0.109" @@ -844,6 +1134,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + [[package]] name = "system-deps" version = "6.2.2" @@ -883,6 +1184,16 @@ dependencies = [ "syn 2.0.111", ] +[[package]] +name = "tinystr" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +dependencies = [ + "displaydoc", + "zerovec", +] + [[package]] name = "toml" version = "0.8.23" @@ -934,6 +1245,46 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "ureq" +version = "2.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d1a66277ed75f640d608235660df48c8e3c19f3b4edb6a263315626cc3c01d" +dependencies = [ + "base64", + "flate2", + "log", + "once_cell", + "rustls", + "rustls-pki-types", + "url", + "webpki-roots 0.26.11", +] + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "version-compare" version = "0.2.1" @@ -952,6 +1303,24 @@ version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" +[[package]] +name = "webpki-roots" +version = "0.26.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" +dependencies = [ + "webpki-roots 1.0.7", +] + +[[package]] +name = "webpki-roots" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52f5ee44c96cf55f1b349600768e3ece3a8f26010c05265ab73f945bb1a2eb9d" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "winapi" version = "0.3.9" @@ -974,6 +1343,79 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + [[package]] name = "winnow" version = "0.5.40" @@ -992,6 +1434,35 @@ dependencies = [ "memchr", ] +[[package]] +name = "writeable" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" + +[[package]] +name = "yoke" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", + "synstructure", +] + [[package]] name = "zerocopy" version = "0.8.31" @@ -1011,3 +1482,63 @@ dependencies = [ "quote", "syn 2.0.111", ] + +[[package]] +name = "zerofrom" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + +[[package]] +name = "zerotrie" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] diff --git a/crates/ahfail-ui/Cargo.toml b/crates/ahfail-ui/Cargo.toml index 669fbe8..4e5df87 100644 --- a/crates/ahfail-ui/Cargo.toml +++ b/crates/ahfail-ui/Cargo.toml @@ -2,3 +2,18 @@ name = "ahfail-ui" version = "0.1.0" edition = "2021" + +[lib] +name = "ahfail_ui" +crate-type = ["rlib"] + +[dependencies] +gtk = { version = "0.15", package = "gtk", features = ["v3_24"] } +gdk = { version = "0.15", package = "gdk", features = ["v3_24"] } +gstreamer = { version = "0.18", package = "gstreamer", features = ["v1_18"] } +gstreamer-player = { version = "0.18", package = "gstreamer-player" } +glib = { version = "0.15", package = "glib" } +gio = { version = "0.15", package = "gio" } +gdk-pixbuf = "0.15" +rand = "0.8" +ureq = "2" diff --git a/crates/ahfail-ui/src/animation.rs b/crates/ahfail-ui/src/animation.rs new file mode 100644 index 0000000..56d8fb5 --- /dev/null +++ b/crates/ahfail-ui/src/animation.rs @@ -0,0 +1,43 @@ +use gtk::{gdk_pixbuf, gio}; +use gdk_pixbuf::InterpType; +use glib::Cast; + +const SPRITE_SCALE: f64 = 0.6; + +extern "C" { + pub fn ahfail_get_resource() -> *mut gio::ffi::GResource; +} + +/// Registers GResources and loads all sprite frames into a looping PixbufSimpleAnim. +/// Returns None if GResources unavailable or no frames found. +pub unsafe fn load_animation() -> Option { + use glib::translate::from_glib_none; + + let resource_ptr = ahfail_get_resource(); + if resource_ptr.is_null() { return None; } + let resource = from_glib_none::<_, gio::Resource>(resource_ptr); + gio::resources_register(&resource); + + let mut frames = gio::resources_enumerate_children( + "/ahfail/sprites", gio::ResourceLookupFlags::NONE, + ).ok()?; + frames.sort(); + + let mut loaded: Vec = Vec::new(); + for name in frames { + let path = format!("/ahfail/sprites/{}", name); + if let Ok(pb) = gdk_pixbuf::Pixbuf::from_resource(&path) { + let w = (pb.width() as f64 * SPRITE_SCALE) as i32; + let h = (pb.height() as f64 * SPRITE_SCALE) as i32; + let scaled = pb.scale_simple(w, h, InterpType::Bilinear).unwrap_or(pb); + loaded.push(scaled); + } + } + if loaded.is_empty() { return None; } + + let first = &loaded[0]; + let anim = gdk_pixbuf::PixbufSimpleAnim::new(first.width(), first.height(), 12.0); + anim.set_loop(true); + for frame in loaded { anim.add_frame(&frame); } + Some(anim.upcast()) +} diff --git a/crates/ahfail-ui/src/audio.rs b/crates/ahfail-ui/src/audio.rs new file mode 100644 index 0000000..b3dc0ac --- /dev/null +++ b/crates/ahfail-ui/src/audio.rs @@ -0,0 +1,12 @@ +use gstreamer_player as gst_player; +use gtk::glib; + +pub fn create_player(uri: &str) -> gst_player::Player { + let player = gst_player::Player::new(None, None); + player.set_uri(Some(uri)); + player.connect_end_of_stream(glib::clone!(@weak player => move |_| { + player.seek(gstreamer::ClockTime::from_seconds(0)); + })); + player.connect_error(|_, err| eprintln!("[ahfail] GStreamer error: {}", err)); + player +} diff --git a/crates/ahfail-ui/src/config.rs b/crates/ahfail-ui/src/config.rs new file mode 100644 index 0000000..56b98a4 --- /dev/null +++ b/crates/ahfail-ui/src/config.rs @@ -0,0 +1,37 @@ +use gtk::gdk; +use std::ffi::CStr; +use std::ptr; + +// Storage for the command line argument string +pub static mut DEADZONE_ARG: *mut std::os::raw::c_char = ptr::null_mut(); + +pub const DEADZONE_LONG: &[u8] = b"deadzone\0"; +pub const DEADZONE_DESC: &[u8] = b"Area to avoid spawning sprites (x,y,w,h)\0"; +pub const DEADZONE_ARG_DESC: &[u8] = b"x,y,w,h\0"; + +pub struct ModuleConfig { + pub deadzone: Option, +} + +impl ModuleConfig { + pub unsafe fn from_args() -> Self { + let mut deadzone = None; + if !DEADZONE_ARG.is_null() { + let c_str = CStr::from_ptr(DEADZONE_ARG); + if let Ok(s) = c_str.to_str() { + let parts: Vec<&str> = s.split(',').collect(); + if parts.len() == 4 { + if let (Ok(x), Ok(y), Ok(w), Ok(h)) = (parts[0].parse(), parts[1].parse(), parts[2].parse(), parts[3].parse()) { + deadzone = Some(gdk::Rectangle::new(x, y, w, h)); + println!("[ahfail] Configured deadzone: {:?}", deadzone); + } else { + eprintln!("[ahfail] Invalid numbers in deadzone argument: {}", s); + } + } else { + eprintln!("[ahfail] Invalid format for deadzone argument (expected x,y,w,h): {}", s); + } + } + } + Self { deadzone } + } +} diff --git a/crates/ahfail-ui/src/display.rs b/crates/ahfail-ui/src/display.rs new file mode 100644 index 0000000..0a3f980 --- /dev/null +++ b/crates/ahfail-ui/src/display.rs @@ -0,0 +1,43 @@ +use gtk::{gdk_pixbuf, prelude::*}; +use rand::Rng; +use crate::config::ModuleConfig; + +const SPRITE_MARGIN: i32 = 100; +const RETRY_ATTEMPTS: usize = 10; + +pub fn place_sprite( + fixed: >k::Fixed, + animation: &gdk_pixbuf::PixbufAnimation, + screen_w: i32, + screen_h: i32, + config: &ModuleConfig, +) -> gtk::Image { + let sprite_w = animation.width(); + let sprite_h = animation.height(); + + let safe_w = screen_w - SPRITE_MARGIN; + let safe_h = screen_h - SPRITE_MARGIN; + + let max_x = (safe_w - sprite_w).max(0); + let max_y = (safe_h - sprite_h).max(0); + + let mut rng = rand::thread_rng(); + let mut x = rng.gen_range(0..=max_x); + let mut y = rng.gen_range(0..=max_y); + + if let Some(dz) = config.deadzone { + for _ in 0..RETRY_ATTEMPTS { + let overlaps_x = x < dz.x() + dz.width() && x + sprite_w > dz.x(); + let overlaps_y = y < dz.y() + dz.height() && y + sprite_h > dz.y(); + if !(overlaps_x && overlaps_y) { + break; + } + x = rng.gen_range(0..=max_x); + y = rng.gen_range(0..=max_y); + } + } + + let image = gtk::Image::from_animation(animation); + fixed.put(&image, x, y); + image +} diff --git a/crates/ahfail-ui/src/lib.rs b/crates/ahfail-ui/src/lib.rs index 2200a7e..a736385 100644 --- a/crates/ahfail-ui/src/lib.rs +++ b/crates/ahfail-ui/src/lib.rs @@ -1 +1,8 @@ -pub fn placeholder() {} +pub mod animation; +pub mod audio; +pub mod config; +pub mod display; +pub mod update; +pub mod volume; + +pub const VERSION: &str = env!("CARGO_PKG_VERSION"); diff --git a/crates/ahfail-ui/src/update.rs b/crates/ahfail-ui/src/update.rs new file mode 100644 index 0000000..0d2384e --- /dev/null +++ b/crates/ahfail-ui/src/update.rs @@ -0,0 +1 @@ +pub fn check_for_update(_current_version: &str) {} diff --git a/crates/ahfail-ui/src/volume.rs b/crates/ahfail-ui/src/volume.rs new file mode 100644 index 0000000..ef8336b --- /dev/null +++ b/crates/ahfail-ui/src/volume.rs @@ -0,0 +1,7 @@ +pub struct VolumeState; + +pub fn save_and_set_max() -> Option { + None +} + +pub fn restore(_state: VolumeState) {}