diff --git a/Cargo.lock b/Cargo.lock index 18af8a5..69196a4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,73 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "ab_glyph" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe21446ad43aa56417a767f3e2f3d7c4ca522904de1dd640529a76e9c5c3b33c" +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 = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aho-corasick" +version = "0.7.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +dependencies = [ + "memchr", +] + +[[package]] +name = "android-activity" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c77a0045eda8b888c76ea473c2b0515ba6f471d318f8927c5c72240937035a6" +dependencies = [ + "android-properties", + "bitflags 1.3.2", + "cc", + "jni-sys", + "libc", + "log", + "ndk", + "ndk-context", + "ndk-sys", + "num_enum", +] + +[[package]] +name = "android-properties" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04" + +[[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.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" + [[package]] name = "autocfg" version = "1.1.0" @@ -14,12 +81,53 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" +[[package]] +name = "base64" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" + [[package]] name = "base64ct" version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +[[package]] +name = "bindgen" +version = "0.65.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfdf7b466f9a4903edc73f95d6d2bcd5baf8ae620638762244d3f60143643cc5" +dependencies = [ + "bitflags 1.3.2", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "log", + "peeking_take_while", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.27", + "which", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" + [[package]] name = "block-buffer" version = "0.10.4" @@ -29,24 +137,153 @@ 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.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" + +[[package]] +name = "bytemuck" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" + [[package]] name = "byteorder" version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +[[package]] +name = "calloop" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a59225be45a478d772ce015d9743e49e92798ece9e34eda9a6aa2a6a7f40192" +dependencies = [ + "log", + "nix 0.25.1", + "slotmap", + "thiserror", + "vec_map", +] + +[[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +dependencies = [ + "jobserver", +] + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + [[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 = "cgl" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ced0551234e87afee12411d535648dd89d2e7f34c78b753395567aff3d447ff" +dependencies = [ + "libc", +] + +[[package]] +name = "clang-sys" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f" +dependencies = [ + "glob", + "libc", + "libloading", +] + [[package]] name = "const-oid" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "520fbf3c07483f94e3e3ca9d0cfd913d7718ef2483d2cfd91c0d9e91474ab913" +[[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.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "foreign-types", + "libc", +] + [[package]] name = "cpufeatures" version = "0.2.6" @@ -56,6 +293,15 @@ 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 = "crypto-common" version = "0.1.6" @@ -89,202 +335,797 @@ dependencies = [ ] [[package]] -name = "generic-array" -version = "0.14.7" +name = "dispatch" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] +checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" [[package]] -name = "getrandom" -version = "0.2.8" +name = "dlib" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +checksum = "ac1b7517328c04c2aa68422fc60a41b92208182142ed04a25879c26c8f878794" dependencies = [ - "cfg-if", - "libc", - "wasi", + "libloading", ] [[package]] -name = "lazy_static" -version = "1.4.0" +name = "downcast-rs" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -dependencies = [ - "spin", -] +checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" [[package]] -name = "libc" -version = "0.2.141" +name = "either" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" [[package]] -name = "libm" -version = "0.2.6" +name = "equivalent" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] -name = "loki-client" -version = "0.1.0" +name = "filetime" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cbc844cecaee9d4443931972e1289c8ff485cb4cc2767cb03ca139ed6885153" dependencies = [ - "loki-shared", - "lokui", - "protolok", + "cfg-if", + "libc", + "redox_syscall 0.2.16", + "windows-sys 0.48.0", ] [[package]] -name = "loki-server" -version = "0.1.0" +name = "flate2" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" dependencies = [ - "loki-shared", - "protolok", + "crc32fast", + "miniz_oxide", ] [[package]] -name = "loki-shared" -version = "0.1.0" +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 = "lokui" -version = "0.1.0" +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] -name = "num-bigint-dig" -version = "0.8.2" +name = "form_urlencoded" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2399c9463abc5f909349d8aa9ba080e0b88b3ce2885389b60b993f39b1a56905" +checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" dependencies = [ - "byteorder", - "lazy_static", - "libm", - "num-integer", - "num-iter", - "num-traits", - "rand", - "smallvec", - "zeroize", + "percent-encoding", ] [[package]] -name = "num-integer" -version = "0.1.45" +name = "generic-array" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ - "autocfg", - "num-traits", + "typenum", + "version_check", ] [[package]] -name = "num-iter" -version = "0.1.43" +name = "getrandom" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" dependencies = [ - "autocfg", - "num-integer", - "num-traits", + "cfg-if", + "libc", + "wasi", ] [[package]] -name = "num-traits" -version = "0.2.15" +name = "gl" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "a94edab108827d67608095e269cf862e60d920f144a5026d3dbcfd8b877fb404" dependencies = [ - "autocfg", - "libm", + "gl_generator", ] [[package]] -name = "pem-rfc7468" -version = "0.6.0" +name = "gl_generator" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d159833a9105500e0398934e205e0773f0b27529557134ecfc51c27646adac" +checksum = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d" dependencies = [ - "base64ct", + "khronos_api", + "log", + "xml-rs", ] [[package]] -name = "pkcs1" -version = "0.4.1" +name = "glob" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eff33bdbdfc54cc98a2eca766ebdec3e1b8fb7387523d5c9c9a2891da856f719" -dependencies = [ - "der", - "pkcs8", - "spki", - "zeroize", -] +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] -name = "pkcs8" -version = "0.9.0" +name = "glutin" +version = "0.30.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" +checksum = "23b0385782048be65f0a9dd046c469d6a758a53fe1aa63a8111dea394d2ffa2f" dependencies = [ - "der", - "spki", + "bitflags 1.3.2", + "cfg_aliases", + "cgl", + "core-foundation", + "dispatch", + "glutin_egl_sys", + "glutin_glx_sys", + "glutin_wgl_sys", + "libloading", + "objc2", + "once_cell", + "raw-window-handle", + "wayland-sys 0.30.1", + "windows-sys 0.45.0", + "x11-dl", ] [[package]] -name = "ppv-lite86" -version = "0.2.17" +name = "glutin-winit" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "protolok" -version = "0.1.0" +checksum = "629a873fc04062830bfe8f97c03773bcd7b371e23bcc465d0a61448cd1588fa4" dependencies = [ - "base16ct", - "rand", - "rsa", - "sha2", + "cfg_aliases", + "glutin", + "raw-window-handle", + "winit", ] [[package]] -name = "rand" -version = "0.8.5" +name = "glutin_egl_sys" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +checksum = "1b3bcbddc51573b977fc6dca5d93867e4f29682cdbaf5d13e48f4fa4346d4d87" dependencies = [ - "libc", - "rand_chacha", - "rand_core", + "gl_generator", + "windows-sys 0.45.0", ] [[package]] -name = "rand_chacha" -version = "0.3.1" +name = "glutin_glx_sys" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +checksum = "1b53cb5fe568964aa066a3ba91eac5ecbac869fb0842cd0dc9e412434f1a1494" dependencies = [ - "ppv-lite86", - "rand_core", + "gl_generator", + "x11-dl", ] [[package]] -name = "rand_core" -version = "0.6.4" +name = "glutin_wgl_sys" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +checksum = "ef89398e90033fc6bc65e9bd42fd29bbbfd483bda5b56dc5562f455550618165" dependencies = [ - "getrandom", + "gl_generator", ] [[package]] -name = "rsa" -version = "0.8.2" +name = "hashbrown" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55a77d189da1fee555ad95b7e50e7457d91c0e089ec68ca69ad2989413bbdab4" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "idna" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[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 = "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.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "khronos_api" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin", +] + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "libc" +version = "0.2.141" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5" + +[[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 = "libm" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "loki-client" +version = "0.1.0" +dependencies = [ + "loki-shared", + "lokui", + "protolok", +] + +[[package]] +name = "loki-server" +version = "0.1.0" +dependencies = [ + "loki-shared", + "protolok", +] + +[[package]] +name = "loki-shared" +version = "0.1.0" + +[[package]] +name = "lokui" +version = "0.1.0" +dependencies = [ + "gl", + "glutin", + "glutin-winit", + "raw-window-handle", + "skia-safe", + "winit", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memmap2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" +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 = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" +dependencies = [ + "libc", + "log", + "wasi", + "windows-sys 0.45.0", +] + +[[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", + "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.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "libc", + "memoffset", +] + +[[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", +] + +[[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-bigint-dig" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2399c9463abc5f909349d8aa9ba080e0b88b3ce2885389b60b993f39b1a56905" +dependencies = [ + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand", + "smallvec", + "zeroize", +] + +[[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-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_enum" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" +dependencies = [ + "num_enum_derive", +] + +[[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 = "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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe31e5425d3d0b89a15982c024392815da40689aceb34bad364d58732bcfd649" +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 = "once_cell" +version = "1.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" + +[[package]] +name = "orbclient" +version = "0.3.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e9829e16c5e112e94efb5e2ad1fe17f8c1c99bb0fcdc8c65c44e935d904767d" +dependencies = [ + "cfg-if", + "redox_syscall 0.2.16", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "owned_ttf_parser" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e25e9fb15717794fae58ab55c26e044103aad13186fbb625893f9a3bbcc24228" +dependencies = [ + "ttf-parser", +] + +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + +[[package]] +name = "pem-rfc7468" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d159833a9105500e0398934e205e0773f0b27529557134ecfc51c27646adac" +dependencies = [ + "base64ct", +] + +[[package]] +name = "percent-encoding" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" + +[[package]] +name = "pkcs1" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eff33bdbdfc54cc98a2eca766ebdec3e1b8fb7387523d5c9c9a2891da856f719" +dependencies = [ + "der", + "pkcs8", + "spki", + "zeroize", +] + +[[package]] +name = "pkcs8" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" + +[[package]] +name = "png" +version = "0.17.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d708eaf860a19b19ce538740d2b4bdeeb8337fa53f7738455e706623ad5c638" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "prettyplease" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c64d9ba0963cdcea2e1b2230fbae2bab30eb25a174be395c41e764bfb65dd62" +dependencies = [ + "proc-macro2", + "syn 2.0.27", +] + +[[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", +] + +[[package]] +name = "proc-macro2" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "protolok" +version = "0.1.0" +dependencies = [ + "base16ct", + "rand", + "rsa", + "sha2", +] + +[[package]] +name = "quote" +version = "1.0.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" +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 = "raw-window-handle" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" + +[[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 = "regex" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin", + "untrusted", + "web-sys", + "winapi", +] + +[[package]] +name = "rsa" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55a77d189da1fee555ad95b7e50e7457d91c0e089ec68ca69ad2989413bbdab4" dependencies = [ "byteorder", "digest", @@ -301,53 +1142,354 @@ dependencies = [ ] [[package]] -name = "sha2" -version = "0.10.6" +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustls" +version = "0.21.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79ea77c539259495ce8ca47f53e66ae0330a8819f67e23ac96ca02f50e7b7d36" +dependencies = [ + "log", + "ring", + "rustls-webpki 0.101.2", + "sct", +] + +[[package]] +name = "rustls-webpki" +version = "0.100.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6207cd5ed3d8dca7816f8f3725513a34609c0c765bf652b8c3cb4cfd87db46b" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "rustls-webpki" +version = "0.101.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "513722fd73ad80a71f72b61009ea1b584bcfa1483ca93949c8f290298837fa59" +dependencies = [ + "ring", + "untrusted", +] + +[[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 = "sct" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +dependencies = [ + "ring", + "untrusted", +] + +[[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", + "smithay-client-toolkit", + "tiny-skia", +] + +[[package]] +name = "serde" +version = "1.0.159" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c04e8343c3daeec41f58990b9d77068df31209f2af111e059e9fe9646693065" + +[[package]] +name = "serde_json" +version = "1.0.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46266871c240a00b8f503b877622fe33430b3c7d963bdc0f2adc511e54a1eae3" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_spanned" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" +dependencies = [ + "serde", +] + +[[package]] +name = "sha2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shlex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" + +[[package]] +name = "signature" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" +dependencies = [ + "digest", + "rand_core", +] + +[[package]] +name = "skia-bindings" +version = "0.63.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffc650a2d45d9acb7e251568dc6193d882cf66aeb78e5dcc08bc2b816ffbbd5" +dependencies = [ + "bindgen", + "cc", + "flate2", + "heck", + "lazy_static", + "regex", + "serde_json", + "tar", + "toml", + "ureq", +] + +[[package]] +name = "skia-safe" +version = "0.63.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae6df6412e061d9792938efc923dc41236edf778058ecc63dc385cd5d5a9ac1" +dependencies = [ + "bitflags 2.3.3", + "lazy_static", + "skia-bindings", +] + +[[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.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" + +[[package]] +name = "smithay-client-toolkit" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f307c47d32d2715eb2e0ece5589057820e0e5e70d07c247d1063e844e107f454" +dependencies = [ + "bitflags 1.3.2", + "calloop", + "dlib", + "lazy_static", + "log", + "memmap2", + "nix 0.24.3", + "pkg-config", + "wayland-client", + "wayland-cursor", + "wayland-protocols", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spki" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "strict-num" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9df65f20698aeed245efdde3628a6b559ea1239bbb871af1b6e3b58c413b2bd1" + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + +[[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.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b60f673f44a8255b9c8c657daf66a596d435f2da81a555b06dc644d080ba45e0" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tar" +version = "0.4.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec96d2ffad078296368d46ff1cb309be1c23c513b4ab0e22a45de0185275ac96" +dependencies = [ + "filetime", + "libc", + "xattr", +] + +[[package]] +name = "thiserror" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.27", +] + +[[package]] +name = "tiny-skia" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfef3412c6975196fdfac41ef232f910be2bb37b9dd3313a49a1a6bc815a5bdb" dependencies = [ + "arrayref", + "arrayvec", + "bytemuck", "cfg-if", - "cpufeatures", - "digest", + "png", + "tiny-skia-path", ] [[package]] -name = "signature" -version = "2.1.0" +name = "tiny-skia-path" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" +checksum = "a4b5edac058fc98f51c935daea4d805b695b38e2f151241cad125ade2a2ac20d" dependencies = [ - "digest", - "rand_core", + "arrayref", + "bytemuck", + "strict-num", ] [[package]] -name = "smallvec" -version = "1.10.0" +name = "tinyvec" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] [[package]] -name = "spin" -version = "0.5.2" +name = "tinyvec_macros" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] -name = "spki" -version = "0.6.0" +name = "toml" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" +checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542" dependencies = [ - "base64ct", - "der", + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", ] [[package]] -name = "subtle" -version = "2.5.0" +name = "toml_datetime" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" +dependencies = [ + "indexmap", + "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 = "typenum" @@ -355,6 +1497,66 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +[[package]] +name = "unicode-bidi" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" + +[[package]] +name = "unicode-ident" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "ureq" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b11c96ac7ee530603dcdf68ed1557050f374ce55a5a07193ebf8cbc9f8927e9" +dependencies = [ + "base64", + "flate2", + "log", + "once_cell", + "rustls", + "rustls-webpki 0.100.1", + "url", + "webpki-roots", +] + +[[package]] +name = "url" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[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" @@ -367,6 +1569,408 @@ 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.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 1.0.109", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" + +[[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", + "wayland-sys 0.29.5", +] + +[[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", + "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", + "wayland-commons", + "wayland-scanner", +] + +[[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-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.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b03058f88386e5ff5310d9111d53f48b17d732b401aeb83a8d5190f2ac459338" +dependencies = [ + "rustls-webpki 0.100.1", +] + +[[package]] +name = "which" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" +dependencies = [ + "either", + "libc", + "once_cell", +] + +[[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-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[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.0", +] + +[[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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +dependencies = [ + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", +] + +[[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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + +[[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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + +[[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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + +[[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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + +[[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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + +[[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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + +[[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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" + +[[package]] +name = "winit" +version = "0.28.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "866db3f712fffba75d31bf0cdecf357c8aeafd158c5b7ab51dba2a2b2d47f196" +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", + "wayland-commons", + "wayland-protocols", + "wayland-scanner", + "web-sys", + "windows-sys 0.45.0", + "x11-dl", +] + +[[package]] +name = "winnow" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25b5872fa2e10bd067ae946f927e726d7d603eaeb6e02fa6a350e0722d2b8c11" +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 = "xattr" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d1526bbe5aaeb5eb06885f4d987bcdfa5e23187055de9b83fe00156a821fabc" +dependencies = [ + "libc", +] + +[[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.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3" + [[package]] name = "zeroize" version = "1.6.0" diff --git a/lokui/Cargo.toml b/lokui/Cargo.toml index 959dfc1..6b0c92d 100644 --- a/lokui/Cargo.toml +++ b/lokui/Cargo.toml @@ -6,3 +6,11 @@ version = "0.1.0" edition = "2021" [dependencies] +skia-safe = { version = "0.63.0", features = ["gl"] } + +[dev-dependencies] +gl = "0.14.0" +glutin = "0.30.9" +glutin-winit = "0.3.0" +raw-window-handle = "0.5.2" +winit = "0.28.6" diff --git a/lokui/examples/common/skia_window.rs b/lokui/examples/common/skia_window.rs new file mode 100644 index 0000000..4968cfb --- /dev/null +++ b/lokui/examples/common/skia_window.rs @@ -0,0 +1,198 @@ +use std::{error::Error, ffi::CString, num::NonZeroU32}; + +use gl::types::*; +use glutin::{ + config::{ConfigTemplateBuilder, GlConfig}, + context::{ + ContextApi, ContextAttributesBuilder, NotCurrentGlContextSurfaceAccessor, + PossiblyCurrentContext, + }, + display::{GetGlDisplay, GlDisplay}, + surface::{Surface as GlutinSurface, SurfaceAttributesBuilder, WindowSurface}, +}; +use glutin_winit::DisplayBuilder; +use raw_window_handle::HasRawWindowHandle; +use skia_safe::{ + gpu::{gl::FramebufferInfo, BackendRenderTarget, SurfaceOrigin}, + ColorType, Surface, +}; +use winit::{ + dpi::{PhysicalSize, Size}, + event_loop::EventLoop, + window::{Window, WindowBuilder}, +}; + +// Guarantee the drop order inside the FnMut closure. `Window` _must_ be dropped after +// `DirectContext`. +// +// https://github.com/rust-skia/rust-skia/issues/476 +pub struct SkiaWindowCtx { + pub fb_info: FramebufferInfo, + pub num_samples: usize, + pub stencil_size: usize, + pub surface: Surface, + pub gl_surface: GlutinSurface, + pub gr_context: skia_safe::gpu::DirectContext, + pub gl_context: PossiblyCurrentContext, + pub window: Window, + pub events: EventLoop<()>, +} + +pub fn create_skia_window( + title: &str, + width: u32, + height: u32, +) -> Result> { + let events = EventLoop::new(); + + let winit_window_builder = WindowBuilder::new() + .with_title(title) + .with_inner_size(Size::Physical(PhysicalSize::new(width, height))); + + let template = ConfigTemplateBuilder::new() + .with_alpha_size(8) + .with_transparency(true); + + let display_builder = DisplayBuilder::new().with_window_builder(Some(winit_window_builder)); + let (window, gl_config) = display_builder + .build(&events, template, |configs| { + // Find the config with the minimum number of samples. Usually Skia takes care of + // anti-aliasing and may not be able to create appropriate Surfaces for samples > 0. + // See https://github.com/rust-skia/rust-skia/issues/782 + // And https://github.com/rust-skia/rust-skia/issues/764 + configs + .reduce(|accum, config| { + let transparency_check = config.supports_transparency().unwrap_or(false) + & !accum.supports_transparency().unwrap_or(false); + + if transparency_check || config.num_samples() < accum.num_samples() { + config + } else { + accum + } + }) + .unwrap() + }) + .unwrap(); + + println!("Picked a config with {} samples", gl_config.num_samples()); + + let mut window = window.expect("Could not create window with OpenGL context"); + let raw_window_handle = window.raw_window_handle(); + + // The context creation part. It can be created before surface and that's how + // it's expected in multithreaded + multiwindow operation mode, since you + // can send NotCurrentContext, but not Surface. + let context_attributes = ContextAttributesBuilder::new().build(Some(raw_window_handle)); + + // Since glutin by default tries to create OpenGL core context, which may not be + // present we should try gles. + let fallback_context_attributes = ContextAttributesBuilder::new() + .with_context_api(ContextApi::Gles(None)) + .build(Some(raw_window_handle)); + + let not_current_gl_context = unsafe { + gl_config + .display() + .create_context(&gl_config, &context_attributes) + .unwrap_or_else(|_| { + gl_config + .display() + .create_context(&gl_config, &fallback_context_attributes) + .expect("failed to create context") + }) + }; + + let attrs = SurfaceAttributesBuilder::::new().build( + raw_window_handle, + NonZeroU32::new(width).unwrap(), + NonZeroU32::new(height).unwrap(), + ); + + let gl_surface = unsafe { + gl_config + .display() + .create_window_surface(&gl_config, &attrs) + .expect("Could not create gl window surface") + }; + + let gl_context = not_current_gl_context + .make_current(&gl_surface) + .expect("Could not make GL context current when setting up skia renderer"); + + gl::load_with(|s| { + gl_config + .display() + .get_proc_address(CString::new(s).unwrap().as_c_str()) + }); + + let interface = skia_safe::gpu::gl::Interface::new_load_with(|name| { + if name == "eglGetCurrentDisplay" { + return std::ptr::null(); + } + gl_config + .display() + .get_proc_address(CString::new(name).unwrap().as_c_str()) + }) + .expect("Could not create interface"); + + let mut gr_context = skia_safe::gpu::DirectContext::new_gl(Some(interface), None) + .expect("Could not create direct context"); + + let fb_info = { + let mut fboid: GLint = 0; + unsafe { gl::GetIntegerv(gl::FRAMEBUFFER_BINDING, &mut fboid) }; + + FramebufferInfo { + fboid: fboid.try_into().unwrap(), + format: skia_safe::gpu::gl::Format::RGBA8.into(), + } + }; + + let num_samples = gl_config.num_samples() as usize; + let stencil_size = gl_config.stencil_size() as usize; + + let surface = create_surface( + &mut window, + fb_info, + &mut gr_context, + num_samples, + stencil_size, + ); + + Ok(SkiaWindowCtx { + fb_info, + num_samples, + stencil_size, + surface, + gl_surface, + gr_context, + gl_context, + window, + events, + }) +} + +pub fn create_surface( + window: &mut Window, + fb_info: FramebufferInfo, + gr_context: &mut skia_safe::gpu::DirectContext, + num_samples: usize, + stencil_size: usize, +) -> Surface { + let size = window.inner_size(); + let size = (size.width as i32, size.height as i32); + + let backend_render_target = + BackendRenderTarget::new_gl(size, num_samples, stencil_size, fb_info); + + Surface::from_backend_render_target( + gr_context, + &backend_render_target, + SurfaceOrigin::BottomLeft, + ColorType::RGBA8888, + None, + None, + ) + .expect("Could not create skia surface") +} diff --git a/lokui/examples/counter.rs b/lokui/examples/counter.rs new file mode 100644 index 0000000..32ac5c5 --- /dev/null +++ b/lokui/examples/counter.rs @@ -0,0 +1,254 @@ +#![allow(clippy::unusual_byte_groupings)] + +use std::num::NonZeroU32; +use std::time::Duration; + +use glutin::surface::GlSurface; +use lokui::anim::ease; +use lokui::events::MousePosition; +use lokui::layout::SolvedLayout; +use lokui::prelude::*; + +use lokui::events::Event as LokuiEvent; +use winit::event::{ElementState, Event, MouseButton}; + +use lokui::state::Color; +use skia_safe::{Font, FontStyle, Typeface}; +use skia_window::{create_skia_window, SkiaWindowCtx}; +use winit::event::{KeyboardInput, VirtualKeyCode, WindowEvent}; + +use crate::skia_window::create_surface; + +#[path = "common/skia_window.rs"] +mod skia_window; + +/// Curried increment callback. +fn increment(value: Lazy) -> impl Fn(f32, f32) -> bool { + move |_, _| { + *value.get_mut() += 1; + println!("+1! Counter = {}", value.get()); + true + } +} + +/// Curried decrement callback. +fn decrement(value: Lazy) -> impl Fn(f32, f32) -> bool { + move |_, _| { + *value.get_mut() -= 1; + println!("-1! Counter = {}", value.get()); + true + } +} + +fn counter_button_color_handler(bg: Lazy) -> impl FnMut(LokuiEvent) -> bool { + /// wrapper struct to have a simple non-copy background color + struct BgColor(u32); + + let idle_color = bg.get_mut().color.current().argb_hex(); + + let mut bg_color = BgColor(idle_color); + move |event| { + bg_color.0 = match event { + LokuiEvent::MouseDown(_) => 0x3d3556, + LokuiEvent::MouseIn | LokuiEvent::MouseUp(_) => 0xaa95f0, + LokuiEvent::MouseOut => idle_color, + _ => bg_color.0, + }; + + let color = Color::from_hex(0xff_000000 | bg_color.0); + (bg.get_mut().color).go_to(color, ease::out_quint, Duration::from_millis(500)); + + false + } +} + +fn counter_button( + text: impl Widget + 'static, + on_click: impl FnMut(f32, f32) -> bool + 'static, +) -> impl Widget { + let background = lazy(RectState::new(0xff_000000 | 0x8460f0, 5., None)); + + pane() + .with_layout( + Layout::new() + .with_dimension(Fixed(80.), Fixed(50.)) + .with_origin(Anchor::CENTER) + .with_anchor(Anchor::CENTER), + ) + .child(text) + .bg(background.clone()) + .on_click(on_click) + .on_event(counter_button_color_handler(background)) +} + +fn counter() -> impl Widget { + let value = lazy(0); + + let typeface = Typeface::new("Roboto", FontStyle::normal()).unwrap(); + let font = lazy(Font::new(typeface, Some(16.))); + + pane() + .with_layout( + Layout::new() + .with_anchor(Anchor::CENTER) + .with_dimension(Fixed(400.), Fixed(250.)), + ) + .with_padding(Padding::splat(10.)) + .bg(lazy(RectState::new(0xff_232128, 10., None))) + .child( + pane() + .with_flex(Flex { + direction: Direction::Horizontal, + gap: 5., + }) + .with_layout(Layout::new().with_dimension(Fill, Fill)) + .with_padding(Padding::vh(5., 10.)) + .bg(lazy(RectState::new(0xff_2e2c35, 5., None))) + .child( + pane() + .with_layout( + Layout::new() + .with_dimension(Fill, Fixed(50.)) + .with_origin(Anchor::CENTER) + .with_anchor(Anchor::CENTER), + ) + .child(text(value.clone(), font.clone())) + .bg(lazy(RectState::new(0xff_232128, 5., None))), + ) + .child(counter_button( + text("+1", font.clone()), + increment(value.clone()), + )) + .child(counter_button(text("-1", font), decrement(value))), + ) +} + +struct RootWidgetTree { + root_widget: W, + root_layout: SolvedLayout, + window_layout: SolvedLayout, +} + +fn main() { + let win = create_skia_window("Lokui GUI Framework Prototype (Counter)", 1280, 720).unwrap(); + + let mut rwt = { + let mut root_widget = counter(); + let window_layout = SolvedLayout::from_top_left(0., 0., 1280., 720.); + let root_layout = root_widget.solve_layout(&window_layout); + + RootWidgetTree { + root_widget, + root_layout, + window_layout, + } + }; + + let mut x = 0; + let mut y = 0; + + let SkiaWindowCtx { + fb_info, + num_samples, + stencil_size, + mut surface, + gl_surface, + mut gr_context, + gl_context, + mut window, + events, + } = win; + + window.request_redraw(); + events.run(move |event, _, control_flow| { + let window = &mut window; + let surface = &mut surface; + let gr_context = &mut gr_context; + let gl_context = &gl_context; + + match event { + Event::LoopDestroyed => {} + Event::WindowEvent { event, .. } => match event { + WindowEvent::CloseRequested => { + println!("Closing..."); + control_flow.set_exit(); + } + WindowEvent::Resized(physical_size) => { + /* First resize the opengl drawable */ + let (width, height): (u32, u32) = physical_size.into(); + + rwt.window_layout = + SolvedLayout::from_top_left(0., 0., width as f32, height as f32); + rwt.root_layout = rwt.root_widget.solve_layout(&rwt.window_layout); + + *surface = create_surface( + window, + fb_info, + gr_context, + num_samples, + stencil_size, + ); + + gl_surface.resize( + gl_context, + NonZeroU32::new(width.max(1)).unwrap(), + NonZeroU32::new(height.max(1)).unwrap(), + ); + + window.request_redraw(); + control_flow.set_wait(); + } + WindowEvent::MouseInput { state, button, .. } => { + if button == MouseButton::Left { + let mouse_pos = MousePosition { + x: x as f32, + y: y as f32, + }; + + let event = match state { + ElementState::Pressed => LokuiEvent::MouseDown(mouse_pos), + ElementState::Released => LokuiEvent::MouseUp(mouse_pos), + }; + + rwt.root_widget.handle_event(event, &rwt.root_layout); + } + + control_flow.set_wait(); + } + WindowEvent::CursorMoved { position, .. } => { + x = position.x as u32; + y = position.y as u32; + + let event = LokuiEvent::MouseMove(MousePosition { + x: position.x as f32, + y: position.y as f32, + }); + rwt.root_widget.handle_event(event, &rwt.root_layout); + + control_flow.set_wait(); + } + WindowEvent::KeyboardInput { + input: + KeyboardInput { + virtual_keycode: Some(VirtualKeyCode::Q), + .. + }, + .. + } => control_flow.set_exit(), + _ => control_flow.set_wait(), + }, + Event::RedrawRequested(_) => { + let canvas = surface.canvas(); + canvas.clear(skia_safe::Color::from(0xff_161a1d)); + rwt.root_widget.draw(canvas, &rwt.root_layout); + + gr_context.flush_and_submit(); + gl_surface.swap_buffers(gl_context).unwrap(); + + window.request_redraw(); + control_flow.set_wait(); + } + _ => control_flow.set_wait(), + } + }); +} diff --git a/lokui/src/anim/ease.rs b/lokui/src/anim/ease.rs new file mode 100644 index 0000000..78d8098 --- /dev/null +++ b/lokui/src/anim/ease.rs @@ -0,0 +1,164 @@ +use std::f32::consts::PI; + +pub fn linear(t: f32) -> f32 { + t +} + +// sine + +pub fn in_sine(t: f32) -> f32 { + 1. - (t * PI / 2.).cos() +} + +pub fn out_sine(t: f32) -> f32 { + ((t * PI) / 2.).sin() +} + +pub fn in_out_sine(t: f32) -> f32 { + -((PI * t).cos() - 1.) / 2. +} + +// quad + +pub fn in_quad(t: f32) -> f32 { + t.powi(2) +} + +pub fn out_quad(t: f32) -> f32 { + 1. - (1. - t).powi(2) +} + +pub fn in_out_quad(t: f32) -> f32 { + if t < 0.5 { + 2. * t.powi(2) + } else { + 1. - (-2. * t + 2.).powi(2) / 2. + } +} + +// cubic + +pub fn in_cubic(t: f32) -> f32 { + t.powi(3) +} + +pub fn out_cubic(t: f32) -> f32 { + 1. - (1. - t).powi(3) +} + +pub fn in_out_cubic(t: f32) -> f32 { + if t < 0.5 { + 4. * t.powi(3) + } else { + 1. - (-2. * t + 2.).powi(3) / 2. + } +} + +// quart + +pub fn in_quart(t: f32) -> f32 { + t.powi(4) +} + +pub fn out_quart(t: f32) -> f32 { + 1. - (1. - t).powi(4) +} + +pub fn in_out_quart(t: f32) -> f32 { + if t < 0.5 { + 8. * t.powi(4) + } else { + 1. - (-2. * t + 2.).powi(4) / 2. + } +} + +// quint + +pub fn in_quint(t: f32) -> f32 { + t.powi(5) +} + +pub fn out_quint(t: f32) -> f32 { + 1. - (1. - t).powi(5) +} + +pub fn in_out_quint(t: f32) -> f32 { + if t < 0.5 { + 16. * t.powi(5) + } else { + 1. - (-2. * t + 2.).powi(5) / 2. + } +} + +// expo + +pub fn in_expo(t: f32) -> f32 { + if t == 0. { + 0. + } else { + 2_f32.powf(10. * t - 10.) + } +} + +pub fn out_expo(t: f32) -> f32 { + if t == 1. { + 1. + } else { + 1. - 2_f32.powf(-10. * t) + } +} + +pub fn in_out_expo(t: f32) -> f32 { + if t == 0. { + 0. + } else if t == 1. { + 1. + } else if t < 0.5 { + 2_f32.powf(20. * t - 10.) / 2. + } else { + (2. - 2_f32.powf(-20. * t + 10.)) / 2. + } +} + +// circ + +pub fn in_circ(t: f32) -> f32 { + 1. - (1. - t.powi(2)).sqrt() +} + +pub fn out_circ(t: f32) -> f32 { + (1. - (t - 1.).powi(2)).sqrt() +} + +pub fn in_out_circ(t: f32) -> f32 { + if t < 0.5 { + (1. - (1. - (2. * t).powi(2)).sqrt()) / 2. + } else { + ((1. - (-2. * t + 2.).powi(2)).sqrt() + 1.) / 2. + } +} + +// back + +pub fn in_back(t: f32) -> f32 { + let c1 = 1.70158; + let c3 = c1 + 1.; + c3 * t.powi(3) - c1 * t.powi(2) +} + +pub fn out_back(t: f32) -> f32 { + let c1 = 1.70158; + let c3 = c1 + 1.; + 1. + c3 * (t - 1.).powi(3) + c1 * (t - 1.).powi(2) +} + +pub fn in_out_back(x: f32) -> f32 { + let c1 = 1.70158; + let c2 = c1 * 1.525; + + if x < 0.5 { + ((2. * x).powi(2) * ((c2 + 1.) * 2. * x - c2)) / 2. + } else { + ((2. * x - 2.).powi(2) * ((c2 + 1.) * (x * 2. - 2.) + c2) + 2.) / 2. + } +} diff --git a/lokui/src/anim/mod.rs b/lokui/src/anim/mod.rs new file mode 100644 index 0000000..403410c --- /dev/null +++ b/lokui/src/anim/mod.rs @@ -0,0 +1,111 @@ +use std::fmt::Debug; +use std::ops::{Add, Mul, Sub}; +use std::time::{Duration, Instant}; + +pub mod ease; + +impl + Sub + Mul + Copy> Interpolate for I {} +pub trait Interpolate: + Add + Sub + Mul + Copy +{ +} + +pub fn lerp(t: f32, start: I, end: I) -> I { + start + (end - start) * t +} + +pub fn interp(ease_fn: fn(f32) -> f32, t: f32, start: I, end: I) -> I { + lerp(ease_fn(t), start, end) +} + +#[derive(Clone)] +pub enum Property { + Static { + value: T, + }, + Anim { + prev: T, + next: T, + start: Instant, + ease_fn: fn(f32) -> f32, + duration: Duration, + }, +} + +impl Property { + pub fn new(value: T) -> Self { + Self::Static { value } + } + + pub fn go_to(&mut self, next: T, ease_fn: fn(f32) -> f32, duration: Duration) { + let prev = self.current(); + let start = Instant::now(); + *self = Self::Anim { + prev, + next, + start, + ease_fn, + duration, + }; + } + + pub fn set(&mut self, value: T) { + *self = Self::Static { value }; + } + + pub fn current(&mut self) -> T { + match self { + Self::Static { value } => *value, + Self::Anim { + prev, + next, + start, + ease_fn, + duration, + } => { + let t = (start.elapsed().as_secs_f32() / duration.as_secs_f32()).clamp(0., 1.); + let value = interp(*ease_fn, t, *prev, *next); + if t == 1. { + // make static + self.set(value); + } + value + } + } + } + + pub fn freeze(&mut self) { + if self.is_anim() { + let value = self.current(); + self.set(value); + } + } + + pub fn is_static(&self) -> bool { + matches!(self, Self::Static { .. }) + } + + pub fn is_anim(&self) -> bool { + matches!(self, Self::Anim { .. }) + } +} + +impl Debug for Property { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Static { value } => write!(f, "static ({value:?})"), + Self::Anim { + prev, + next, + duration, + .. + } => { + write!( + f, + "anim [{}ms] ({prev:?} -> {next:?})", + duration.as_millis() + ) + } + } + } +} diff --git a/lokui/src/components/mod.rs b/lokui/src/components/mod.rs new file mode 100644 index 0000000..0ed3728 --- /dev/null +++ b/lokui/src/components/mod.rs @@ -0,0 +1,56 @@ +use crate::events::Event; +use crate::state::{Lazy, RectState}; +use crate::widget::Widget; + +use self::wrappers::*; + +pub mod pane; +pub mod text; +pub mod wrappers; + +pub trait WidgetExt: Widget { + fn bg(self, bg: Lazy) -> WithBg + where + Self: Sized; + + fn on_click(self, callback: impl FnMut(f32, f32) -> bool + 'static) -> WithOnClick + where + Self: Sized; + + fn on_event(self, callback: impl FnMut(Event) -> bool + 'static) -> WithOnEvent + where + Self: Sized; +} + +impl WidgetExt for T { + fn bg(self, state: Lazy) -> WithBg + where + Self: Sized, + { + WithBg { + widget: self, + state, + } + } + + fn on_click(self, callback: impl FnMut(f32, f32) -> bool + 'static) -> WithOnClick + where + Self: Sized, + { + WithOnClick { + widget: self, + on_click: Box::new(callback), + is_mouse_down: false, + } + } + + fn on_event(self, callback: impl FnMut(Event) -> bool + 'static) -> WithOnEvent + where + Self: Sized, + { + WithOnEvent { + widget: self, + callback: Box::new(callback), + } + } +} diff --git a/lokui/src/components/pane.rs b/lokui/src/components/pane.rs new file mode 100644 index 0000000..cf4d98b --- /dev/null +++ b/lokui/src/components/pane.rs @@ -0,0 +1,248 @@ +use std::io; + +use skia_safe::Canvas; + +use crate::events::{Event, MousePosition}; +use crate::indentation; +use crate::layout::{DimScalar, Direction, Flex, Layout, SolvedLayout, Padding}; +use crate::widget::{default_solve_layout, solve_height, solve_width, Widget, WidgetContainer}; + +struct PaneChild { + widget: Box, + solved_layout: SolvedLayout, + is_hovered: bool, +} + +impl PaneChild { + fn new(widget: Box) -> Self { + Self { + widget, + solved_layout: SolvedLayout::default(), + is_hovered: false, + } + } +} + +#[derive(Default)] +pub struct Pane { + layout: Layout, + padding: Padding, + flex: Option, + children: Vec, +} + +pub fn pane() -> Pane { + Pane::default() +} + +impl Pane { + pub fn with_layout(mut self, layout: Layout) -> Self { + self.layout = layout; + self + } + + pub fn with_padding(mut self, padding: Padding) -> Self { + self.padding = padding; + self + } + + pub fn with_flex(mut self, flex: Flex) -> Self { + self.flex = Some(flex); + self + } +} + +impl WidgetContainer for Pane { + fn add_dyn_child(&mut self, widget: Box) { + self.children.push(PaneChild::new(widget)); + } + + fn pop_child(&mut self) -> Option> { + self.children.pop().map(|child| child.widget) + } +} + +impl Widget for Pane { + fn layout(&self) -> &Layout { + &self.layout + } + + fn solve_layout(&mut self, parent_layout: &SolvedLayout) -> SolvedLayout { + let layout = default_solve_layout(self, parent_layout); + + let inner_layout = layout.padded(self.padding); + if let Some(flex) = &self.flex { + solve_flex_layout(flex, &mut self.children, inner_layout); + } else { + // Without flex-layout, all children are superposed to each other. + + for child in &mut self.children { + child.solved_layout = child.widget.solve_layout(&inner_layout); + } + } + + layout + } + + fn min_width(&self) -> f32 { + let width_pad = self.padding.left + self.padding.right; + + if let Some(flex) = self.flex.as_ref() { + if flex.direction == Direction::Horizontal { + let inner_min_width: f32 = (self.children.iter()) + .map(|child| match child.widget.layout().width { + DimScalar::Fixed(w) => w, + _ => child.widget.min_width(), + }) + .sum(); + + return inner_min_width + width_pad; + } + } + + let inner_min_width = (self.children.iter()) + .map(|child| child.widget.min_width()) + .max_by(|x, y| x.total_cmp(y)) + .unwrap_or_default(); + + inner_min_width + width_pad + } + + fn min_height(&self) -> f32 { + let height_pad = self.padding.top + self.padding.bottom; + + if let Some(flex) = self.flex.as_ref() { + if flex.direction == Direction::Vertical { + let inner_min_height: f32 = (self.children.iter()) + .map(|child| match child.widget.layout().height { + DimScalar::Fixed(h) => h, + _ => child.widget.min_height(), + }) + .sum(); + + return inner_min_height + height_pad; + } + } + + let inner_min_height = (self.children.iter()) + .map(|child| child.widget.min_height()) + .max_by(|x, y| x.total_cmp(y)) + .unwrap_or_default(); + + inner_min_height + height_pad + } + + fn debug(&self, w: &mut dyn io::Write, deepness: usize) -> io::Result<()> { + writeln!(w, "{}", indentation(deepness))?; + for child in &self.children { + child.widget.debug(w, deepness + 1)?; + } + writeln!(w, "{}", indentation(deepness)) + } + + fn draw(&self, canvas: &mut Canvas, _layout: &SolvedLayout) { + for child in &self.children { + child.widget.draw(canvas, &child.solved_layout); + } + } + + fn handle_event(&mut self, event: Event, _layout: &SolvedLayout) -> bool { + match event { + Event::MouseDown(MousePosition { x, y }) | Event::MouseUp(MousePosition { x, y }) => { + for child in &mut self.children { + if !child.solved_layout.contains(x, y) { + continue; + } + + child.widget.handle_event(event, &child.solved_layout); + } + } + Event::MouseMove(MousePosition { x, y }) => { + for child in &mut self.children { + if child.solved_layout.contains(x, y) { + if !child.is_hovered { + child.is_hovered = true; + (child.widget).handle_event(Event::MouseIn, &child.solved_layout); + } + child.widget.handle_event(event, &child.solved_layout); + } else if child.is_hovered { + child.is_hovered = false; + (child.widget).handle_event(Event::MouseOut, &child.solved_layout); + } + } + } + _ => (), + } + + true + } +} + +/// Solves a pane's children's solved layouts with a flex layout. +/// +/// With a flex layout, all children are placed next to each other, vertically or horizontally. +fn solve_flex_layout( + flex: &Flex, + children: &mut [PaneChild], + inner_layout: SolvedLayout, +) { + match flex.direction { + Direction::Horizontal => { + let fills_count = (children.iter()) + .filter(|child| child.widget.layout().width.is_fill()) + .count(); + + let filling_width = if fills_count == 0 { + 0. + } else { + let fixed_width: f32 = (children.iter()) + .filter_map(|child| solve_width(child.widget.as_ref())) + .sum(); + + let gap_width = flex.gap * children.len().saturating_sub(1) as f32; + let leftover_width = (inner_layout.width() - fixed_width - gap_width).max(0.); + leftover_width / fills_count as f32 + }; + + let mut x = inner_layout.x_start(); + for child in children.iter_mut() { + // Each child is given a slice of the inner layout. + + let child_width = solve_width(child.widget.as_ref()).unwrap_or(filling_width); + let inner_layout = inner_layout.with_width(child_width).with_x(x); + child.solved_layout = child.widget.solve_layout(&inner_layout); + + x += child_width + flex.gap; + } + } + Direction::Vertical => { + // maybe put this into a function since it's + // copy-pasted from the Horizontal case but for height? + + let fills_count = (children.iter()) + .filter(|child| child.widget.layout().height.is_fill()) + .count(); + + let filling_height = if fills_count == 0 { + 0. + } else { + let fixed_height: f32 = (children.iter()) + .filter_map(|child| solve_height(child.widget.as_ref())) + .sum(); + + let gap_width = flex.gap * children.len().saturating_sub(1) as f32; + let leftover_height = (inner_layout.height() - fixed_height - gap_width).max(0.); + leftover_height / fills_count as f32 + }; + + let mut y = inner_layout.y_start(); + for child in children.iter_mut() { + let child_height = solve_height(child.widget.as_ref()).unwrap_or(filling_height); + let inner_layout = inner_layout.with_height(child_height).with_y(y); + child.solved_layout = child.widget.solve_layout(&inner_layout); + + y += child_height + flex.gap; + } + } + } +} diff --git a/lokui/src/components/text.rs b/lokui/src/components/text.rs new file mode 100644 index 0000000..b3bac7b --- /dev/null +++ b/lokui/src/components/text.rs @@ -0,0 +1,82 @@ +use std::fmt::Display; +use std::io; + +use skia_safe::{Canvas, Color, Font, Paint, Rect}; + +use crate::events::Event; +use crate::indentation; +use crate::layout::{Anchor, Layout, SolvedLayout}; +use crate::state::Lazy; +use crate::widget::{default_solve_layout, Widget}; + +pub struct Text { + layout: Layout, + font: Lazy, + text: T, +} + +pub fn text(text: T, font: Lazy) -> Text { + Text { + layout: Layout::hug(), + font, + text, + } +} + +impl Text { + pub fn with_layout(mut self, layout: Layout) -> Self { + self.layout = layout; + self + } + + pub fn text(&self) -> &T { + &self.text + } + + pub fn min_bounds(&self) -> Rect { + (self.font.get()) + .measure_str(format!("{}", &self.text), None) + .1 + } +} + +impl Widget for Text { + fn layout(&self) -> &Layout { + &self.layout + } + + fn solve_layout(&mut self, parent_layout: &SolvedLayout) -> SolvedLayout { + default_solve_layout(self, parent_layout) + } + + fn min_width(&self) -> f32 { + self.min_bounds().width() + } + + fn min_height(&self) -> f32 { + self.min_bounds().height() + } + + fn debug(&self, w: &mut dyn io::Write, deepness: usize) -> io::Result<()> { + writeln!(w, "{}{}", indentation(deepness), &self.text) + } + + fn draw(&self, canvas: &mut Canvas, layout: &SolvedLayout) { + let mut paint = Paint::default(); + paint.set_anti_alias(true); + paint.set_color(Color::from(0xff_ffffff)); + + let (x, y) = layout.point_at_anchor(Anchor::TOP_LEFT); + + canvas.draw_str( + format!("{}", &self.text), + (x, y + self.min_bounds().height()), + self.font.get().as_ref(), + &paint, + ); + } + + fn handle_event(&mut self, _event: Event, _layout: &SolvedLayout) -> bool { + false + } +} diff --git a/lokui/src/components/wrappers.rs b/lokui/src/components/wrappers.rs new file mode 100644 index 0000000..49b0720 --- /dev/null +++ b/lokui/src/components/wrappers.rs @@ -0,0 +1,205 @@ +use std::ops::{Deref, DerefMut}; + +use skia_safe::{Canvas, Paint, RRect, Rect}; + +use crate::events::{Event, MousePosition}; +use crate::layout::{Layout, SolvedLayout}; +use crate::state::{Lazy, RectState}; +use crate::widget::Widget; + +// bg + +pub struct WithBg { + pub(super) widget: W, + pub(super) state: Lazy, +} + +impl Deref for WithBg { + type Target = W; + + fn deref(&self) -> &Self::Target { + &self.widget + } +} + +impl DerefMut for WithBg { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.widget + } +} + +impl Widget for WithBg { + fn layout(&self) -> &Layout { + self.widget.layout() + } + + fn solve_layout(&mut self, parent_layout: &SolvedLayout) -> SolvedLayout { + self.widget.solve_layout(parent_layout) + } + + fn min_width(&self) -> f32 { + self.widget.min_width() + } + + fn min_height(&self) -> f32 { + self.widget.min_height() + } + + fn draw(&self, canvas: &mut Canvas, layout: &SolvedLayout) { + let rect = Rect::from_xywh( + layout.x_start(), + layout.y_start(), + layout.width(), + layout.height(), + ); + + let mut state = self.state.get_mut(); + + let radius = state.border_radius.current(); + let rect = RRect::new_rect_xy(rect, radius, radius); + + let mut paint = Paint::default(); + paint.set_anti_alias(true); + + paint.set_stroke(false); + paint.set_color(state.color.current().into_skia()); + canvas.draw_rrect(rect, &paint); + + if let Some((color, width)) = &mut state.stroke { + paint.set_stroke(true); + paint.set_stroke_width(width.current()); + paint.set_color(color.current().into_skia()); + canvas.draw_rrect(rect, &paint); + } + + self.widget.draw(canvas, layout); + } + + fn handle_event(&mut self, event: Event, layout: &SolvedLayout) -> bool { + self.widget.handle_event(event, layout) + } +} + +// onclick + +pub struct WithOnClick { + pub(super) widget: W, + pub(super) on_click: Box bool>, + pub(super) is_mouse_down: bool, +} + +impl Deref for WithOnClick { + type Target = W; + + fn deref(&self) -> &Self::Target { + &self.widget + } +} + +impl DerefMut for WithOnClick { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.widget + } +} + +impl Widget for WithOnClick { + fn layout(&self) -> &Layout { + self.widget.layout() + } + + fn solve_layout(&mut self, parent_layout: &SolvedLayout) -> SolvedLayout { + self.widget.solve_layout(parent_layout) + } + + fn min_width(&self) -> f32 { + self.widget.min_width() + } + + fn min_height(&self) -> f32 { + self.widget.min_height() + } + + fn draw(&self, canvas: &mut Canvas, layout: &SolvedLayout) { + self.widget.draw(canvas, layout); + } + + fn handle_event(&mut self, event: Event, layout: &SolvedLayout) -> bool { + let handled = match event { + Event::MouseDown(_) => { + self.is_mouse_down = true; + false + } + Event::MouseUp(MousePosition { x, y }) => { + if self.is_mouse_down { + self.is_mouse_down = false; + (self.on_click)(x, y); + true + } else { + false + } + } + Event::MouseOut => { + self.is_mouse_down = false; + false + }, + _ => false, + }; + + if !handled { + self.widget.handle_event(event, layout) + } else { + true + } + } +} + +// onevent + +pub struct WithOnEvent { + pub(super) widget: W, + pub(super) callback: Box bool>, +} + +impl Deref for WithOnEvent { + type Target = W; + + fn deref(&self) -> &Self::Target { + &self.widget + } +} + +impl DerefMut for WithOnEvent { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.widget + } +} + +impl Widget for WithOnEvent { + fn layout(&self) -> &Layout { + self.widget.layout() + } + + fn solve_layout(&mut self, parent_layout: &SolvedLayout) -> SolvedLayout { + self.widget.solve_layout(parent_layout) + } + + fn min_width(&self) -> f32 { + self.widget.min_width() + } + + fn min_height(&self) -> f32 { + self.widget.min_height() + } + + fn draw(&self, canvas: &mut Canvas, layout: &SolvedLayout) { + self.widget.draw(canvas, layout); + } + + fn handle_event(&mut self, event: Event, layout: &SolvedLayout) -> bool { + if !(self.callback)(event) { + return self.widget.handle_event(event, layout); + } + + false + } +} diff --git a/lokui/src/events.rs b/lokui/src/events.rs new file mode 100644 index 0000000..f39fe67 --- /dev/null +++ b/lokui/src/events.rs @@ -0,0 +1,14 @@ +#[derive(Clone, Copy, Debug)] +pub struct MousePosition { + pub x: f32, + pub y: f32, +} + +#[derive(Clone, Copy, Debug)] +pub enum Event { + MouseDown(MousePosition), + MouseUp(MousePosition), + MouseMove(MousePosition), + MouseIn, + MouseOut, +} diff --git a/lokui/src/layout/anchor.rs b/lokui/src/layout/anchor.rs new file mode 100644 index 0000000..5f3379d --- /dev/null +++ b/lokui/src/layout/anchor.rs @@ -0,0 +1,46 @@ +use super::SolvedLayout; + +#[derive(Clone, Copy, Debug)] +pub struct Anchor { + pub x: f32, + pub y: f32, +} + +impl Anchor { + pub const fn new(x: f32, y: f32) -> Self { + Self { x, y } + } + + pub const TOP_LEFT: Anchor = Anchor::new(0.0, 0.0); + pub const TOP_CENTER: Anchor = Anchor::new(0.5, 0.0); + pub const TOP_RIGHT: Anchor = Anchor::new(1.0, 0.0); + pub const CENTER_LEFT: Anchor = Anchor::new(0.0, 0.5); + pub const CENTER: Anchor = Anchor::new(0.5, 0.5); + pub const CENTER_RIGHT: Anchor = Anchor::new(1.0, 0.5); + pub const BOTTOM_LEFT: Anchor = Anchor::new(0.0, 1.0); + pub const BOTTOM_CENTER: Anchor = Anchor::new(0.5, 1.0); + pub const BOTTOM_RIGHT: Anchor = Anchor::new(1.0, 1.0); + + pub fn calc_child_abs_pos( + &self, + width: f32, + height: f32, + parent_layout: &SolvedLayout, + ) -> SolvedLayout { + let x_offset = (parent_layout.width() - width) * self.x; + let y_offset = (parent_layout.height() - height) * self.y; + + SolvedLayout { + x: parent_layout.x + x_offset, + y: parent_layout.y + y_offset, + width, + height, + } + } +} + +impl Default for Anchor { + fn default() -> Self { + Self::CENTER + } +} diff --git a/lokui/src/layout/mod.rs b/lokui/src/layout/mod.rs new file mode 100644 index 0000000..1a4687c --- /dev/null +++ b/lokui/src/layout/mod.rs @@ -0,0 +1,223 @@ +pub use anchor::*; +pub use padding::*; + +pub mod anchor; +pub mod padding; + +/// Scalar value used to represent static and dynamic widths and heights. +#[derive(Clone, Copy, Debug, Default)] +pub enum DimScalar { + /// The widget fills its parent on that dimension. + #[default] + Fill, + /// The widget hugs its internal content on that dimension. + Hug, + /// The dimension is fixed by that amount of pixels. + Fixed(f32), +} + +impl DimScalar { + pub fn is_fill(&self) -> bool { + matches!(self, Self::Fill) + } + pub fn is_hug(&self) -> bool { + matches!(self, Self::Hug) + } + pub fn is_fixed(&self) -> bool { + matches!(self, Self::Fixed(_)) + } +} + +#[derive(Clone, Debug, Default)] +pub struct Layout { + /// Position offset in pixels on the `x` axis. + pub x: f32, + /// Position offset in pixels on the `y` axis. + pub y: f32, + /// Width of the widget box. + pub width: DimScalar, + /// Height of the widget box. + pub height: DimScalar, + /// Point where the widget is placed relative to its parent. + pub anchor: Anchor, + /// Point of origin of the widget relative to its own box. + pub origin: Anchor, +} + +impl Layout { + pub fn new() -> Self { + Self::default() + } + + pub fn hug() -> Self { + Self::new().with_dimension(DimScalar::Hug, DimScalar::Hug) + } + + pub fn with_pos(mut self, x: f32, y: f32) -> Self { + self.x = x; + self.y = y; + self + } + + pub fn with_dimension(mut self, width: DimScalar, height: DimScalar) -> Self { + self.width = width; + self.height = height; + self + } + + pub fn with_anchor(mut self, anchor: Anchor) -> Self { + self.anchor = anchor; + self + } + + pub fn with_origin(mut self, origin: Anchor) -> Self { + self.origin = origin; + self + } + + pub fn position(&self) -> (f32, f32) { + (self.x, self.y) + } + + pub fn dimension(&self) -> (DimScalar, DimScalar) { + (self.width, self.height) + } +} + +/// State returned by a widget that solved its layout geometry. +#[derive(Clone, Copy, Debug, Default)] +pub struct SolvedLayout { + /// Absolute X coordinate of the concrete widget box from the top-level corner. + x: f32, + /// Absolute Y coordinate of the concrete widget box from the top-level corner. + y: f32, + /// Width of the concrete widget box. + width: f32, + /// Height of the concrete widget box. + height: f32, +} + +impl SolvedLayout { + pub fn from_top_left(x: f32, y: f32, width: f32, height: f32) -> Self { + Self { + x, + y, + width, + height, + } + } + + pub fn from_origin(origin: Anchor, x: f32, y: f32, width: f32, height: f32) -> Self { + Self::from_top_left(x, y, width, height).anchored(origin) + } + + pub fn from_2_points(xa: f32, ya: f32, xb: f32, yb: f32) -> Self { + Self { + x: xa.min(xb), + y: ya.min(yb), + width: (xb - xa).abs(), + height: (yb - ya).abs(), + } + } + + pub fn x_at_anchor(&self, anchor: Anchor) -> f32 { + self.x + self.width * anchor.x + } + + pub fn y_at_anchor(&self, anchor: Anchor) -> f32 { + self.y + self.height * anchor.y + } + + pub fn point_at_anchor(&self, anchor: Anchor) -> (f32, f32) { + (self.x_at_anchor(anchor), self.y_at_anchor(anchor)) + } + + pub fn x_start(&self) -> f32 { + self.x + } + + pub fn y_start(&self) -> f32 { + self.y + } + + pub fn x_end(&self) -> f32 { + self.x + self.width + } + + pub fn y_end(&self) -> f32 { + self.y + self.height + } + + pub fn width(&self) -> f32 { + self.width + } + + pub fn height(&self) -> f32 { + self.height + } + + pub fn contains_x(&self, x: f32) -> bool { + x >= self.x && x <= self.x + self.width + } + + pub fn contains_y(&self, y: f32) -> bool { + y >= self.y && y <= self.y + self.height + } + + pub fn contains(&self, x: f32, y: f32) -> bool { + self.contains_x(x) && self.contains_y(y) + } + + pub fn padded(mut self, padding: Padding) -> Self { + self.x += padding.left; + self.y += padding.top; + self.width -= padding.left + padding.right; + self.height -= padding.top + padding.bottom; + self + } + + pub fn anchored(mut self, anchor: Anchor) -> Self { + self.x -= self.width * anchor.x; + self.y -= self.height * anchor.y; + self + } + + pub fn with_dimensions(mut self, width: f32, height: f32) -> Self { + self.width = width; + self.height = height; + self + } + + pub fn with_width(mut self, width: f32) -> Self { + self.width = width; + self + } + + pub fn with_height(mut self, height: f32) -> Self { + self.height = height; + self + } + + pub fn with_x(mut self, x: f32) -> Self { + self.x = x; + self + } + + pub fn with_y(mut self, y: f32) -> Self { + self.y = y; + self + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)] +pub enum Direction { + #[default] + Horizontal, + Vertical, +} + +#[derive(Clone, Debug, Default)] +pub struct Flex { + pub direction: Direction, + pub gap: f32, +} diff --git a/lokui/src/layout/padding.rs b/lokui/src/layout/padding.rs new file mode 100644 index 0000000..9fb6039 --- /dev/null +++ b/lokui/src/layout/padding.rs @@ -0,0 +1,154 @@ +use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign}; + +#[derive(Clone, Copy, Debug, Default)] +pub struct Padding { + pub top: f32, + pub right: f32, + pub bottom: f32, + pub left: f32, +} + +impl Padding { + pub fn trbl(top: f32, right: f32, bottom: f32, left: f32) -> Self { + Self { + top, + right, + bottom, + left, + } + } + + pub fn vh(vertical: f32, horizontal: f32) -> Self { + Self { + top: vertical, + right: horizontal, + bottom: vertical, + left: horizontal, + } + } + + pub fn splat(val: f32) -> Self { + Self { + top: val, + right: val, + bottom: val, + left: val, + } + } +} + +// add + +impl Add for Padding { + type Output = Self; + + fn add(mut self, rhs: Self) -> Self::Output { + self += rhs; + self + } +} + +impl Add for Padding { + type Output = Self; + + fn add(mut self, rhs: f32) -> Self::Output { + self += rhs; + self + } +} + +impl AddAssign for Padding { + fn add_assign(&mut self, rhs: Self) { + self.top += rhs.top; + self.right += rhs.right; + self.bottom += rhs.bottom; + self.left += rhs.left; + } +} + +impl AddAssign for Padding { + fn add_assign(&mut self, rhs: f32) { + self.top += rhs; + self.right += rhs; + self.bottom += rhs; + self.left += rhs; + } +} + +// sub + +impl Sub for Padding { + type Output = Self; + + fn sub(mut self, rhs: Self) -> Self::Output { + self -= rhs; + self + } +} + +impl Sub for Padding { + type Output = Self; + + fn sub(mut self, rhs: f32) -> Self::Output { + self -= rhs; + self + } +} + +impl SubAssign for Padding { + fn sub_assign(&mut self, rhs: Self) { + self.top -= rhs.top; + self.right -= rhs.right; + self.bottom -= rhs.bottom; + self.left -= rhs.left; + } +} + +impl SubAssign for Padding { + fn sub_assign(&mut self, rhs: f32) { + self.top -= rhs; + self.right -= rhs; + self.bottom -= rhs; + self.left -= rhs; + } +} + +// mul + +impl Mul for Padding { + type Output = Self; + + fn mul(mut self, rhs: f32) -> Self::Output { + self *= rhs; + self + } +} + +impl MulAssign for Padding { + fn mul_assign(&mut self, rhs: f32) { + self.top *= rhs; + self.right *= rhs; + self.bottom *= rhs; + self.left *= rhs; + } +} + +// div + +impl Div for Padding { + type Output = Self; + + fn div(mut self, rhs: f32) -> Self::Output { + self /= rhs; + self + } +} + +impl DivAssign for Padding { + fn div_assign(&mut self, rhs: f32) { + self.top /= rhs; + self.right /= rhs; + self.bottom /= rhs; + self.left /= rhs; + } +} diff --git a/lokui/src/lib.rs b/lokui/src/lib.rs index 06d268d..f731597 100644 --- a/lokui/src/lib.rs +++ b/lokui/src/lib.rs @@ -1,14 +1,26 @@ -pub fn add(left: usize, right: usize) -> usize { - left + right -} +#![allow(clippy::unusual_byte_groupings)] + +pub mod anim; +pub mod components; +pub mod events; +pub mod layout; +pub mod state; +pub mod widget; + +pub mod prelude { + pub use crate::components::WidgetExt; -#[cfg(test)] -mod tests { - use super::*; + pub use crate::components::pane::pane; + pub use crate::components::text::text; + + pub use crate::layout::anchor::Anchor; + pub use crate::layout::padding::Padding; + pub use crate::layout::DimScalar::*; + pub use crate::layout::{Direction, Flex, Layout}; + pub use crate::state::{lazy, Lazy, RectState}; + pub use crate::widget::{Widget, WidgetContainer}; +} - #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); - } +pub fn indentation(n: usize) -> String { + " ".repeat(n) } diff --git a/lokui/src/state.rs b/lokui/src/state.rs new file mode 100644 index 0000000..db8b465 --- /dev/null +++ b/lokui/src/state.rs @@ -0,0 +1,162 @@ +use std::cell::{Ref, RefCell, RefMut}; +use std::fmt::{self, Debug}; +use std::ops::{Add, Mul, Sub}; +use std::rc::Rc; + +use crate::anim::Property; + +pub struct Lazy(Rc>); + +pub fn lazy(val: T) -> Lazy { + Lazy::new(val) +} + +impl Lazy { + pub fn new(val: T) -> Self { + Lazy(Rc::new(RefCell::new(val))) + } + + pub fn get(&self) -> Ref { + (*self.0).borrow() + } + + pub fn get_mut(&self) -> RefMut { + (*self.0).borrow_mut() + } +} + +impl Clone for Lazy { + fn clone(&self) -> Self { + Self(Rc::clone(&self.0)) + } +} + +impl fmt::Display for Lazy { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.get().fmt(f) + } +} + +#[derive(Clone, Copy)] +pub struct Color { + a: f32, + r: f32, + g: f32, + b: f32, +} + +impl Color { + pub fn from_hex(hex: u32) -> Self { + let a = ((hex >> 24) & 0xff) as u8; + let r = ((hex >> 16) & 0xff) as u8; + let g = ((hex >> 8) & 0xff) as u8; + let b = (hex & 0xff) as u8; + Self::from_argb(a, r, g, b) + } + + pub fn from_argb(a: u8, r: u8, g: u8, b: u8) -> Self { + Self { + a: a as f32 / 255., + r: r as f32 / 255., + g: g as f32 / 255., + b: b as f32 / 255., + } + } + + pub fn argb_f32(&self) -> (f32, f32, f32, f32) { + ( + (self.a * 255.).clamp(0., 255.).round(), + (self.r * 255.).clamp(0., 255.).round(), + (self.g * 255.).clamp(0., 255.).round(), + (self.b * 255.).clamp(0., 255.).round(), + ) + } + + pub fn argb(&self) -> (u8, u8, u8, u8) { + let (a, r, g, b) = self.argb_f32(); + (a as u8, r as u8, g as u8, b as u8) + } + + pub fn argb_hex(&self) -> u32 { + let (a, r, g, b) = self.argb(); + let a = (a as u32) << 24; + let r = (r as u32) << 16; + let g = (g as u32) << 8; + let b = b as u32; + a | r | g | b + } + + pub fn rgb_i32(&self) -> (i32, i32, i32, i32) { + let (a, r, g, b) = self.argb_f32(); + (a as i32, r as i32, g as i32, b as i32) + } + + pub fn into_skia(self) -> skia_safe::Color { + let (a, r, g, b) = self.argb(); + skia_safe::Color::from_argb(a, r, g, b) + } +} + +impl Debug for Color { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.rgb_i32().fmt(f) + } +} + +impl Add for Color { + type Output = Self; + + fn add(mut self, rhs: Self) -> Self::Output { + self.a += rhs.a; + self.r += rhs.r; + self.g += rhs.g; + self.b += rhs.b; + self + } +} + +impl Sub for Color { + type Output = Self; + + fn sub(mut self, rhs: Self) -> Self::Output { + self.a -= rhs.a; + self.r -= rhs.r; + self.g -= rhs.g; + self.b -= rhs.b; + self + } +} + +impl Mul for Color { + type Output = Self; + + fn mul(mut self, rhs: f32) -> Self::Output { + self.a *= rhs; + self.r *= rhs; + self.g *= rhs; + self.b *= rhs; + self + } +} + +impl From for Color { + fn from(value: u32) -> Self { + Self::from_hex(value) + } +} + +pub struct RectState { + pub color: Property, + pub border_radius: Property, + pub stroke: Option<(Property, Property)>, +} + +impl RectState { + pub fn new(color: impl Into, border_radius: f32, stroke: Option<(Color, f32)>) -> Self { + Self { + color: Property::new(color.into()), + border_radius: Property::new(border_radius), + stroke: stroke.map(|(c, w)| (Property::new(c), Property::new(w))), + } + } +} diff --git a/lokui/src/widget.rs b/lokui/src/widget.rs new file mode 100644 index 0000000..c1aaa5e --- /dev/null +++ b/lokui/src/widget.rs @@ -0,0 +1,92 @@ +use std::io; +use std::ops::DerefMut; + +use skia_safe::Canvas; + +use crate::events::Event; +use crate::layout::{DimScalar, Layout, SolvedLayout}; + +pub trait Widget { + fn layout(&self) -> &Layout; + + fn solve_layout(&mut self, parent_layout: &SolvedLayout) -> SolvedLayout; + + /// Minimum possible width in case we choose DimScalar::Hug as the layout width. + fn min_width(&self) -> f32; + + /// Minimum possible height in case we choose DimScalar::Hug as the layout height. + fn min_height(&self) -> f32; + + fn debug(&self, _w: &mut dyn io::Write, _deepness: usize) -> io::Result<()> { + Ok(()) + } + + fn draw(&self, canvas: &mut Canvas, layout: &SolvedLayout); + fn handle_event(&mut self, event: Event, layout: &SolvedLayout) -> bool; +} + +/// Partially resolve this widget's width. +/// +/// - If the width is `Fill`, it returns `None`. +/// - If the width is `Hug`, it returns this widget's minimum width. +/// - If the width is `Fixed`, it returns that fixed width value. +pub fn solve_width(widget: &dyn Widget) -> Option { + match widget.layout().width { + DimScalar::Fill => None, + DimScalar::Hug => Some(widget.min_width()), + DimScalar::Fixed(w) => Some(w), + } +} + +/// Partially resolve this widget's height. +/// +/// - If the height is `Fill`, it returns `None`. +/// - If the height is `Hug`, it returns this widget's minimum height. +/// - If the height is `Fixed`, it returns that fixed height value. +pub fn solve_height(widget: &dyn Widget) -> Option { + match widget.layout().height { + DimScalar::Fill => None, + DimScalar::Hug => Some(widget.min_height()), + DimScalar::Fixed(w) => Some(w), + } +} + +/// Default function to solve a widget's layout, based on the parent's solved layout. +pub fn default_solve_layout( + widget: &mut impl Widget, + parent_layout: &SolvedLayout, +) -> SolvedLayout { + let width = solve_width(widget).unwrap_or_else(|| parent_layout.width()); + let height = solve_height(widget).unwrap_or_else(|| parent_layout.height()); + + let (x, y) = parent_layout.point_at_anchor(widget.layout().anchor); + SolvedLayout::from_origin(widget.layout().origin, x, y, width, height) +} + +pub trait WidgetContainer { + fn pop_child(&mut self) -> Option>; + fn add_dyn_child(&mut self, widget: Box); + + fn add_child(&mut self, widget: impl Widget + 'static) { + self.add_dyn_child(Box::new(widget)); + } + + fn child(mut self, widget: impl Widget + 'static) -> Self + where + Self: Sized, + { + self.add_child(widget); + self + } +} + +/// Anything that mut-derefs to a WidgetContainer is also a WidgetContainer. +impl> WidgetContainer for W { + fn add_dyn_child(&mut self, widget: Box) { + self.deref_mut().add_dyn_child(widget); + } + + fn pop_child(&mut self) -> Option> { + self.deref_mut().pop_child() + } +}