From a5507881c8f21837f186638bcd36824d2556f3e1 Mon Sep 17 00:00:00 2001 From: Olivier FAURE Date: Tue, 2 Apr 2024 18:57:02 +0200 Subject: [PATCH 01/21] TMP --- Cargo.lock | 1021 ++++++++++++++++++++++++--- Cargo.toml | 13 +- examples/blocking_function.rs | 5 +- src/app_root.rs | 97 +-- src/contexts.rs | 145 +--- src/lib.rs | 10 +- src/mouse.rs | 8 +- src/paint_scene_helpers.rs | 83 +++ src/platform/win_handler.rs | 10 +- src/platform/window_description.rs | 12 +- src/testing/harness.rs | 190 +++-- src/testing/helper_widgets.rs | 17 +- src/testing/screenshots.rs | 17 - src/theme.rs | 17 +- src/widget/align.rs | 8 +- src/widget/button.rs | 38 +- src/widget/checkbox.rs | 35 +- src/widget/flex.rs | 14 +- src/widget/mod.rs | 4 +- src/widget/portal.rs | 20 +- src/widget/scroll_bar.rs | 23 +- src/widget/sized_box.rs | 69 +- src/widget/spinner.rs | 23 +- src/widget/split.rs | 24 +- src/widget/tests/invalidation.rs | 40 -- src/widget/tests/layout.rs | 3 +- src/widget/tests/lifecycle_basic.rs | 2 + src/widget/tests/mod.rs | 1 - src/widget/tests/safety_rails.rs | 20 +- src/widget/widget.rs | 7 +- src/widget/widget_pod.rs | 150 +--- src/widget/widget_state.rs | 13 +- 32 files changed, 1428 insertions(+), 711 deletions(-) create mode 100644 src/paint_scene_helpers.rs delete mode 100644 src/widget/tests/invalidation.rs diff --git a/Cargo.lock b/Cargo.lock index de748e1c..ed73ac88 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,6 +8,18 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if 1.0.0", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" version = "0.7.19" @@ -17,6 +29,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "allocator-api2" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" + [[package]] name = "android_system_properties" version = "0.1.5" @@ -47,6 +65,15 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" +[[package]] +name = "ash" +version = "0.37.3+1.3.251" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e9c3835d686b0a6084ab4234fcd1b07dbf6e4767dce60874b12356a25ecd4a" +dependencies = [ + "libloading 0.7.3", +] + [[package]] name = "ashpd" version = "0.3.2" @@ -146,7 +173,7 @@ checksum = "d7d78656ba01f1b93024b7c3a0467f1608e4be67d725749fdcd7d2c7678fd7a2" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.101", ] [[package]] @@ -163,7 +190,7 @@ checksum = "76464446b8bc32758d7e88ee1a804d9914cd9b1cb264c029899680b0be29826f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.101", ] [[package]] @@ -173,7 +200,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39991bc421ddf72f70159011b323ff49b0f783cc676a7287c59453da2e2531cf" dependencies = [ "atk-sys", - "bitflags", + "bitflags 1.3.2", "glib", "libc", ] @@ -208,7 +235,7 @@ version = "0.61.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a022e58a142a46fea340d68012b9201c094e93ec3d033a944a24f8fd4a4f09a" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cexpr", "clang-sys", "lazy_static", @@ -220,10 +247,25 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn", + "syn 1.0.101", "which", ] +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + [[package]] name = "bit_field" version = "0.10.1" @@ -236,6 +278,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" + [[package]] name = "bitmaps" version = "2.1.0" @@ -259,9 +307,23 @@ checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d" [[package]] name = "bytemuck" -version = "1.12.1" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f5715e491b5a1598fc2bef5a606847b5dc1d48ea625bd3c02c00de8285591da" +checksum = "5d6d68c57235a3a081186990eca2867354726650f42f7516ca50c28d6281fd15" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4da9a32f3fed317401fa3c862968128267c3106685286e15d5aaa3d7389c2f60" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.55", +] [[package]] name = "byteorder" @@ -281,7 +343,7 @@ version = "0.16.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3125b15ec28b84c238f6f476c6034016a5f6cc0221cb514ca46c532139fc97d" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cairo-sys-rs", "glib", "libc", @@ -336,6 +398,12 @@ 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 = "chrono" version = "0.4.22" @@ -359,7 +427,7 @@ checksum = "fa2e27ae6ab525c3d369ded447057bca5438d86dc3a68f6faafb8269ba82ebf3" dependencies = [ "glob", "libc", - "libloading", + "libloading 0.7.3", ] [[package]] @@ -368,12 +436,12 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f425db7937052c684daec3bd6375c8abe2d146dca4b8b143d6db777c39138f3a" dependencies = [ - "bitflags", + "bitflags 1.3.2", "block", "cocoa-foundation", "core-foundation", "core-graphics", - "foreign-types", + "foreign-types 0.3.2", "libc", "objc", ] @@ -384,21 +452,62 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ade49b65d560ca58c403a479bb396592b155c0185eada742ee323d1d68d6318" dependencies = [ - "bitflags", + "bitflags 1.3.2", "block", "core-foundation", "core-graphics-types", - "foreign-types", + "foreign-types 0.3.2", "libc", "objc", ] +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + [[package]] name = "color_quant" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" +[[package]] +name = "com" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e17887fd17353b65b1b2ef1c526c83e26cd72e74f598a8dc1bee13a48f3d9f6" +dependencies = [ + "com_macros", +] + +[[package]] +name = "com_macros" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d375883580a668c7481ea6631fc1a8863e33cc335bf56bfad8d7e6d4b04b13a5" +dependencies = [ + "com_macros_support", + "proc-macro2", + "syn 1.0.101", +] + +[[package]] +name = "com_macros_support" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad899a1087a9296d5644792d7cb72b8e34c1bec8e7d4fbc002230169a6e8710c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.101", +] + [[package]] name = "concurrent-queue" version = "1.2.4" @@ -453,10 +562,10 @@ version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb" dependencies = [ - "bitflags", + "bitflags 1.3.2", "core-foundation", "core-graphics-types", - "foreign-types", + "foreign-types 0.3.2", "libc", ] @@ -466,9 +575,9 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b" dependencies = [ - "bitflags", + "bitflags 1.3.2", "core-foundation", - "foreign-types", + "foreign-types 0.3.2", "libc", ] @@ -480,7 +589,7 @@ checksum = "99d74ada66e07c1cefa18f8abfba765b486f250de2e4a999e5727fc0dd4b4a25" dependencies = [ "core-foundation", "core-graphics", - "foreign-types", + "foreign-types 0.3.2", "libc", ] @@ -536,6 +645,17 @@ dependencies = [ "cfg-if 1.0.0", ] +[[package]] +name = "d3d12" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e3d747f100290a1ca24b752186f61f6637e1deffe3bf6320de6fcb29510a307" +dependencies = [ + "bitflags 2.5.0", + "libloading 0.8.3", + "winapi", +] + [[package]] name = "data-url" version = "0.1.1" @@ -553,7 +673,7 @@ checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.101", ] [[package]] @@ -585,14 +705,14 @@ dependencies = [ "anyhow", "ashpd", "bindgen", - "bitflags", + "bitflags 1.3.2", "block", "cairo-rs", "cairo-sys-rs", "cfg-if 1.0.0", "cocoa", "core-graphics", - "foreign-types", + "foreign-types 0.3.2", "futures", "gdk-sys", "glib-sys", @@ -660,7 +780,22 @@ checksum = "f58dc3c5e468259f19f2d46304a6b28f1c3d034442e14b322d2b850e36f6d5ae" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.101", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "euclid" +version = "0.22.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f253bc5c813ca05792837a0ff4b3a580336b224512d48f7eda1d7dd9210787" +dependencies = [ + "num-traits", ] [[package]] @@ -778,6 +913,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "font-types" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b7f6040d337bd44434ab21fc6509154edf2cece88b23758d9d64654c4e7730b" + [[package]] name = "fontdb" version = "0.5.4" @@ -795,7 +936,28 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" dependencies = [ - "foreign-types-shared", + "foreign-types-shared 0.1.1", +] + +[[package]] +name = "foreign-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" +dependencies = [ + "foreign-types-macros", + "foreign-types-shared 0.3.1", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.55", ] [[package]] @@ -804,6 +966,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" +[[package]] +name = "foreign-types-shared" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" + [[package]] name = "futures" version = "0.3.26" @@ -846,6 +1014,17 @@ dependencies = [ "futures-util", ] +[[package]] +name = "futures-intrusive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" +dependencies = [ + "futures-core", + "lock_api", + "parking_lot", +] + [[package]] name = "futures-io" version = "0.3.26" @@ -875,7 +1054,7 @@ checksum = "95a73af87da33b5acf53acfebdc339fe592ecf5357ac7c0a7734ab9d8c876a70" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.101", ] [[package]] @@ -914,7 +1093,7 @@ version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa9cb33da481c6c040404a11f8212d193889e9b435db2c14fd86987f630d3ce1" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cairo-rs", "gdk-pixbuf", "gdk-sys", @@ -930,7 +1109,7 @@ version = "0.16.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3578c60dee9d029ad86593ed88cb40f35c1b83360e12498d055022385dd9a05" dependencies = [ - "bitflags", + "bitflags 1.3.2", "gdk-pixbuf-sys", "gio", "glib", @@ -1017,7 +1196,7 @@ version = "0.16.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a1c84b4534a290a29160ef5c6eff2a9c95833111472e824fc5cb78b513dd092" dependencies = [ - "bitflags", + "bitflags 1.3.2", "futures-channel", "futures-core", "futures-io", @@ -1044,13 +1223,24 @@ dependencies = [ "winapi", ] +[[package]] +name = "gl_generator" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d" +dependencies = [ + "khronos_api", + "log", + "xml-rs", +] + [[package]] name = "glib" version = "0.16.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddd4df61a866ed7259d6189b8bcb1464989a77f1d85d25d002279bbe9dd38b2f" dependencies = [ - "bitflags", + "bitflags 1.3.2", "futures-channel", "futures-core", "futures-executor", @@ -1078,7 +1268,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 1.0.101", ] [[package]] @@ -1097,6 +1287,27 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" +[[package]] +name = "glow" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd348e04c43b32574f2de31c8bb397d96c9fcfa1371bd4ca6d8bdc464ab121b1" +dependencies = [ + "js-sys", + "slotmap", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "glutin_wgl_sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8098adac955faa2d31079b65dc48841251f69efd3ac25477903fc424362ead" +dependencies = [ + "gl_generator", +] + [[package]] name = "gobject-sys" version = "0.16.3" @@ -1108,6 +1319,58 @@ dependencies = [ "system-deps", ] +[[package]] +name = "gpu-alloc" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171" +dependencies = [ + "bitflags 2.5.0", + "gpu-alloc-types", +] + +[[package]] +name = "gpu-alloc-types" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4" +dependencies = [ + "bitflags 2.5.0", +] + +[[package]] +name = "gpu-allocator" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f56f6318968d03c18e1bcf4857ff88c61157e9da8e47c5f29055d60e1228884" +dependencies = [ + "log", + "presser", + "thiserror", + "winapi", + "windows", +] + +[[package]] +name = "gpu-descriptor" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc11df1ace8e7e564511f53af41f3e42ddc95b56fd07b3f4445d2a6048bc682c" +dependencies = [ + "bitflags 2.5.0", + "gpu-descriptor-types", + "hashbrown", +] + +[[package]] +name = "gpu-descriptor-types" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bf0b36e6f090b7e1d8a4b49c0cb81c1f8376f72198c65dd3ad9ff3556b8b78c" +dependencies = [ + "bitflags 2.5.0", +] + [[package]] name = "gtk" version = "0.16.2" @@ -1115,7 +1378,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4d3507d43908c866c805f74c9dd593c0ce7ba5c38e576e41846639cdcd4bee6" dependencies = [ "atk", - "bitflags", + "bitflags 1.3.2", "cairo-rs", "field-offset", "futures-channel", @@ -1160,7 +1423,17 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 1.0.101", +] + +[[package]] +name = "guillotiere" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b62d5865c036cb1393e23c50693df631d3f5d7bcca4c04fe4cc0fd592e74a782" +dependencies = [ + "euclid", + "svg_fmt", ] [[package]] @@ -1169,6 +1442,31 @@ version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +dependencies = [ + "ahash", + "allocator-api2", +] + +[[package]] +name = "hassle-rs" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af2a7e73e1f34c48da31fb668a907f250794837e08faa144fd24f0b8b741e890" +dependencies = [ + "bitflags 2.5.0", + "com", + "libc", + "libloading 0.8.3", + "thiserror", + "widestring", + "winapi", +] + [[package]] name = "heck" version = "0.4.1" @@ -1190,6 +1488,12 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hexf-parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" + [[package]] name = "iana-time-zone" version = "0.1.50" @@ -1251,6 +1555,16 @@ dependencies = [ "tiff", ] +[[package]] +name = "indexmap" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +dependencies = [ + "equivalent", + "hashbrown", +] + [[package]] name = "insta" version = "1.18.2" @@ -1303,6 +1617,12 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754" +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + [[package]] name = "jpeg-decoder" version = "0.3.0" @@ -1314,9 +1634,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.60" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" dependencies = [ "wasm-bindgen", ] @@ -1327,9 +1647,26 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7668b7cff6a51fe61cdde64cd27c8a220786f399501b57ebe36f7d8112fd68" dependencies = [ - "bitflags", + "bitflags 1.3.2", +] + +[[package]] +name = "khronos-egl" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76" +dependencies = [ + "libc", + "libloading 0.8.3", + "pkg-config", ] +[[package]] +name = "khronos_api" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" + [[package]] name = "kurbo" version = "0.8.3" @@ -1349,6 +1686,16 @@ dependencies = [ "serde", ] +[[package]] +name = "kurbo" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e5aa9f0f96a938266bdb12928a67169e8d22c6a786fda8ed984b85e6ba93c3c" +dependencies = [ + "arrayvec", + "smallvec", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -1383,6 +1730,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "libloading" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" +dependencies = [ + "cfg-if 1.0.0", + "windows-targets", +] + [[package]] name = "linked-hash-map" version = "0.5.6" @@ -1430,17 +1787,21 @@ dependencies = [ "fluent-langneg", "fluent-syntax", "fnv", + "futures-intrusive", "im", "image 0.24.5", "insta", "instant", + "kurbo 0.11.0", "once_cell", "open", - "piet-common", + "parley", + "pollster", "pulldown-cmark", "serde", "serde_json", "smallvec", + "swash", "tempfile", "tracing", "tracing-subscriber 0.2.25", @@ -1448,6 +1809,8 @@ dependencies = [ "unic-langid", "unicode-segmentation", "usvg", + "vello", + "wgpu", "xi-unicode", ] @@ -1481,6 +1844,21 @@ dependencies = [ "autocfg", ] +[[package]] +name = "metal" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c43f73953f8cbe511f021b58f18c3ce1c3d1ae13fe953293e13345bf83217f25" +dependencies = [ + "bitflags 2.5.0", + "block", + "core-graphics-types", + "foreign-types 0.5.0", + "log", + "objc", + "paste", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -1505,6 +1883,26 @@ dependencies = [ "adler", ] +[[package]] +name = "naga" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50e3524642f53d9af419ab5e8dd29d3ba155708267667c2f3f06c88c9e130843" +dependencies = [ + "bit-set", + "bitflags 2.5.0", + "codespan-reporting", + "hexf-parse", + "indexmap", + "log", + "num-traits", + "rustc-hash", + "spirv", + "termcolor", + "thiserror", + "unicode-xid", +] + [[package]] name = "nanorand" version = "0.7.0" @@ -1515,13 +1913,22 @@ dependencies = [ ] [[package]] -name = "nix" -version = "0.23.1" +name = "ndk-sys" +version = "0.5.0+25.2.9519653" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6" +checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691" dependencies = [ - "bitflags", - "cc", + "jni-sys", +] + +[[package]] +name = "nix" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6" +dependencies = [ + "bitflags 1.3.2", + "cc", "cfg-if 1.0.0", "libc", "memoffset", @@ -1533,7 +1940,7 @@ version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cfg-if 1.0.0", "libc", "memoffset", @@ -1618,13 +2025,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" dependencies = [ "malloc_buf", + "objc_exception", +] + +[[package]] +name = "objc_exception" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4" +dependencies = [ + "cc", ] [[package]] name = "once_cell" -version = "1.17.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "open" @@ -1652,7 +2069,7 @@ version = "0.16.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdff66b271861037b89d028656184059e03b0b6ccb36003820be19f7200b1e94" dependencies = [ - "bitflags", + "bitflags 1.3.2", "gio", "glib", "libc", @@ -1678,7 +2095,7 @@ version = "0.16.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16ad2ec87789371b551fd2367c10aa37060412ffd3e60abd99491b21b93a3f9b" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cairo-rs", "glib", "libc", @@ -1728,6 +2145,21 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "parley" +version = "0.0.1" +source = "git+https://github.com/dfrg/parley?rev=1940d1ae9f2a9b44b7c18967147ffa7d345fdafd#1940d1ae9f2a9b44b7c18967147ffa7d345fdafd" +dependencies = [ + "peniko", + "swash", +] + +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + [[package]] name = "pathdiff" version = "0.2.1" @@ -1740,6 +2172,16 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" +[[package]] +name = "peniko" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caaf7fec601d640555d9a4cab7343eba1e1c7a5a71c9993ff63b4c26bc5d50c5" +dependencies = [ + "kurbo 0.11.0", + "smallvec", +] + [[package]] name = "pest" version = "2.3.1" @@ -1811,7 +2253,7 @@ dependencies = [ "core-foundation-sys", "core-graphics", "core-text", - "foreign-types", + "foreign-types 0.3.2", "piet", ] @@ -1860,7 +2302,7 @@ checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.101", ] [[package]] @@ -1887,7 +2329,7 @@ version = "0.17.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d708eaf860a19b19ce538740d2b4bdeeb8337fa53f7738455e706623ad5c638" dependencies = [ - "bitflags", + "bitflags 1.3.2", "crc32fast", "flate2", "miniz_oxide 0.6.2", @@ -1907,12 +2349,24 @@ dependencies = [ "winapi", ] +[[package]] +name = "pollster" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22686f4785f02a4fcc856d3b3bb19bf6c8160d103f7a99cc258bddd0251dc7f2" + [[package]] name = "ppv-lite86" version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" +[[package]] +name = "presser" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa" + [[package]] name = "proc-macro-crate" version = "1.2.1" @@ -1933,7 +2387,7 @@ dependencies = [ "proc-macro-error-attr", "proc-macro2", "quote", - "syn", + "syn 1.0.101", "version_check", ] @@ -1950,29 +2404,35 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.46" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94e2ef8dbfc347b10c094890f778ee2e36ca9bb4262e86dc99cd217e35f3470b" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" dependencies = [ "unicode-ident", ] +[[package]] +name = "profiling" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d84d1d7a6ac92673717f9f6d1518374ef257669c24ebc5ac25d5033828be58" + [[package]] name = "pulldown-cmark" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8" dependencies = [ - "bitflags", + "bitflags 1.3.2", "memchr", "unicase", ] [[package]] name = "quote" -version = "1.0.21" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -2057,6 +2517,18 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "range-alloc" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8a99fddc9f0ba0a85884b8d14e3592853e787d581ca1816c91349b10e4eeab" + +[[package]] +name = "raw-window-handle" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42a9830a0e1b9fb145ebb365b8bc4ccd75f290f98c0247deafbbe2c75cefb544" + [[package]] name = "rayon" version = "1.5.3" @@ -2087,6 +2559,24 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be9e29cb19c8fe84169fcb07f8f11e66bc9e6e0280efd4715c54818296f8a4a8" +[[package]] +name = "read-fonts" +version = "0.15.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17ea23eedb4d938031b6d4343222444608727a6aa68ec355e13588d9947ffe92" +dependencies = [ + "font-types", +] + +[[package]] +name = "read-fonts" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81c524658d3b77930a391f559756d91dbe829ab6cf4687083f615d395df99722" +dependencies = [ + "font-types", +] + [[package]] name = "redox_syscall" version = "0.1.57" @@ -2099,7 +2589,7 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -2139,6 +2629,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "renderdoc-sys" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" + [[package]] name = "roxmltree" version = "0.14.1" @@ -2169,7 +2665,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ab463a295d00f3692e0974a0bfd83c7a9bcd119e27e07c2beecdb1b44a09d10" dependencies = [ - "bitflags", + "bitflags 1.3.2", "bytemuck", "smallvec", "ttf-parser 0.9.0", @@ -2238,7 +2734,7 @@ checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.101", ] [[package]] @@ -2260,7 +2756,7 @@ checksum = "1fe39d9fbb0ebf5eb2c7cb7e2a47e4f462fad1379f1166b8ae49ad9eae89a7ca" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.101", ] [[package]] @@ -2324,6 +2820,15 @@ dependencies = [ "typenum", ] +[[package]] +name = "skrifa" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eff28ee3b66d43060ef9a327e0f18e4c1813f194120156b4d4524fac3ba8ce22" +dependencies = [ + "read-fonts 0.15.6", +] + [[package]] name = "slab" version = "0.4.7" @@ -2333,11 +2838,20 @@ dependencies = [ "autocfg", ] +[[package]] +name = "slotmap" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a" +dependencies = [ + "version_check", +] + [[package]] name = "smallvec" -version = "1.9.0" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" @@ -2358,12 +2872,27 @@ dependencies = [ "lock_api", ] +[[package]] +name = "spirv" +version = "0.3.0+sdk-1.3.268.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844" +dependencies = [ + "bitflags 2.5.0", +] + [[package]] name = "static_assertions" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "svg_fmt" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83ba502a3265efb76efb89b0a2f7782ad6f2675015d4ce37e4b547dda42b499" + [[package]] name = "svgtypes" version = "0.5.0" @@ -2374,6 +2903,17 @@ dependencies = [ "siphasher", ] +[[package]] +name = "swash" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9af636fb90d39858650cae1088a37e2862dab4e874a0bb49d6dfb5b2dacf0e24" +dependencies = [ + "read-fonts 0.16.0", + "yazi", + "zeno", +] + [[package]] name = "syn" version = "1.0.101" @@ -2385,6 +2925,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "2.0.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "system-deps" version = "6.0.3" @@ -2412,6 +2963,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + [[package]] name = "terminal_size" version = "0.1.17" @@ -2424,22 +2984,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.37" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" +checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.37" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" +checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.55", ] [[package]] @@ -2533,7 +3093,7 @@ checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.101", ] [[package]] @@ -2749,6 +3309,18 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1d386ff53b415b7fe27b50bb44679e2cc4660272694b7b6f3326d8480823a94" +[[package]] +name = "unicode-width" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + [[package]] name = "usvg" version = "0.14.1" @@ -2788,6 +3360,33 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +[[package]] +name = "vello" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9a4b96a2d6d6effa67868b4436560e3a767f71f0e043df007587c5d6b2e8b7a" +dependencies = [ + "bytemuck", + "futures-intrusive", + "peniko", + "raw-window-handle", + "skrifa", + "vello_encoding", + "wgpu", +] + +[[package]] +name = "vello_encoding" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c5b6c6ec113c9b6ee1e1894ccef1b5559373aead718b7442811f2fefff7d423" +dependencies = [ + "bytemuck", + "guillotiere", + "peniko", + "skrifa", +] + [[package]] name = "version-compare" version = "0.1.1" @@ -2826,9 +3425,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.83" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ "cfg-if 1.0.0", "wasm-bindgen-macro", @@ -2836,24 +3435,36 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.83" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn", + "syn 2.0.55", "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +dependencies = [ + "cfg-if 1.0.0", + "js-sys", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "wasm-bindgen-macro" -version = "0.2.83" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2861,28 +3472,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.83" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.55", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.83" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "web-sys" -version = "0.3.60" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" dependencies = [ "js-sys", "wasm-bindgen", @@ -2903,6 +3514,113 @@ dependencies = [ "cc", ] +[[package]] +name = "wgpu" +version = "0.19.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4b1213b52478a7631d6e387543ed8f642bc02c578ef4e3b49aca2a29a7df0cb" +dependencies = [ + "arrayvec", + "cfg-if 1.0.0", + "cfg_aliases", + "js-sys", + "log", + "naga", + "parking_lot", + "profiling", + "raw-window-handle", + "smallvec", + "static_assertions", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "wgpu-core", + "wgpu-hal", + "wgpu-types", +] + +[[package]] +name = "wgpu-core" +version = "0.19.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9f6b033c2f00ae0bc8ea872c5989777c60bc241aac4e58b24774faa8b391f78" +dependencies = [ + "arrayvec", + "bit-vec", + "bitflags 2.5.0", + "cfg_aliases", + "codespan-reporting", + "indexmap", + "log", + "naga", + "once_cell", + "parking_lot", + "profiling", + "raw-window-handle", + "rustc-hash", + "smallvec", + "thiserror", + "web-sys", + "wgpu-hal", + "wgpu-types", +] + +[[package]] +name = "wgpu-hal" +version = "0.19.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f972c280505ab52ffe17e94a7413d9d54b58af0114ab226b9fc4999a47082e" +dependencies = [ + "android_system_properties", + "arrayvec", + "ash", + "bit-set", + "bitflags 2.5.0", + "block", + "cfg_aliases", + "core-graphics-types", + "d3d12", + "glow", + "glutin_wgl_sys", + "gpu-alloc", + "gpu-allocator", + "gpu-descriptor", + "hassle-rs", + "js-sys", + "khronos-egl", + "libc", + "libloading 0.8.3", + "log", + "metal", + "naga", + "ndk-sys", + "objc", + "once_cell", + "parking_lot", + "profiling", + "range-alloc", + "raw-window-handle", + "renderdoc-sys", + "rustc-hash", + "smallvec", + "thiserror", + "wasm-bindgen", + "web-sys", + "wgpu-types", + "winapi", +] + +[[package]] +name = "wgpu-types" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b671ff9fb03f78b46ff176494ee1ebe7d603393f42664be55b64dc8d53969805" +dependencies = [ + "bitflags 2.5.0", + "js-sys", + "web-sys", +] + [[package]] name = "which" version = "4.4.0" @@ -2914,6 +3632,12 @@ dependencies = [ "once_cell", ] +[[package]] +name = "widestring" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8" + [[package]] name = "winapi" version = "0.3.9" @@ -2930,6 +3654,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + [[package]] name = "winapi-wsapoll" version = "0.1.1" @@ -2945,49 +3678,125 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" +dependencies = [ + "windows-core", + "windows-targets", +] + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets", +] + [[package]] name = "windows-sys" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" dependencies = [ - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_msvc", + "windows_aarch64_msvc 0.36.1", + "windows_i686_gnu 0.36.1", + "windows_i686_msvc 0.36.1", + "windows_x86_64_gnu 0.36.1", + "windows_x86_64_msvc 0.36.1", +] + +[[package]] +name = "windows-targets" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc 0.52.4", + "windows_i686_gnu 0.52.4", + "windows_i686_msvc 0.52.4", + "windows_x86_64_gnu 0.52.4", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc 0.52.4", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" + [[package]] name = "windows_aarch64_msvc" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" + [[package]] name = "windows_i686_gnu" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" +[[package]] +name = "windows_i686_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" + [[package]] name = "windows_i686_msvc" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" +[[package]] +name = "windows_i686_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" + [[package]] name = "windows_x86_64_gnu" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" + [[package]] name = "windows_x86_64_msvc" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" + [[package]] name = "wio" version = "0.2.2" @@ -3026,6 +3835,12 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a67300977d3dc3f8034dae89778f502b6ba20b269527b3223ba59c0cf393bb8a" +[[package]] +name = "xml-rs" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fcb9cbac069e033553e8bb871be2fbdffcab578eb25bd0f7c508cedc6dcd75a" + [[package]] name = "xmlparser" version = "0.13.3" @@ -3047,6 +3862,12 @@ dependencies = [ "linked-hash-map", ] +[[package]] +name = "yazi" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c94451ac9513335b5e23d7a8a2b61a7102398b8cca5160829d313e84c9d98be1" + [[package]] name = "zbus" version = "2.3.2" @@ -3097,7 +3918,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn", + "syn 1.0.101", ] [[package]] @@ -3111,6 +3932,32 @@ dependencies = [ "zvariant", ] +[[package]] +name = "zeno" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd15f8e0dbb966fd9245e7498c7e9e5055d9e5c8b676b95bd67091cd11a1e697" + +[[package]] +name = "zerocopy" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.55", +] + [[package]] name = "zvariant" version = "3.7.1" @@ -3134,5 +3981,5 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 1.0.101", ] diff --git a/Cargo.toml b/Cargo.toml index dd05170c..320388ed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ rustdoc-args = ["--cfg", "docsrs"] [features] default = ["gtk", "image", "png", "jpeg"] gtk = ["druid-shell/gtk"] -image = ["druid-shell/image", "piet-common/image"] +image = ["druid-shell/image"] serde_deps = ["im/serde", "druid-shell/serde"] svg = ["usvg"] x11 = ["druid-shell/x11"] @@ -50,8 +50,6 @@ image-all = ["image", "svg", "png", "jpeg", "jpeg_rayon", "gif", "bmp", "ico", " [dependencies] druid-shell = {version = "0.8.0", default-features = false} -# We defer to the version imported by druid-shell -piet-common = "*" # TODO - remove unused dependencies - See #10 fluent-bundle = "0.15.1" @@ -76,6 +74,15 @@ image = "0.24.0" once_cell = "1.9.0" serde = {version = "1.0.133", features = ["derive"]} serde_json = "1.0.74" +vello = "0.1.0" +kurbo = "0.11.0" +futures-intrusive = "0.5.0" +pollster = "0.3.0" +parley = { git = "https://github.com/dfrg/parley", rev = "1940d1ae9f2a9b44b7c18967147ffa7d345fdafd" } + +# NOTE: Make sure to keep this in sync with the version badge in README.md +wgpu = { version = "0.19.3" } +swash = "0.1.13" [target.'cfg(target_arch="wasm32")'.dependencies] console_error_panic_hook = {version = "0.1.6"} diff --git a/examples/blocking_function.rs b/examples/blocking_function.rs index 14c2ba66..a8215f52 100644 --- a/examples/blocking_function.rs +++ b/examples/blocking_function.rs @@ -16,6 +16,7 @@ use masonry::widget::WidgetRef; use masonry::widget::{Flex, Label, Spinner, WidgetPod}; use masonry::{AppLauncher, Point, Selector, Target, WindowDescription}; use smallvec::{smallvec, SmallVec}; +use vello::Scene; const FINISH_SLOW_FUNCTION: Selector = Selector::new("finish_slow_function"); @@ -102,8 +103,8 @@ impl Widget for MainWidget { content_size } - fn paint(&mut self, ctx: &mut PaintCtx) { - self.content.paint(ctx); + fn paint(&mut self, ctx: &mut PaintCtx, scene: &mut Scene) { + self.content.paint(ctx, scene); } fn children(&self) -> SmallVec<[WidgetRef<'_, dyn Widget>; 16]> { diff --git a/src/app_root.rs b/src/app_root.rs index cba86a25..e3339968 100644 --- a/src/app_root.rs +++ b/src/app_root.rs @@ -21,8 +21,12 @@ use druid_shell::{ Cursor, FileDialogToken, FileInfo, Region, TextFieldToken, TimerToken, WindowBuilder, }; // Automatically defaults to std::time::Instant on non Wasm platforms +use druid_shell::piet::Piet; use instant::Instant; +use kurbo::Affine; use tracing::{error, info, info_span}; +use vello::peniko::{Color, Fill}; +use vello::Scene; use crate::action::ActionQueue; use crate::app_delegate::{AppDelegate, DelegateCtx, NullDelegate}; @@ -31,12 +35,11 @@ use crate::contexts::GlobalPassCtx; use crate::debug_logger::DebugLogger; use crate::ext_event::{ExtEventQueue, ExtEventSink, ExtMessage}; use crate::kurbo::{Point, Size}; -use crate::piet::{Color, Piet, RenderContext}; use crate::platform::{ DialogInfo, WindowConfig, WindowSizePolicy, EXT_EVENT_IDLE_TOKEN, RUN_COMMANDS_TOKEN, }; use crate::testing::MockTimerQueue; -use crate::text::TextFieldRegistration; +use crate::text_helpers::TextFieldRegistration; use crate::widget::{FocusChange, StoreInWidgetMut, WidgetMut, WidgetRef, WidgetState}; use crate::{ command as sys_cmd, ArcStr, BoxConstraints, Command, Event, EventCtx, Handled, InternalEvent, @@ -100,7 +103,6 @@ pub struct WindowRoot { pub(crate) title: ArcStr, size_policy: WindowSizePolicy, size: Size, - invalid: Region, // Is `Some` if the most recently displayed frame was an animation frame. pub(crate) last_anim: Option, pub(crate) last_mouse_pos: Option, @@ -316,18 +318,19 @@ impl AppRoot { /// /// Currently, this computes layout if needed and calls paint methods in the /// widget hierarchy. - pub fn paint(&mut self, window_id: WindowId, piet: &mut Piet, invalid: &Region) { + pub fn paint(&mut self, window_id: WindowId, piet: &mut Piet) { let mut inner = self.inner.borrow_mut(); let inner = inner.deref_mut(); if let Some(win) = inner.active_windows.get_mut(&window_id) { + let mut scene = Scene::new(); win.do_paint( - piet, - invalid, + &mut scene, &mut inner.debug_logger, &mut inner.command_queue, &mut inner.action_queue, ); } + todo!("Switch to winit"); } /// Run any leftover commands from previous events. @@ -857,7 +860,6 @@ impl WindowRoot { root: WidgetPod::new(root), size_policy, size: Size::ZERO, - invalid: Region::EMPTY, title, transparent, last_anim: None, @@ -910,6 +912,9 @@ impl WindowRoot { .. } = self; ime_handlers.retain(|(token, v)| { + // FIXME + let will_retain = true; + #[cfg(FALSE)] let will_retain = v.is_alive(); if !will_retain { tracing::debug!("{:?} removed", token); @@ -956,7 +961,6 @@ impl WindowRoot { if self.wants_animation_frame() { self.handle.request_anim_frame(); } - self.invalid.union_with(&widget_state.invalid); for ime_field in widget_state.text_registrations.drain(..) { let token = self.handle.add_text_field(); tracing::debug!("{:?} added", token); @@ -1138,25 +1142,7 @@ impl WindowRoot { } pub(crate) fn invalidate_paint_region(&mut self) { - if self.root.state().needs_layout { - // TODO - this might be too coarse - self.handle.invalidate(); - } else { - for rect in self.invalid.rects() { - self.handle.invalidate_rect(*rect); - } - } - self.invalid.clear(); - } - - #[allow(dead_code)] - pub(crate) fn invalid(&self) -> &Region { - &self.invalid - } - - #[allow(dead_code)] - pub(crate) fn invalid_mut(&mut self) -> &mut Region { - &mut self.invalid + self.handle.invalidate(); } /// Get ready for painting, by doing layout and sending an `AnimFrame` event. @@ -1187,8 +1173,7 @@ impl WindowRoot { pub(crate) fn do_paint( &mut self, - piet: &mut Piet, - invalid: &Region, + scene: &mut Scene, debug_logger: &mut DebugLogger, command_queue: &mut CommandQueue, action_queue: &mut ActionQueue, @@ -1197,17 +1182,20 @@ impl WindowRoot { self.layout(debug_logger, command_queue, action_queue); } - for &r in invalid.rects() { - piet.clear( - Some(r), - if self.transparent { - Color::TRANSPARENT - } else { - crate::theme::WINDOW_BACKGROUND_COLOR - }, - ); - } - self.paint(piet, invalid, debug_logger, command_queue, action_queue); + scene.reset(); + self.paint(scene, debug_logger, command_queue, action_queue); + + // FIXME - This is a workaround to Vello panicking when given an + // empty scene + // See https://github.com/linebender/vello/issues/291 + let empty_path = kurbo::Rect::ZERO; + scene.fill( + Fill::NonZero, + Affine::IDENTITY, + &Color::TRANSPARENT, + None, + &empty_path, + ); } pub(crate) fn layout( @@ -1275,8 +1263,7 @@ impl WindowRoot { fn paint( &mut self, - piet: &mut Piet, - invalid: &Region, + scene: &mut Scene, debug_logger: &mut DebugLogger, command_queue: &mut CommandQueue, action_queue: &mut ActionQueue, @@ -1294,34 +1281,18 @@ impl WindowRoot { self.focus, ); let mut ctx = PaintCtx { - render_ctx: piet, global_state: &mut global_state, widget_state: &widget_state, - z_ops: Vec::new(), - region: invalid.clone(), depth: 0, debug_paint: false, debug_widget: false, - debug_widget_id: false, }; let root = &mut self.root; info_span!("paint").in_scope(|| { - ctx.with_child_ctx(invalid.clone(), |ctx| root.paint_raw(ctx)); + root.paint(&mut ctx, scene); }); - let mut z_ops = std::mem::take(&mut ctx.z_ops); - z_ops.sort_by_key(|k| k.z_index); - - for z_op in z_ops.into_iter() { - ctx.with_child_ctx(invalid.clone(), |ctx| { - ctx.with_save(|ctx| { - ctx.render_ctx.transform(z_op.transform); - (z_op.paint_func)(ctx); - }); - }); - } - if self.wants_animation_frame() { self.handle.request_anim_frame(); } @@ -1332,6 +1303,8 @@ impl WindowRoot { req_token: TextFieldToken, mutable: bool, ) -> Box { + todo!(); + #[cfg(FALSE)] self.ime_handlers .iter() .find(|(token, _)| req_token == *token) @@ -1344,6 +1317,8 @@ impl WindowRoot { mutable: bool, ) -> Option> { let focused_widget_id = self.focus?; + todo!(); + #[cfg(FALSE)] self.ime_handlers .iter() .find(|(_, reg)| reg.widget_id == focused_widget_id) @@ -1423,6 +1398,8 @@ impl WindowRoot { .ime_handlers .iter() .find(|(token, _)| req_token == *token)?; + todo!(); + #[cfg(FALSE)] reg.document.release().then_some(reg.widget_id) } @@ -1432,6 +1409,8 @@ impl WindowRoot { .ime_handlers .iter() .find(|(_, reg)| reg.widget_id == focused_widget_id)?; + todo!(); + #[cfg(FALSE)] reg.document.release().then_some(reg.widget_id) } diff --git a/src/contexts.rs b/src/contexts.rs index 07ef6609..11e2c7be 100644 --- a/src/contexts.rs +++ b/src/contexts.rs @@ -10,6 +10,7 @@ use std::ops::{Deref, DerefMut}; use std::rc::Rc; use std::time::Duration; +use druid_shell::piet::{Piet, PietText}; use druid_shell::text::Event as ImeInvalidation; use druid_shell::{Cursor, Region, TimerToken, WindowHandle}; use tracing::{error, trace, warn}; @@ -18,11 +19,10 @@ use crate::action::{Action, ActionQueue}; use crate::command::{Command, CommandQueue, Notification, SingleUse}; use crate::debug_logger::DebugLogger; use crate::ext_event::ExtEventSink; -use crate::piet::{Piet, PietText, RenderContext}; use crate::platform::WindowDescription; use crate::promise::PromiseToken; use crate::testing::MockTimerQueue; -use crate::text::{ImeHandlerRef, TextFieldRegistration}; +use crate::text_helpers::TextFieldRegistration; use crate::widget::{CursorChange, FocusChange, StoreInWidgetMut, WidgetMut, WidgetState}; use crate::{ Affine, Insets, Point, Rect, Size, Target, Vec2, Widget, WidgetId, WidgetPod, WindowId, @@ -107,39 +107,21 @@ pub struct LayoutCtx<'a, 'b> { pub(crate) mouse_pos: Option, } -/// Z-order paint operations with transformations. -pub(crate) struct ZOrderPaintOp { - pub z_index: u32, - pub paint_func: Box, - pub transform: Affine, -} - /// A context passed to paint methods of widgets. -/// -/// In addition to the API below, [`PaintCtx`] derefs to an implemention of -/// the [`RenderContext`] trait, which defines the basic available drawing -/// commands. -pub struct PaintCtx<'a, 'b, 'c> { +pub struct PaintCtx<'a, 'b> { pub(crate) global_state: &'a mut GlobalPassCtx<'b>, pub(crate) widget_state: &'a WidgetState, - /// The render context for actually painting. - pub render_ctx: &'a mut Piet<'c>, - /// The z-order paint operations. - pub(crate) z_ops: Vec, - /// The currently visible region. - pub(crate) region: Region, /// The approximate depth in the tree at the time of painting. pub(crate) depth: u32, pub(crate) debug_paint: bool, pub(crate) debug_widget: bool, - pub(crate) debug_widget_id: bool, } impl_context_method!( WidgetCtx<'_, '_>, EventCtx<'_, '_>, LifeCycleCtx<'_, '_>, - PaintCtx<'_, '_, '_>, + PaintCtx<'_, '_>, LayoutCtx<'_, '_>, { /// get the `WidgetId` of the current widget. @@ -181,7 +163,7 @@ impl_context_method!( WidgetCtx<'_, '_>, EventCtx<'_, '_>, LifeCycleCtx<'_, '_>, - PaintCtx<'_, '_, '_>, + PaintCtx<'_, '_>, { /// The layout size. /// @@ -215,7 +197,9 @@ impl_context_method!( /// [`Screen`]: druid_shell::Screen pub fn to_screen(&self, widget_point: Point) -> Point { let insets = self.window().content_insets(); - let content_origin = self.window().get_position() + Vec2::new(insets.x0, insets.y0); + let window_pos = self.window().get_position(); + let window_pos = Point::new(window_pos.x, window_pos.y); + let content_origin = window_pos + Vec2::new(insets.x0, insets.y0); content_origin + self.to_window(widget_point).to_vec2() } @@ -407,25 +391,10 @@ impl<'a, 'b> LifeCycleCtx<'a, 'b> { // methods on event and lifecycle impl_context_method!(WidgetCtx<'_, '_>, EventCtx<'_, '_>, LifeCycleCtx<'_, '_>, { - /// Request a [`paint`] pass. This is equivalent to calling - /// [`request_paint_rect`](Self::request_paint_rect) for the widget's [`paint_rect`]. - /// + /// Request a [`paint`] pass. /// [`paint`]: trait.Widget.html#tymethod.paint - /// [`paint_rect`]: struct.WidgetPod.html#method.paint_rect pub fn request_paint(&mut self) { trace!("request_paint"); - self.widget_state.invalid.set_rect( - self.widget_state.paint_rect() - self.widget_state.layout_rect().origin().to_vec2(), - ); - } - - /// Request a [`paint`] pass for redrawing a rectangle, which is given - /// relative to our layout rectangle. - /// - /// [`paint`]: trait.Widget.html#tymethod.paint - pub fn request_paint_rect(&mut self, rect: Rect) { - trace!("request_paint_rect {}", rect); - self.widget_state.invalid.add_rect(rect); } /// Request a layout pass. @@ -757,9 +726,8 @@ impl LifeCycleCtx<'_, '_> { } /// Register this widget as accepting text input. - pub fn register_text_input(&mut self, document: impl ImeHandlerRef + 'static) { + pub fn register_as_text_input(&mut self) { let registration = TextFieldRegistration { - document: Rc::new(document), widget_id: self.widget_id(), }; self.widget_state.text_registrations.push(registration); @@ -833,7 +801,7 @@ impl LayoutCtx<'_, '_> { } } -impl PaintCtx<'_, '_, '_> { +impl PaintCtx<'_, '_> { /// The depth in the tree of the currently painting widget. /// /// This may be used in combination with [`paint_with_z_index`](Self::paint_with_z_index) in order @@ -845,83 +813,6 @@ impl PaintCtx<'_, '_, '_> { pub fn depth(&self) -> u32 { self.depth } - - /// Returns the region that needs to be repainted. - #[inline] - pub fn region(&self) -> &Region { - &self.region - } - - /// Creates a temporary `PaintCtx` with a new visible region, and calls - /// the provided function with that `PaintCtx`. - /// - /// This is used by containers to ensure that their children have the correct - /// visible region given their layout. - pub fn with_child_ctx(&mut self, region: impl Into, f: impl FnOnce(&mut PaintCtx)) { - let mut child_ctx = PaintCtx { - render_ctx: self.render_ctx, - global_state: self.global_state, - widget_state: self.widget_state, - z_ops: Vec::new(), - region: region.into(), - depth: self.depth + 1, - debug_paint: self.debug_paint, - debug_widget: self.debug_widget, - debug_widget_id: self.debug_widget_id, - }; - f(&mut child_ctx); - self.z_ops.append(&mut child_ctx.z_ops); - } - - /// Saves the current context, executes the closures, and restores the context. - /// - /// This is useful if you would like to transform or clip or otherwise - /// modify the drawing context but do not want that modification to - /// effect other widgets. - /// - /// # Examples - /// - /// ``` - /// # use masonry::{PaintCtx, RenderContext, theme}; - /// # struct T; - /// # impl T { - /// fn paint(&mut self, ctx: &mut PaintCtx) { - /// let clip_rect = ctx.size().to_rect().inset(5.0); - /// ctx.with_save(|ctx| { - /// ctx.clip(clip_rect); - /// ctx.stroke(clip_rect, &theme::PRIMARY_DARK, 5.0); - /// }); - /// } - /// # } - /// ``` - pub fn with_save(&mut self, f: impl FnOnce(&mut PaintCtx)) { - if let Err(e) = self.render_ctx.save() { - error!("Failed to save RenderContext: '{}'", e); - return; - } - - f(self); - - if let Err(e) = self.render_ctx.restore() { - error!("Failed to restore RenderContext: '{}'", e); - } - } - - /// Allows to specify order for paint operations. - /// - /// Larger `z_index` indicate that an operation will be executed later. - pub fn paint_with_z_index( - &mut self, - z_index: u32, - paint_func: impl FnOnce(&mut PaintCtx) + 'static, - ) { - let current_transform = self.render_ctx.current_transform(); - self.z_ops.push(ZOrderPaintOp { - z_index, - paint_func: Box::new(paint_func), - transform: current_transform, - }) - } } impl<'a> GlobalPassCtx<'a> { @@ -978,17 +869,3 @@ impl<'a> GlobalPassCtx<'a> { timer_token } } - -impl<'c> Deref for PaintCtx<'_, '_, 'c> { - type Target = Piet<'c>; - - fn deref(&self) -> &Self::Target { - self.render_ctx - } -} - -impl<'c> DerefMut for PaintCtx<'_, '_, 'c> { - fn deref_mut(&mut self) -> &mut Self::Target { - self.render_ctx - } -} diff --git a/src/lib.rs b/src/lib.rs index 4253e322..fd6dd169 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -93,7 +93,7 @@ pub use druid_shell as shell; #[doc(inline)] -pub use druid_shell::{kurbo, piet}; +pub use kurbo; #[macro_use] mod util; @@ -109,10 +109,11 @@ mod contexts; mod event; pub mod ext_event; mod mouse; +pub mod paint_scene_helpers; mod platform; pub mod promise; pub mod testing; -pub mod text; +pub mod text_helpers; pub mod theme; pub mod widget; @@ -131,10 +132,11 @@ pub use druid_shell::Error as PlatformError; pub use event::{Event, InternalEvent, InternalLifeCycle, LifeCycle, StatusChange}; pub use kurbo::{Affine, Insets, Point, Rect, Size, Vec2}; pub use mouse::MouseEvent; -pub use piet::{Color, ImageBuf, LinearGradient, RadialGradient, RenderContext, UnitPoint}; pub use platform::{ MasonryWinHandler, WindowConfig, WindowDescription, WindowId, WindowSizePolicy, }; -pub use text::ArcStr; pub use util::{AsAny, Handled}; +pub use vello::peniko::{Color, Gradient}; pub use widget::{BackgroundBrush, Widget, WidgetId, WidgetPod, WidgetState}; + +pub use text_helpers::ArcStr; diff --git a/src/mouse.rs b/src/mouse.rs index 26104e3d..c43e3724 100644 --- a/src/mouse.rs +++ b/src/mouse.rs @@ -76,14 +76,16 @@ impl From for MouseEvent { wheel_delta, } = src; MouseEvent { - pos, - window_pos: pos, + // Temporary fix, should be removed after the switch to Winit + pos: (pos.x, pos.y).into(), + window_pos: (pos.x, pos.y).into(), buttons, mods, count, focus, button, - wheel_delta, + // Temporary fix, should be removed after the switch to Winit + wheel_delta: (wheel_delta.x, wheel_delta.y).into(), } } } diff --git a/src/paint_scene_helpers.rs b/src/paint_scene_helpers.rs new file mode 100644 index 00000000..9596957d --- /dev/null +++ b/src/paint_scene_helpers.rs @@ -0,0 +1,83 @@ +use vello::{ + kurbo::{self, Affine, Rect, Shape, Stroke}, + peniko::{BrushRef, Color, ColorStopsSource, Fill, Gradient}, + Scene, +}; + +// TODO - Remove this file + +#[derive(Debug, Clone, Copy)] +pub struct UnitPoint { + u: f64, + v: f64, +} + +pub fn stroke<'b>( + scene: &mut Scene, + path: &impl Shape, + brush: impl Into>, + stroke_width: f64, +) { + scene.stroke( + &Stroke::new(stroke_width), + Affine::IDENTITY, + brush, + None, + path, + ); +} + +// Note: copied from piet +#[allow(unused)] +impl UnitPoint { + /// `(0.0, 0.0)` + pub const TOP_LEFT: UnitPoint = UnitPoint::new(0.0, 0.0); + /// `(0.5, 0.0)` + pub const TOP: UnitPoint = UnitPoint::new(0.5, 0.0); + /// `(1.0, 0.0)` + pub const TOP_RIGHT: UnitPoint = UnitPoint::new(1.0, 0.0); + /// `(0.0, 0.5)` + pub const LEFT: UnitPoint = UnitPoint::new(0.0, 0.5); + /// `(0.5, 0.5)` + pub const CENTER: UnitPoint = UnitPoint::new(0.5, 0.5); + /// `(1.0, 0.5)` + pub const RIGHT: UnitPoint = UnitPoint::new(1.0, 0.5); + /// `(0.0, 1.0)` + pub const BOTTOM_LEFT: UnitPoint = UnitPoint::new(0.0, 1.0); + /// `(0.5, 1.0)` + pub const BOTTOM: UnitPoint = UnitPoint::new(0.5, 1.0); + /// `(1.0, 1.0)` + pub const BOTTOM_RIGHT: UnitPoint = UnitPoint::new(1.0, 1.0); + + /// Create a new UnitPoint. + /// + /// The `u` and `v` coordinates describe the point, with (0.0, 0.0) being + /// the top-left, and (1.0, 1.0) being the bottom-right. + pub const fn new(u: f64, v: f64) -> UnitPoint { + UnitPoint { u, v } + } + + /// Given a rectangle, resolve the point within the rectangle. + pub fn resolve(self, rect: Rect) -> kurbo::Point { + kurbo::Point::new( + rect.x0 + self.u * (rect.x1 - rect.x0), + rect.y0 + self.v * (rect.y1 - rect.y0), + ) + } +} + +pub fn fill_lin_gradient( + scene: &mut Scene, + path: &impl Shape, + stops: impl ColorStopsSource, + start: UnitPoint, + end: UnitPoint, +) { + let rect = path.bounding_box(); + let brush = Gradient::new_linear(start.resolve(rect), end.resolve(rect)).with_stops(stops); + scene.fill(Fill::NonZero, Affine::IDENTITY, &brush, None, path); +} + +pub fn fill_color(scene: &mut Scene, path: &impl Shape, color: Color) { + scene.fill(Fill::NonZero, Affine::IDENTITY, color, None, path); +} diff --git a/src/platform/win_handler.rs b/src/platform/win_handler.rs index 7012f3b1..516676e2 100644 --- a/src/platform/win_handler.rs +++ b/src/platform/win_handler.rs @@ -6,6 +6,8 @@ use std::any::Any; +use druid_shell::kurbo::Size; +use druid_shell::piet::Piet; use druid_shell::text::InputHandler; use druid_shell::{ AppHandler, FileDialogToken, FileInfo, IdleToken, KeyEvent, MouseEvent, Region, Scale, @@ -13,8 +15,6 @@ use druid_shell::{ }; use crate::app_root::AppRoot; -use crate::kurbo::Size; -use crate::piet::Piet; use crate::{command as sys_cmd, Event, InternalEvent, Selector, WindowId}; pub(crate) const RUN_COMMANDS_TOKEN: IdleToken = IdleToken::new(1); @@ -111,12 +111,12 @@ impl WinHandler for MasonryWinHandler { self.app_state.prepare_paint(self.window_id); } - fn paint(&mut self, piet: &mut Piet, region: &Region) { - self.app_state.paint(self.window_id, piet, region); + fn paint(&mut self, piet: &mut Piet, _region: &Region) { + self.app_state.paint(self.window_id, piet); } fn size(&mut self, size: Size) { - let event = Event::WindowSize(size); + let event = Event::WindowSize((size.width, size.height).into()); self.app_state.handle_event(event, self.window_id); } diff --git a/src/platform/window_description.rs b/src/platform/window_description.rs index f86938c1..88da82cd 100644 --- a/src/platform/window_description.rs +++ b/src/platform/window_description.rs @@ -284,13 +284,13 @@ impl WindowConfig { } if let Some(size) = self.size { - builder.set_size(size); + builder.set_size((size.width, size.height).into()); } else if let WindowSizePolicy::Content = self.size_policy { - builder.set_size(Size::new(0., 0.)); + builder.set_size((0., 0.).into()); } if let Some(position) = self.position { - builder.set_position(position); + builder.set_position((position.x, position.y).into()); } if let Some(transparent) = self.transparent { @@ -306,7 +306,7 @@ impl WindowConfig { } if let Some(min_size) = self.min_size { - builder.set_min_size(min_size); + builder.set_min_size((min_size.width, min_size.height).into()); } } @@ -321,14 +321,14 @@ impl WindowConfig { } if let Some(size) = self.size { - win_handle.set_size(size); + win_handle.set_size((size.width, size.height)); } // Can't apply min size currently as window handle // does not support it. if let Some(position) = self.position { - win_handle.set_position(position); + win_handle.set_position((position.x, position.y)); } // TODO - set_level ? diff --git a/src/testing/harness.rs b/src/testing/harness.rs index f3eb008b..5642a6df 100644 --- a/src/testing/harness.rs +++ b/src/testing/harness.rs @@ -3,17 +3,25 @@ // details. //! Tools and infrastructure for testing widgets. +#![warn(unused)] use std::collections::{HashMap, VecDeque}; -use std::sync::Arc; +use std::num::NonZeroUsize; +pub use druid_shell::RawMods; use druid_shell::{KeyEvent, Modifiers, MouseButton, MouseButtons}; -pub use druid_shell::{RawMods, Region}; use image::io::Reader as ImageReader; +use image::RgbaImage; use instant::Duration; use shell::text::Selection; - -use super::screenshots::{get_image_diff, get_rgba_image}; +use vello::util::RenderContext; +use vello::{block_on_wgpu, RendererOptions, Scene}; +use wgpu::{ + BufferDescriptor, BufferUsages, CommandEncoderDescriptor, Extent3d, ImageCopyBuffer, + TextureDescriptor, TextureFormat, TextureUsages, +}; + +use super::screenshots::get_image_diff; use super::snapshot_utils::get_cargo_workspace; use super::MockTimerQueue; use crate::action::{Action, ActionQueue}; @@ -22,13 +30,16 @@ use crate::command::CommandQueue; use crate::contexts::GlobalPassCtx; use crate::debug_logger::DebugLogger; use crate::ext_event::ExtEventQueue; -use crate::piet::{BitmapTarget, Device, ImageFormat, Piet}; use crate::widget::{StoreInWidgetMut, WidgetMut, WidgetRef}; use crate::*; -/// Default screen size for tests. +// TODO - Get shorter names +/// Default canvas size for tests. pub const HARNESS_DEFAULT_SIZE: Size = Size::new(400., 400.); +/// Default background color for tests. +pub const HARNESS_DEFAULT_BACKGROUND_COLOR: Color = Color::rgb8(0x29, 0x29, 0x29); + /// A safe headless environment to test widgets in. /// /// `TestHarness` is a type that simulates an [`AppRoot`](crate::AppRoot) @@ -113,11 +124,11 @@ pub const HARNESS_DEFAULT_SIZE: Size = Size::new(400., 400.); /// /// # simple_button(); /// ``` -// TODO - Fix examples pub struct TestHarness { mock_app: MockAppRoot, mouse_state: MouseEvent, window_size: Size, + background_color: Color, } /// Assert a snapshot of a rendered frame of your app. @@ -156,12 +167,19 @@ impl TestHarness { /// Builds harness with given root widget. /// /// Window size will be [`HARNESS_DEFAULT_SIZE`]. + /// Background color will be [`HARNESS_DEFAULT_BACKGROUND_COLOR`]. pub fn create(root: impl Widget) -> Self { - Self::create_with_size(root, HARNESS_DEFAULT_SIZE) + Self::create_with(root, HARNESS_DEFAULT_SIZE, HARNESS_DEFAULT_BACKGROUND_COLOR) } + // TODO - Remove /// Builds harness with given root widget and window size. pub fn create_with_size(root: impl Widget, window_size: Size) -> Self { + Self::create_with(root, window_size, HARNESS_DEFAULT_BACKGROUND_COLOR) + } + + /// Builds harness with given root widget, canvas size and background color. + pub fn create_with(root: impl Widget, window_size: Size, background_color: Color) -> Self { //let ext_host = ExtEventHost::default(); //let ext_handle = ext_host.make_sink(); @@ -199,6 +217,7 @@ impl TestHarness { }, mouse_state, window_size, + background_color, }; // verify that all widgets are marked as having children_changed @@ -236,50 +255,109 @@ impl TestHarness { // TODO - this might be too coarse if self.root_widget().state().needs_layout { self.mock_app.layout(); - *self.window_mut().invalid_mut() = Region::from(self.window_size.to_rect()); } } - fn render_to(&mut self, render_target: &mut BitmapTarget) { - /// A way to clean up resources when our render context goes out of - /// scope, even during a panic. - pub struct RenderContextGuard<'a>(Piet<'a>); - - impl Drop for RenderContextGuard<'_> { - fn drop(&mut self) { - // We need to call finish even if a test assert failed - if let Err(err) = self.0.finish() { - // We can't panic, because we might already be panicking - tracing::error!("piet finish failed: {}", err); - } - } - } + // TODO - We add way too many dependencies in this code + // TODO - Should be async? + /// Create a bitmap (an array of pixels), paint the window and return the bitmap as an 8-bits-per-channel RGB image. + pub fn render(&mut self) -> RgbaImage { + let mut context = + RenderContext::new().expect("Got non-Send/Sync error from creating render context"); + let device_id = + pollster::block_on(context.device(None)).expect("No compatible device found"); + let device_handle = &mut context.devices[device_id]; + let device = &device_handle.device; + let queue = &device_handle.queue; + let mut renderer = vello::Renderer::new( + device, + RendererOptions { + surface_format: None, + // TODO - Examine this value + use_cpu: true, + num_init_threads: NonZeroUsize::new(1), + // TODO - Examine this value + antialiasing_support: vello::AaSupport::area_only(), + }, + ) + .expect("Got non-Send/Sync error from creating renderer"); - let mut piet = RenderContextGuard(render_target.render_context()); + let mut scene = Scene::new(); + self.mock_app.paint_region(&mut scene); - // FIXME - this doesn't make sense given we might render to a fresh surface - let invalid = std::mem::replace(self.window_mut().invalid_mut(), Region::EMPTY); - self.mock_app.paint_region(&mut piet.0, &invalid); - } + // TODO - fix window_size + let (width, height) = ( + self.window_size.width as u32, + self.window_size.height as u32, + ); + let render_params = vello::RenderParams { + // TODO - Parameterize + base_color: self.background_color, + width, + height, + antialiasing_method: vello::AaConfig::Area, + }; - /// Create a Piet bitmap render context (an array of pixels), paint the - /// window and return the bitmap. - pub fn render(&mut self) -> Arc<[u8]> { - let mut device = Device::new().expect("harness failed to get device"); - let mut render_target = device - .bitmap_target( - self.window_size.width as usize, - self.window_size.height as usize, - 1.0, - ) - .expect("failed to create bitmap_target"); - - self.render_to(&mut render_target); - - render_target - .to_image_buf(ImageFormat::RgbaPremul) - .unwrap() - .raw_pixels_shared() + let size = Extent3d { + width, + height, + depth_or_array_layers: 1, + }; + let target = device.create_texture(&TextureDescriptor { + label: Some("Target texture"), + size, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: TextureFormat::Rgba8Unorm, + usage: TextureUsages::STORAGE_BINDING | TextureUsages::COPY_SRC, + view_formats: &[], + }); + let view = target.create_view(&wgpu::TextureViewDescriptor::default()); + renderer + .render_to_texture(device, queue, &scene, &view, &render_params) + .expect("Got non-Send/Sync error from rendering"); + let padded_byte_width = (width * 4).next_multiple_of(256); + let buffer_size = padded_byte_width as u64 * height as u64; + let buffer = device.create_buffer(&BufferDescriptor { + label: Some("val"), + size: buffer_size, + usage: BufferUsages::MAP_READ | BufferUsages::COPY_DST, + mapped_at_creation: false, + }); + let mut encoder = device.create_command_encoder(&CommandEncoderDescriptor { + label: Some("Copy out buffer"), + }); + encoder.copy_texture_to_buffer( + target.as_image_copy(), + ImageCopyBuffer { + buffer: &buffer, + layout: wgpu::ImageDataLayout { + offset: 0, + bytes_per_row: Some(padded_byte_width), + rows_per_image: None, + }, + }, + size, + ); + + queue.submit([encoder.finish()]); + let buf_slice = buffer.slice(..); + + let (sender, receiver) = futures_intrusive::channel::shared::oneshot_channel(); + buf_slice.map_async(wgpu::MapMode::Read, move |v| sender.send(v).unwrap()); + let recv_result = block_on_wgpu(device, receiver.receive()).expect("channel was closed"); + recv_result.expect("failed to map buffer"); + + let data = buf_slice.get_mapped_range(); + let mut result_unpadded = + Vec::::with_capacity((width * height * 4).try_into().unwrap()); + for row in 0..height { + let start = (row * padded_byte_width).try_into().unwrap(); + result_unpadded.extend(&data[start..start + (width * 4) as usize]); + } + + RgbaImage::from_vec(width, height, result_unpadded).expect("failed to create image") } // --- Event helpers --- @@ -546,6 +624,8 @@ impl TestHarness { test_module_path: &str, test_name: &str, ) { + let new_image = self.render(); + if option_env!("SKIP_RENDER_SNAPSHOTS").is_some() { // FIXME - This is a terrible, awful hack. // We need a way to skip render snapshots on CI and locally @@ -554,19 +634,6 @@ impl TestHarness { return; } - let mut device = Device::new().expect("harness failed to get device"); - let mut render_target = device - .bitmap_target( - self.window_size.width as usize, - self.window_size.height as usize, - 1.0, - ) - .expect("failed to create bitmap_target"); - - self.render_to(&mut render_target); - - let new_image = get_rgba_image(&mut render_target, self.window_size); - let workspace_path = get_cargo_workspace(manifest_dir); let test_file_path_abs = workspace_path.join(test_file_path); let folder_path = test_file_path_abs.parent().unwrap(); @@ -646,10 +713,9 @@ impl MockAppRoot { ); } - fn paint_region(&mut self, piet: &mut Piet, invalid: &Region) { + fn paint_region(&mut self, scene: &mut Scene) { self.window.do_paint( - piet, - invalid, + scene, &mut self.debug_logger, &mut self.command_queue, &mut self.action_queue, diff --git a/src/testing/helper_widgets.rs b/src/testing/helper_widgets.rs index d59738a8..c99a3b26 100644 --- a/src/testing/helper_widgets.rs +++ b/src/testing/helper_widgets.rs @@ -16,6 +16,7 @@ use std::collections::VecDeque; use std::rc::Rc; use smallvec::SmallVec; +use vello::Scene; use crate::widget::{SizedBox, WidgetRef}; use crate::*; @@ -24,7 +25,7 @@ pub type EventFn = dyn FnMut(&mut S, &mut EventCtx, &Event); pub type StatusChangeFn = dyn FnMut(&mut S, &mut LifeCycleCtx, &StatusChange); pub type LifeCycleFn = dyn FnMut(&mut S, &mut LifeCycleCtx, &LifeCycle); pub type LayoutFn = dyn FnMut(&mut S, &mut LayoutCtx, &BoxConstraints) -> Size; -pub type PaintFn = dyn FnMut(&mut S, &mut PaintCtx); +pub type PaintFn = dyn FnMut(&mut S, &mut PaintCtx, &mut Scene); pub type ChildrenFn = dyn Fn(&S) -> SmallVec<[WidgetRef<'_, dyn Widget>; 16]>; pub const REPLACE_CHILD: Selector = Selector::new("masonry-test.replace-child"); @@ -148,7 +149,7 @@ impl ModularWidget { self } - pub fn paint_fn(mut self, f: impl FnMut(&mut S, &mut PaintCtx) + 'static) -> Self { + pub fn paint_fn(mut self, f: impl FnMut(&mut S, &mut PaintCtx, &mut Scene) + 'static) -> Self { self.paint = Some(Box::new(f)); self } @@ -193,9 +194,9 @@ impl Widget for ModularWidget { .unwrap_or_else(|| Size::new(100., 100.)) } - fn paint(&mut self, ctx: &mut PaintCtx) { + fn paint(&mut self, ctx: &mut PaintCtx, scene: &mut Scene) { if let Some(f) = self.paint.as_mut() { - f(&mut self.state, ctx) + f(&mut self.state, ctx, scene) } } @@ -240,8 +241,8 @@ impl Widget for ReplaceChild { self.child.layout(ctx, bc) } - fn paint(&mut self, ctx: &mut PaintCtx) { - self.child.paint_raw(ctx) + fn paint(&mut self, ctx: &mut PaintCtx, scene: &mut Scene) { + self.child.paint(ctx, scene) } fn children(&self) -> SmallVec<[WidgetRef<'_, dyn Widget>; 16]> { @@ -302,8 +303,8 @@ impl Widget for Recorder { size } - fn paint(&mut self, ctx: &mut PaintCtx) { - self.child.paint(ctx); + fn paint(&mut self, ctx: &mut PaintCtx, scene: &mut Scene) { + self.child.paint(ctx, scene); self.recording.push(Record::Paint) } diff --git a/src/testing/screenshots.rs b/src/testing/screenshots.rs index 2bcbdc40..55658b36 100644 --- a/src/testing/screenshots.rs +++ b/src/testing/screenshots.rs @@ -6,23 +6,6 @@ use image::{GenericImageView as _, RgbaImage}; -use crate::piet::{BitmapTarget, ImageFormat}; -use crate::Size; - -pub(crate) fn get_rgba_image(render_target: &mut BitmapTarget, window_size: Size) -> RgbaImage { - let pixels = render_target - .to_image_buf(ImageFormat::RgbaPremul) - .unwrap() - .raw_pixels_shared(); - - RgbaImage::from_raw( - window_size.width as u32, - window_size.height as u32, - Vec::from(pixels.as_ref()), - ) - .unwrap() -} - pub(crate) fn get_image_diff(ref_image: &RgbaImage, new_image: &RgbaImage) -> Option { let mut is_changed = false; diff --git a/src/theme.rs b/src/theme.rs index e6dc9ab7..67bbfb56 100644 --- a/src/theme.rs +++ b/src/theme.rs @@ -6,8 +6,8 @@ #![allow(missing_docs)] -use crate::piet::{Color, FontFamily, FontStyle, FontWeight}; -use crate::text::FontDescriptor; +use vello::peniko::Color; + use crate::Insets; // Colors are from https://sashat.me/2017/01/11/list-of-20-simple-distinct-colors/ @@ -28,14 +28,14 @@ pub const DISABLED_FOREGROUND_LIGHT: Color = Color::rgb8(0x89, 0x89, 0x89); pub const DISABLED_FOREGROUND_DARK: Color = Color::rgb8(0x6f, 0x6f, 0x6f); pub const BUTTON_DARK: Color = Color::BLACK; pub const BUTTON_LIGHT: Color = Color::rgb8(0x21, 0x21, 0x21); -pub const DISABLED_BUTTON_DARK: Color = Color::grey8(0x28); -pub const DISABLED_BUTTON_LIGHT: Color = Color::grey8(0x38); +pub const DISABLED_BUTTON_DARK: Color = Color::rgb8(0x28, 0x28, 0x28); +pub const DISABLED_BUTTON_LIGHT: Color = Color::rgb8(0x38, 0x38, 0x38); pub const BUTTON_BORDER_RADIUS: f64 = 4.; pub const BUTTON_BORDER_WIDTH: f64 = 2.; pub const BORDER_DARK: Color = Color::rgb8(0x3a, 0x3a, 0x3a); pub const BORDER_LIGHT: Color = Color::rgb8(0xa1, 0xa1, 0xa1); pub const SELECTED_TEXT_BACKGROUND_COLOR: Color = Color::rgb8(0x43, 0x70, 0xA8); -pub const SELECTED_TEXT_INACTIVE_BACKGROUND_COLOR: Color = Color::grey8(0x74); +pub const SELECTED_TEXT_INACTIVE_BACKGROUND_COLOR: Color = Color::rgb8(0x74, 0x74, 0x74); pub const SELECTION_TEXT_COLOR: Color = Color::rgb8(0x00, 0x00, 0x00); pub const CURSOR_COLOR: Color = Color::WHITE; pub const TEXT_SIZE_NORMAL: f64 = 15.0; @@ -58,13 +58,6 @@ pub const SCROLLBAR_EDGE_WIDTH: f64 = 1.; pub const WIDGET_PADDING_VERTICAL: f64 = 10.0; pub const WIDGET_PADDING_HORIZONTAL: f64 = 8.0; pub const WIDGET_CONTROL_COMPONENT_PADDING: f64 = 4.0; -pub const UI_FONT: FontDescriptor = FontDescriptor::new(FontFamily::SYSTEM_UI).with_size(15.0); -pub const UI_FONT_BOLD: FontDescriptor = FontDescriptor::new(FontFamily::SYSTEM_UI) - .with_weight(FontWeight::BOLD) - .with_size(15.0); -pub const UI_FONT_ITALIC: FontDescriptor = FontDescriptor::new(FontFamily::SYSTEM_UI) - .with_style(FontStyle::Italic) - .with_size(15.0); static DEBUG_COLOR: &[Color] = &[ Color::rgb8(230, 25, 75), diff --git a/src/widget/align.rs b/src/widget/align.rs index c0a27ef4..2124557f 100644 --- a/src/widget/align.rs +++ b/src/widget/align.rs @@ -11,11 +11,13 @@ use smallvec::{smallvec, SmallVec}; use tracing::{trace, trace_span, Span}; +use vello::Scene; +use crate::paint_scene_helpers::UnitPoint; use crate::widget::{WidgetPod, WidgetRef}; use crate::{ BoxConstraints, Event, EventCtx, LayoutCtx, LifeCycle, LifeCycleCtx, PaintCtx, Rect, Size, - StatusChange, UnitPoint, Widget, + StatusChange, Widget, }; // TODO - Have child widget type as generic argument @@ -137,8 +139,8 @@ impl Widget for Align { my_size } - fn paint(&mut self, ctx: &mut PaintCtx) { - self.child.paint(ctx); + fn paint(&mut self, ctx: &mut PaintCtx, scene: &mut Scene) { + self.child.paint(ctx, scene); } fn children(&self) -> SmallVec<[WidgetRef<'_, dyn Widget>; 16]> { diff --git a/src/widget/button.rs b/src/widget/button.rs index 8a0e3217..8a0fc0b9 100644 --- a/src/widget/button.rs +++ b/src/widget/button.rs @@ -6,12 +6,16 @@ use smallvec::SmallVec; use tracing::{trace, trace_span, Span}; +use vello::Scene; use crate::action::Action; +#[allow(unused)] +use crate::paint_scene_helpers::UnitPoint; +use crate::paint_scene_helpers::{fill_lin_gradient, stroke}; use crate::widget::{Label, WidgetMut, WidgetPod, WidgetRef}; use crate::{ theme, ArcStr, BoxConstraints, Event, EventCtx, Insets, LayoutCtx, LifeCycle, LifeCycleCtx, - LinearGradient, PaintCtx, RenderContext, Size, StatusChange, UnitPoint, Widget, + PaintCtx, Size, StatusChange, Widget, }; // the minimum padding added to a button. @@ -126,7 +130,7 @@ impl Widget for Button { button_size } - fn paint(&mut self, ctx: &mut PaintCtx) { + fn paint(&mut self, ctx: &mut PaintCtx, scene: &mut Scene) { let is_active = ctx.is_active() && !ctx.is_disabled(); let is_hot = ctx.is_hot(); let size = ctx.size(); @@ -138,23 +142,11 @@ impl Widget for Button { .to_rounded_rect(theme::BUTTON_BORDER_RADIUS); let bg_gradient = if ctx.is_disabled() { - LinearGradient::new( - UnitPoint::TOP, - UnitPoint::BOTTOM, - (theme::DISABLED_BUTTON_LIGHT, theme::DISABLED_BUTTON_DARK), - ) + [theme::DISABLED_BUTTON_LIGHT, theme::DISABLED_BUTTON_DARK] } else if is_active { - LinearGradient::new( - UnitPoint::TOP, - UnitPoint::BOTTOM, - (theme::BUTTON_DARK, theme::BUTTON_LIGHT), - ) + [theme::BUTTON_DARK, theme::BUTTON_LIGHT] } else { - LinearGradient::new( - UnitPoint::TOP, - UnitPoint::BOTTOM, - (theme::BUTTON_LIGHT, theme::BUTTON_DARK), - ) + [theme::BUTTON_LIGHT, theme::BUTTON_DARK] }; let border_color = if is_hot && !ctx.is_disabled() { @@ -163,10 +155,16 @@ impl Widget for Button { theme::BORDER_DARK }; - ctx.stroke(rounded_rect, &border_color, stroke_width); - ctx.fill(rounded_rect, &bg_gradient); + stroke(scene, &rounded_rect, &border_color, stroke_width); + fill_lin_gradient( + scene, + &rounded_rect, + bg_gradient, + UnitPoint::TOP, + UnitPoint::BOTTOM, + ); - self.label.paint(ctx); + self.label.paint(ctx, scene); } fn children(&self) -> SmallVec<[WidgetRef<'_, dyn Widget>; 16]> { diff --git a/src/widget/checkbox.rs b/src/widget/checkbox.rs index 53555eba..371152b0 100644 --- a/src/widget/checkbox.rs +++ b/src/widget/checkbox.rs @@ -4,12 +4,14 @@ //! A checkbox widget. +use kurbo::{Affine, Stroke}; use smallvec::SmallVec; use tracing::{trace, trace_span, Span}; +use vello::Scene; use crate::action::Action; -use crate::kurbo::{BezPath, Size}; -use crate::piet::{LineCap, LineJoin, LinearGradient, RenderContext, StrokeStyle, UnitPoint}; +use crate::kurbo::{BezPath, Cap, Join, Size}; +use crate::paint_scene_helpers::{fill_lin_gradient, stroke, UnitPoint}; use crate::widget::{Label, WidgetMut, WidgetRef}; use crate::{ theme, ArcStr, BoxConstraints, Event, EventCtx, LayoutCtx, LifeCycle, LifeCycleCtx, PaintCtx, @@ -109,7 +111,7 @@ impl Widget for Checkbox { our_size } - fn paint(&mut self, ctx: &mut PaintCtx) { + fn paint(&mut self, ctx: &mut PaintCtx, scene: &mut Scene) { let check_size = theme::BASIC_WIDGET_HEIGHT; let border_width = 1.; @@ -118,22 +120,21 @@ impl Widget for Checkbox { .inset(-border_width / 2.) .to_rounded_rect(2.); - //Paint the background - let background_gradient = LinearGradient::new( + fill_lin_gradient( + scene, + &rect, + [theme::BACKGROUND_LIGHT, theme::BACKGROUND_DARK], UnitPoint::TOP, UnitPoint::BOTTOM, - (theme::BACKGROUND_LIGHT, theme::BACKGROUND_DARK), ); - ctx.fill(rect, &background_gradient); - let border_color = if ctx.is_hot() && !ctx.is_disabled() { theme::BORDER_LIGHT } else { theme::BORDER_DARK }; - ctx.stroke(rect, &border_color, border_width); + stroke(scene, &rect, &border_color, border_width); if self.checked { // Paint the checkmark @@ -142,9 +143,15 @@ impl Widget for Checkbox { path.line_to((8.0, 13.0)); path.line_to((14.0, 5.0)); - let style = StrokeStyle::new() - .line_cap(LineCap::Round) - .line_join(LineJoin::Round); + let style = Stroke { + width: 2.0, + join: Join::Round, + miter_limit: 10.0, + start_cap: Cap::Round, + end_cap: Cap::Round, + dash_pattern: Default::default(), + dash_offset: 0.0, + }; let brush = if ctx.is_disabled() { theme::DISABLED_TEXT_COLOR @@ -152,11 +159,11 @@ impl Widget for Checkbox { theme::TEXT_COLOR }; - ctx.stroke_styled(path, &brush, 2., &style); + scene.stroke(&style, Affine::IDENTITY, brush, None, &path); } // Paint the text label - self.label.paint(ctx); + self.label.paint(ctx, scene); } fn children(&self) -> SmallVec<[WidgetRef<'_, dyn Widget>; 16]> { diff --git a/src/widget/flex.rs b/src/widget/flex.rs index eeb1803d..39eeb27b 100644 --- a/src/widget/flex.rs +++ b/src/widget/flex.rs @@ -4,12 +4,15 @@ //! A widget that arranges its children in a one-dimensional array. -use piet_common::RenderContext; +use kurbo::{Affine, Stroke}; use smallvec::SmallVec; use tracing::{trace, trace_span, Span}; +use vello::peniko::Brush; +use vello::Scene; use crate::kurbo::common::FloatExt; use crate::kurbo::Vec2; +use crate::paint_scene_helpers::stroke; use crate::theme::get_debug_color; use crate::widget::{WidgetMut, WidgetRef}; use crate::{ @@ -686,9 +689,9 @@ impl Widget for Flex { my_size } - fn paint(&mut self, ctx: &mut PaintCtx) { + fn paint(&mut self, ctx: &mut PaintCtx, scene: &mut Scene) { for child in self.children.iter_mut().filter_map(|x| x.widget_mut()) { - child.paint(ctx); + child.paint(ctx, scene); } // paint the baseline if we're debugging layout @@ -696,8 +699,9 @@ impl Widget for Flex { let color = get_debug_color(ctx.widget_id().to_raw()); let my_baseline = ctx.size().height - ctx.widget_state.baseline_offset; let line = crate::kurbo::Line::new((0.0, my_baseline), (ctx.size().width, my_baseline)); - let stroke_style = crate::piet::StrokeStyle::new().dash_pattern(&[4.0, 4.0]); - ctx.stroke_styled(line, &color, 1.0, &stroke_style); + + let stroke_style = Stroke::new(1.0).with_dashes(0., [4.0, 4.0]); + scene.stroke(&stroke_style, Affine::IDENTITY, color, None, &line); } } diff --git a/src/widget/mod.rs b/src/widget/mod.rs index 5b0092a0..692ca75c 100644 --- a/src/widget/mod.rs +++ b/src/widget/mod.rs @@ -153,7 +153,7 @@ impl FillStrat { pub mod prelude { #[doc(hidden)] pub use crate::{ - BoxConstraints, Event, EventCtx, LayoutCtx, LifeCycle, LifeCycleCtx, PaintCtx, - RenderContext, Size, StatusChange, Widget, WidgetId, + BoxConstraints, Event, EventCtx, LayoutCtx, LifeCycle, LifeCycleCtx, PaintCtx, Size, + StatusChange, Widget, WidgetId, }; } diff --git a/src/widget/portal.rs b/src/widget/portal.rs index 30cf1c10..f904f6e0 100644 --- a/src/widget/portal.rs +++ b/src/widget/portal.rs @@ -6,15 +6,18 @@ use std::ops::Range; +use kurbo::Affine; use smallvec::{smallvec, SmallVec}; use tracing::{trace_span, Span}; +use vello::peniko::BlendMode; +use vello::Scene; use crate::kurbo::{Point, Rect, Size, Vec2}; use crate::widget::scroll_bar::SCROLLBAR_MOVED; use crate::widget::{Axis, ScrollBar, StoreInWidgetMut, WidgetMut, WidgetRef}; use crate::{ - BoxConstraints, Event, EventCtx, LayoutCtx, LifeCycle, LifeCycleCtx, PaintCtx, RenderContext, - StatusChange, Widget, WidgetPod, + BoxConstraints, Event, EventCtx, LayoutCtx, LifeCycle, LifeCycleCtx, PaintCtx, StatusChange, + Widget, WidgetPod, }; // TODO - refactor - see issue #15 @@ -345,20 +348,21 @@ impl Widget for Portal { portal_size } - fn paint(&mut self, ctx: &mut PaintCtx) { - // TODO - have ctx.clip also clip the invalidated region + fn paint(&mut self, ctx: &mut PaintCtx, scene: &mut Scene) { + // TODO - also clip the invalidated region let clip_rect = ctx.size().to_rect(); - ctx.clip(clip_rect); - self.child.paint(ctx); + scene.push_layer(BlendMode::default(), 1., Affine::IDENTITY, &clip_rect); + self.child.paint(ctx, scene); + scene.pop_layer(); if self.scrollbar_horizontal_visible { - self.scrollbar_horizontal.paint(ctx); + self.scrollbar_horizontal.paint(ctx, scene); } else { ctx.skip_child(&mut self.scrollbar_horizontal); } if self.scrollbar_vertical_visible { - self.scrollbar_vertical.paint(ctx); + self.scrollbar_vertical.paint(ctx, scene); } else { ctx.skip_child(&mut self.scrollbar_vertical); } diff --git a/src/widget/scroll_bar.rs b/src/widget/scroll_bar.rs index b66c63c5..8ff67e29 100644 --- a/src/widget/scroll_bar.rs +++ b/src/widget/scroll_bar.rs @@ -3,17 +3,18 @@ // details. #![allow(missing_docs)] -#![allow(unused)] -use druid_shell::kurbo::Rect; use smallvec::SmallVec; use tracing::{trace_span, Span}; +use vello::Scene; use super::Axis; +use crate::kurbo::Rect; +use crate::paint_scene_helpers::{fill_color, stroke}; use crate::widget::WidgetRef; use crate::{ theme, BoxConstraints, Event, EventCtx, LayoutCtx, LifeCycle, LifeCycleCtx, PaintCtx, Point, - RenderContext, Selector, Size, StatusChange, Widget, + Selector, Size, StatusChange, Widget, }; // RULES @@ -192,10 +193,7 @@ impl Widget for ScrollBar { .into() } - fn paint(&mut self, ctx: &mut PaintCtx) { - let brush = ctx.render_ctx.solid_brush(theme::SCROLLBAR_COLOR); - let border_brush = ctx.render_ctx.solid_brush(theme::SCROLLBAR_BORDER_COLOR); - + fn paint(&mut self, ctx: &mut PaintCtx, scene: &mut Scene) { let radius = theme::SCROLLBAR_RADIUS; let edge_width = theme::SCROLLBAR_EDGE_WIDTH; let cursor_padding = theme::SCROLLBAR_PAD; @@ -206,9 +204,14 @@ impl Widget for ScrollBar { .get_cursor_rect(ctx.size(), cursor_min_length) .inset((-inset_x, -inset_y)) .to_rounded_rect(radius); - ctx.render_ctx.fill(cursor_rect, &brush); - ctx.render_ctx - .stroke(cursor_rect, &border_brush, edge_width); + + fill_color(scene, &cursor_rect, theme::SCROLLBAR_COLOR); + stroke( + scene, + &cursor_rect, + &theme::SCROLLBAR_BORDER_COLOR, + edge_width, + ); } fn children(&self) -> SmallVec<[WidgetRef<'_, dyn Widget>; 16]> { diff --git a/src/widget/sized_box.rs b/src/widget/sized_box.rs index 7415a22d..94100edf 100644 --- a/src/widget/sized_box.rs +++ b/src/widget/sized_box.rs @@ -6,15 +6,18 @@ use std::f64::INFINITY; +use kurbo::Affine; use smallvec::{smallvec, SmallVec}; use tracing::{trace, trace_span, warn, Span}; +use vello::peniko::{BlendMode, Color, Fill, Gradient}; +use vello::Scene; use crate::kurbo::RoundedRectRadii; -use crate::piet::{Color, FixedGradient, LinearGradient, PaintBrush, RadialGradient}; +use crate::paint_scene_helpers::{fill_color, stroke}; use crate::widget::{WidgetId, WidgetMut, WidgetPod, WidgetRef}; use crate::{ - BoxConstraints, Event, EventCtx, LayoutCtx, LifeCycle, LifeCycleCtx, PaintCtx, Point, - RenderContext, Size, StatusChange, Widget, + BoxConstraints, Event, EventCtx, LayoutCtx, LifeCycle, LifeCycleCtx, PaintCtx, Point, Size, + StatusChange, Widget, }; // FIXME - Improve all doc in this module ASAP. @@ -25,9 +28,7 @@ use crate::{ #[allow(clippy::type_complexity)] pub enum BackgroundBrush { Color(Color), - Linear(LinearGradient), - Radial(RadialGradient), - Fixed(FixedGradient), + Gradient(Gradient), PainterFn(Box), } @@ -335,17 +336,16 @@ impl Widget for SizedBox { size } - fn paint(&mut self, ctx: &mut PaintCtx) { + fn paint(&mut self, ctx: &mut PaintCtx, scene: &mut Scene) { let corner_radius = self.corner_radius; if let Some(background) = self.background.as_mut() { let panel = ctx.size().to_rounded_rect(corner_radius); trace_span!("paint background").in_scope(|| { - ctx.with_save(|ctx| { - ctx.clip(panel); - background.paint(ctx); - }); + scene.push_layer(BlendMode::default(), 1., Affine::IDENTITY, &panel); + background.paint(ctx, scene); + scene.pop_layer(); }); } @@ -356,11 +356,11 @@ impl Widget for SizedBox { .to_rect() .inset(border_width / -2.0) .to_rounded_rect(corner_radius); - ctx.stroke(border_rect, &border.color, border_width); + stroke(scene, &border_rect, &border.color, border_width); }; if let Some(ref mut child) = self.child { - child.paint(ctx); + child.paint(ctx, scene); } } @@ -381,13 +381,17 @@ impl Widget for SizedBox { impl BackgroundBrush { /// Draw this brush into a provided [`PaintCtx`]. - pub fn paint(&mut self, ctx: &mut PaintCtx) { + pub fn paint(&mut self, ctx: &mut PaintCtx, scene: &mut Scene) { let bounds = ctx.size().to_rect(); match self { - Self::Color(color) => ctx.fill(bounds, color), - Self::Linear(grad) => ctx.fill(bounds, grad), - Self::Radial(grad) => ctx.fill(bounds, grad), - Self::Fixed(grad) => ctx.fill(bounds, grad), + Self::Color(color) => fill_color(scene, &bounds, *color), + Self::Gradient(grad) => scene.fill( + Fill::NonZero, + Affine::IDENTITY, + &*grad, + Some(Affine::IDENTITY), + &bounds, + ), Self::PainterFn(painter) => painter(ctx), } } @@ -399,21 +403,9 @@ impl From for BackgroundBrush { } } -impl From for BackgroundBrush { - fn from(src: LinearGradient) -> BackgroundBrush { - BackgroundBrush::Linear(src) - } -} - -impl From for BackgroundBrush { - fn from(src: RadialGradient) -> BackgroundBrush { - BackgroundBrush::Radial(src) - } -} - -impl From for BackgroundBrush { - fn from(src: FixedGradient) -> BackgroundBrush { - BackgroundBrush::Fixed(src) +impl From for BackgroundBrush { + fn from(src: Gradient) -> BackgroundBrush { + BackgroundBrush::Gradient(src) } } @@ -423,17 +415,6 @@ impl From for BackgroundBrush } } -impl From for BackgroundBrush { - fn from(src: PaintBrush) -> BackgroundBrush { - match src { - PaintBrush::Linear(grad) => BackgroundBrush::Linear(grad), - PaintBrush::Radial(grad) => BackgroundBrush::Radial(grad), - PaintBrush::Fixed(grad) => BackgroundBrush::Fixed(grad), - PaintBrush::Color(color) => BackgroundBrush::Color(color), - } - } -} - // --- Tests --- #[cfg(test)] diff --git a/src/widget/spinner.rs b/src/widget/spinner.rs index db40154f..eab231d5 100644 --- a/src/widget/spinner.rs +++ b/src/widget/spinner.rs @@ -6,14 +6,17 @@ use std::f64::consts::PI; +use kurbo::{Affine, Cap, Stroke}; use smallvec::SmallVec; use tracing::trace; +use vello::Scene; use crate::kurbo::Line; +use crate::paint_scene_helpers::stroke; use crate::widget::WidgetRef; use crate::{ theme, BoxConstraints, Color, Event, EventCtx, LayoutCtx, LifeCycle, LifeCycleCtx, PaintCtx, - Point, RenderContext, Size, StatusChange, Vec2, Widget, + Point, Size, StatusChange, Vec2, Widget, }; // TODO - Set color @@ -103,11 +106,14 @@ impl Widget for Spinner { size } - fn paint(&mut self, ctx: &mut PaintCtx) { + fn paint(&mut self, ctx: &mut PaintCtx, scene: &mut Scene) { let t = self.t; let (width, height) = (ctx.size().width, ctx.size().height); let center = Point::new(width / 2.0, height / 2.0); - let (r, g, b, original_alpha) = Color::as_rgba(self.color); + let (r, g, b, original_alpha) = { + let c = self.color; + (c.r, c.g, c.b, c.a) + }; let scale_factor = width.min(height) / 40.0; for step in 1..=12 { @@ -117,12 +123,15 @@ impl Widget for Spinner { let angle = Vec2::from_angle((step / 12.0) * -2.0 * PI); let ambit_start = center + (10.0 * scale_factor * angle); let ambit_end = center + (20.0 * scale_factor * angle); - let color = Color::rgba(r, g, b, fade * original_alpha); + let alpha = (fade * original_alpha as f64) as u8; + let color = Color::rgba8(r, g, b, alpha); - ctx.stroke( - Line::new(ambit_start, ambit_end), + scene.stroke( + &Stroke::new(3.0 * scale_factor).with_caps(Cap::Square), + Affine::IDENTITY, &color, - 3.0 * scale_factor, + None, + &Line::new(ambit_start, ambit_end), ); } } diff --git a/src/widget/split.rs b/src/widget/split.rs index 231aec6d..206500bf 100644 --- a/src/widget/split.rs +++ b/src/widget/split.rs @@ -7,13 +7,15 @@ use druid_shell::Cursor; use smallvec::{smallvec, SmallVec}; use tracing::{trace, trace_span, warn, Span}; +use vello::Scene; use crate::kurbo::Line; +use crate::paint_scene_helpers::{fill_color, stroke}; use crate::widget::flex::Axis; use crate::widget::{WidgetPod, WidgetRef}; use crate::{ theme, BoxConstraints, Color, Event, EventCtx, LayoutCtx, LifeCycle, LifeCycleCtx, PaintCtx, - Point, Rect, RenderContext, Size, StatusChange, Widget, + Point, Rect, Size, StatusChange, Widget, }; // TODO - Have child widget type as generic argument @@ -234,7 +236,7 @@ impl Split { } } - fn paint_solid_bar(&mut self, ctx: &mut PaintCtx) { + fn paint_solid_bar(&mut self, ctx: &mut PaintCtx, scene: &mut Scene) { let size = ctx.size(); let (edge1, edge2) = self.bar_edges(size); let padding = self.bar_padding(); @@ -249,10 +251,10 @@ impl Split { ), }; let splitter_color = self.bar_color(); - ctx.fill(rect, &splitter_color); + fill_color(scene, &rect, splitter_color); } - fn paint_stroked_bar(&mut self, ctx: &mut PaintCtx) { + fn paint_stroked_bar(&mut self, ctx: &mut PaintCtx, scene: &mut Scene) { let size = ctx.size(); // Set the line width to a third of the splitter bar size, // because we'll paint two equal lines at the edges. @@ -283,8 +285,8 @@ impl Split { ), }; let splitter_color = self.bar_color(); - ctx.stroke(line1, &splitter_color, line_width); - ctx.stroke(line2, &splitter_color, line_width); + stroke(scene, &line1, &splitter_color, line_width); + stroke(scene, &line2, &splitter_color, line_width); } } @@ -551,15 +553,15 @@ impl Widget for Split { my_size } - fn paint(&mut self, ctx: &mut PaintCtx) { + fn paint(&mut self, ctx: &mut PaintCtx, scene: &mut Scene) { // TODO - Paint differently if the bar is draggable and hovered. if self.solid { - self.paint_solid_bar(ctx); + self.paint_solid_bar(ctx, scene); } else { - self.paint_stroked_bar(ctx); + self.paint_stroked_bar(ctx, scene); } - self.child1.paint(ctx); - self.child2.paint(ctx); + self.child1.paint(ctx, scene); + self.child2.paint(ctx, scene); } fn children(&self) -> SmallVec<[WidgetRef<'_, dyn Widget>; 16]> { diff --git a/src/widget/tests/invalidation.rs b/src/widget/tests/invalidation.rs deleted file mode 100644 index 1da0215a..00000000 --- a/src/widget/tests/invalidation.rs +++ /dev/null @@ -1,40 +0,0 @@ -// This software is licensed under Apache License 2.0 and distributed on an -// "as-is" basis without warranties of any kind. See the LICENSE file for -// details. - -//! Tests related to propagation of invalid rects. - -use crate::testing::{widget_ids, TestHarness}; -use crate::widget::{Button, Flex}; - -#[test] -fn invalidate_union() { - let [id_child_1, id_child_2] = widget_ids(); - - let widget = Flex::column() - .with_child_id(Button::new("hi"), id_child_1) - .with_child_id(Button::new("there"), id_child_2); - - let mut harness = TestHarness::create(widget); - - // This resets the invalid region. - let _ = harness.render(); - assert!(harness.window().invalid().is_empty()); - - let child1_rect = harness.get_widget(id_child_1).state().layout_rect(); - let child2_rect = harness.get_widget(id_child_2).state().layout_rect(); - harness.mouse_move_to(id_child_1); - assert_eq!(harness.window().invalid().rects(), &[child1_rect]); - - let _ = harness.render(); - assert!(harness.window().invalid().is_empty()); - - harness.mouse_move_to(id_child_2); - assert_eq!( - harness.window().invalid().rects(), - // TODO: this is probably too fragile, because is there any guarantee on the order? - &[child1_rect, child2_rect] - ); -} - -// TODO: Add a test with scrolling/viewport diff --git a/src/widget/tests/layout.rs b/src/widget/tests/layout.rs index c483ff56..0a422a87 100644 --- a/src/widget/tests/layout.rs +++ b/src/widget/tests/layout.rs @@ -6,8 +6,7 @@ #![allow(unused_imports)] -use druid_shell::kurbo::{Insets, Size}; - +use crate::kurbo::{Insets, Size}; use crate::testing::{widget_ids, ModularWidget, TestHarness, TestWidgetExt}; use crate::widget::{Flex, SizedBox}; diff --git a/src/widget/tests/lifecycle_basic.rs b/src/widget/tests/lifecycle_basic.rs index 81a39165..399c3542 100644 --- a/src/widget/tests/lifecycle_basic.rs +++ b/src/widget/tests/lifecycle_basic.rs @@ -21,6 +21,8 @@ fn app_creation() { assert_debug_snapshot!(record); } +// FIXME - Need to figure out this test +#[ignore] /// Test that lifecycle events are sent correctly to a child added during event /// handling #[test] diff --git a/src/widget/tests/mod.rs b/src/widget/tests/mod.rs index 7025c8d3..ffad7c62 100644 --- a/src/widget/tests/mod.rs +++ b/src/widget/tests/mod.rs @@ -4,7 +4,6 @@ mod aspect_ratio; mod event_notification; -mod invalidation; mod layout; mod lifecycle_basic; mod lifecycle_disable; diff --git a/src/widget/tests/safety_rails.rs b/src/widget/tests/safety_rails.rs index 027bfe7c..9c997766 100644 --- a/src/widget/tests/safety_rails.rs +++ b/src/widget/tests/safety_rails.rs @@ -20,8 +20,8 @@ fn make_parent_widget(child: W) -> ModularWidget> { ctx.place_child(child, Point::ZERO); size }) - .paint_fn(move |child, ctx| { - child.paint(ctx); + .paint_fn(move |child, ctx, scene| { + child.paint(ctx, scene); }) .children_fn(|child| smallvec![child.as_dyn()]) } @@ -89,7 +89,7 @@ fn check_forget_to_call_place_child() { #[should_panic(expected = "not visited in method paint")] #[test] fn check_forget_to_recurse_paint() { - let widget = make_parent_widget(Flex::row()).paint_fn(|_child, _ctx| { + let widget = make_parent_widget(Flex::row()).paint_fn(|_child, _ctx, _scene| { // We forget to call child.paint(); }); @@ -172,7 +172,7 @@ fn allow_non_recurse_stashed_paint() { ctx.set_stashed(child, true); }) .layout_fn(|_child, _ctx, _bc| Size::ZERO) - .paint_fn(|_child, _ctx| { + .paint_fn(|_child, _ctx, _scene| { // We don't call child.paint(); }); @@ -213,9 +213,9 @@ fn check_forget_children_changed() { Size::ZERO } }) - .paint_fn(|child, ctx| { + .paint_fn(|child, ctx, scene| { if let Some(child) = child { - child.paint(ctx); + child.paint(ctx, scene); } }) .children_fn(|child| { @@ -272,8 +272,8 @@ fn check_recurse_layout_twice() { #[should_panic] #[test] fn check_recurse_paint_twice() { - let widget = make_parent_widget(Flex::row()).paint_fn(|child, ctx| { - child.paint(ctx); + let widget = make_parent_widget(Flex::row()).paint_fn(|child, ctx, scene| { + child.paint(ctx, scene); }); let mut harness = TestHarness::create(widget); @@ -307,8 +307,8 @@ fn check_paint_stashed() { ctx.set_stashed(child, true); }) .layout_fn(|_child, _ctx, _bc| Size::ZERO) - .paint_fn(|child, ctx| { - child.paint(ctx); + .paint_fn(|child, ctx, scene| { + child.paint(ctx, scene); }); let mut harness = TestHarness::create(widget); diff --git a/src/widget/widget.rs b/src/widget/widget.rs index 156ce737..ec235093 100644 --- a/src/widget/widget.rs +++ b/src/widget/widget.rs @@ -8,6 +8,7 @@ use std::ops::{Deref, DerefMut}; use smallvec::SmallVec; use tracing::{trace_span, Span}; +use vello::Scene; use crate::event::StatusChange; use crate::widget::WidgetRef; @@ -109,7 +110,7 @@ pub trait Widget: AsAny { /// children, or annotations (for example, scrollbars) by painting /// afterwards. In addition, they can apply masks and transforms on /// the render context, which is especially useful for scrolling. - fn paint(&mut self, ctx: &mut PaintCtx); + fn paint(&mut self, ctx: &mut PaintCtx, scene: &mut Scene); /// Return references to this widget's children. /// @@ -364,8 +365,8 @@ impl Widget for Box { self.deref_mut().layout(ctx, bc) } - fn paint(&mut self, ctx: &mut PaintCtx) { - self.deref_mut().paint(ctx); + fn paint(&mut self, ctx: &mut PaintCtx, scene: &mut Scene) { + self.deref_mut().paint(ctx, scene); } fn type_name(&self) -> &'static str { diff --git a/src/widget/widget_pod.rs b/src/widget/widget_pod.rs index abcaeb57..fba306b8 100644 --- a/src/widget/widget_pod.rs +++ b/src/widget/widget_pod.rs @@ -5,16 +5,16 @@ use std::collections::VecDeque; use tracing::{info_span, trace, warn}; +use vello::Scene; use crate::contexts::GlobalPassCtx; use crate::kurbo::{Affine, Insets, Point, Rect, Shape, Size}; -use crate::text::TextLayout; +use crate::paint_scene_helpers::stroke; use crate::theme::get_debug_color; use crate::widget::{FocusChange, WidgetRef, WidgetState}; use crate::{ - ArcStr, BoxConstraints, Color, Event, EventCtx, InternalEvent, InternalLifeCycle, LayoutCtx, - LifeCycle, LifeCycleCtx, Notification, PaintCtx, RenderContext, StatusChange, Target, Widget, - WidgetId, + BoxConstraints, Event, EventCtx, InternalEvent, InternalLifeCycle, LayoutCtx, LifeCycle, + LifeCycleCtx, Notification, PaintCtx, StatusChange, Target, Widget, WidgetId, }; // TODO - rewrite links in doc @@ -30,8 +30,7 @@ use crate::{ pub struct WidgetPod { pub(crate) state: WidgetState, pub(crate) inner: W, - // stashed layout so we don't recompute this when debugging - pub(crate) debug_widget_text: TextLayout, + pub(crate) fragment: Scene, } // --- @@ -54,7 +53,7 @@ impl WidgetPod { WidgetPod { state, inner, - debug_widget_text: TextLayout::new(), + fragment: Scene::new(), } } @@ -1010,73 +1009,11 @@ impl WidgetPod { // --- PAINT --- - // TODO - make non-pub? - /// Paint a child widget. - /// - /// Generally called by container widgets as part of their [`Widget::paint`] - /// method. - /// - /// Note that this method does not apply the offset of the layout rect. - /// If that is desired, use [`paint`] instead. - /// - /// [`layout`]: trait.Widget.html#tymethod.layout - /// [`Widget::paint`]: trait.Widget.html#tymethod.paint - /// [`paint`]: #method.paint - pub fn paint_raw(&mut self, ctx: &mut PaintCtx) { - self.mark_as_visited(); - - // we need to do this before we borrow from self - if ctx.debug_widget_id { - self.make_widget_id_layout_if_needed(self.state.id, ctx); - } - - self.call_widget_method_with_checks("paint", |widget_pod| { - // widget_pod is a reborrow of `self` - - let mut inner_ctx = PaintCtx { - global_state: ctx.global_state, - widget_state: &widget_pod.state, - render_ctx: ctx.render_ctx, - z_ops: Vec::new(), - region: ctx.region.clone(), - depth: ctx.depth, - debug_paint: ctx.debug_paint, - debug_widget: ctx.debug_widget, - debug_widget_id: ctx.debug_widget_id, - }; - widget_pod.inner.paint(&mut inner_ctx); - - let debug_ids = widget_pod.state.is_hot && ctx.debug_widget_id; - if debug_ids { - // this also draws layout bounds - widget_pod.debug_paint_widget_ids(&mut inner_ctx); - } - - if !debug_ids && ctx.debug_paint { - widget_pod.debug_paint_layout_bounds(&mut inner_ctx); - } - - ctx.z_ops.append(&mut inner_ctx.z_ops); - }); - } - /// Paint the widget, translating it by the origin of its layout rectangle. /// /// This will recursively paint widgets, stopping if a widget's layout /// rect is outside of the currently visible region. - pub fn paint(&mut self, parent_ctx: &mut PaintCtx) { - self.paint_impl(parent_ctx, false) - } - - // TODO - remove - /// Paint the widget, even if its paint rect is outside of the currently - /// visible region. - pub fn paint_always(&mut self, parent_ctx: &mut PaintCtx) { - self.paint_impl(parent_ctx, true) - } - - /// Shared implementation that can skip drawing non-visible content. - fn paint_impl(&mut self, parent_ctx: &mut PaintCtx, paint_if_not_visible: bool) { + pub fn paint(&mut self, parent_ctx: &mut PaintCtx, scene: &mut Scene) { let _span = self.inner.make_trace_span().entered(); if self.state.is_stashed { @@ -1092,63 +1029,42 @@ impl WidgetPod { self.mark_as_visited(); self.check_initialized("paint"); - if !paint_if_not_visible && !parent_ctx.region().intersects(self.state.paint_rect()) { - return; - } + // TODO + let needs_paint = true; - parent_ctx.with_save(|ctx| { - let layout_origin = self.layout_rect().origin().to_vec2(); - ctx.transform(Affine::translate(layout_origin)); - let mut visible = ctx.region().clone(); - visible.intersect_with(self.state.paint_rect()); - visible -= layout_origin; - ctx.with_child_ctx(visible, |ctx| self.paint_raw(ctx)); - }); - } + if needs_paint { + self.call_widget_method_with_checks("paint", |widget_pod| { + // TODO - Handle invalidation regions + let mut child_ctx = PaintCtx { + global_state: parent_ctx.global_state, + widget_state: &widget_pod.state, + depth: parent_ctx.depth + 1, + debug_paint: parent_ctx.debug_paint, + debug_widget: parent_ctx.debug_widget, + }; - // FIXME - Add snapshot test for debug_widget_text + widget_pod.fragment.reset(); + widget_pod + .inner + .paint(&mut child_ctx, &mut widget_pod.fragment); - fn make_widget_id_layout_if_needed(&mut self, id: WidgetId, ctx: &mut PaintCtx) { - if self.debug_widget_text.needs_rebuild() { - // switch text color based on background, this is meh and that's okay - let border_color = get_debug_color(id.to_raw()); - let (r, g, b, _) = border_color.as_rgba8(); - let avg = (r as u32 + g as u32 + b as u32) / 3; - let text_color = if avg < 128 { - Color::WHITE - } else { - Color::BLACK - }; - let id_string = id.to_raw().to_string(); - self.debug_widget_text.set_text(id_string.into()); - self.debug_widget_text.set_text_size(10.0); - self.debug_widget_text.set_text_color(text_color); - self.debug_widget_text.rebuild_if_needed(ctx.text()); + if parent_ctx.debug_paint { + widget_pod.debug_paint_layout_bounds(widget_pod.state.size); + } + }); } - } - fn debug_paint_widget_ids(&self, ctx: &mut PaintCtx) { - // we clone because we need to move it for paint_with_z_index - let text = self.debug_widget_text.clone(); - let text_size = text.size(); - let origin = ctx.size().to_vec2() - text_size.to_vec2(); - let border_color = get_debug_color(ctx.widget_id().to_raw()); - self.debug_paint_layout_bounds(ctx); - - ctx.paint_with_z_index(ctx.depth(), move |ctx| { - let origin = Point::new(origin.x.max(0.0), origin.y.max(0.0)); - let text_rect = Rect::from_origin_size(origin, text_size); - ctx.fill(text_rect, &border_color); - text.draw(ctx, origin); - }) + let transform = Affine::translate(self.state.origin.to_vec2()); + scene.append(&self.fragment, Some(transform)); } - fn debug_paint_layout_bounds(&self, ctx: &mut PaintCtx) { + fn debug_paint_layout_bounds(&mut self, size: Size) { const BORDER_WIDTH: f64 = 1.0; - let rect = ctx.size().to_rect().inset(BORDER_WIDTH / -2.0); + let rect = size.to_rect().inset(BORDER_WIDTH / -2.0); let id = self.id().to_raw(); let color = get_debug_color(id); - ctx.stroke(rect, &color, BORDER_WIDTH); + let scene = &mut self.fragment; + stroke(scene, &rect, &color, BORDER_WIDTH); } } diff --git a/src/widget/widget_state.rs b/src/widget/widget_state.rs index b1bb817c..22f6dc91 100644 --- a/src/widget/widget_state.rs +++ b/src/widget/widget_state.rs @@ -10,7 +10,7 @@ use druid_shell::{Cursor, Region}; use crate::bloom::Bloom; use crate::kurbo::{Insets, Point, Rect, Size}; -use crate::text::TextFieldRegistration; +use crate::text_helpers::TextFieldRegistration; use crate::widget::{CursorChange, FocusChange}; use crate::WidgetId; @@ -221,17 +221,6 @@ impl WidgetState { .with_origin(Point::ORIGIN) .inset(self.paint_insets); let offset = child_state.layout_rect().origin().to_vec2(); - for &rect in child_state.invalid.rects() { - let rect = (rect + offset).intersect(clip); - if rect.area() != 0.0 { - self.invalid.add_rect(rect); - } - } - // Clearing the invalid rects here is less fragile than doing it while painting. The - // problem is that widgets (for example, Either) might choose not to paint certain - // invisible children, and we shouldn't allow these invisible children to accumulate - // invalid rects. - child_state.invalid.clear(); self.needs_layout |= child_state.needs_layout; self.needs_window_origin |= child_state.needs_window_origin; From 8c9110481c9ff06f2f354b1114f516f0178dfd98 Mon Sep 17 00:00:00 2001 From: Olivier FAURE Date: Tue, 2 Apr 2024 18:57:12 +0200 Subject: [PATCH 02/21] TMP 2 --- examples/calc.rs | 5 +- examples/custom_widget.rs | 5 +- examples/promise_button.rs | 8 +- src/app_root.rs | 8 +- src/lib.rs | 2 + src/text_helpers.rs | 59 +++++ src/widget/image.rs | 16 +- src/widget/label.rs | 215 +++++++++--------- src/widget/mod.rs | 3 +- ...ts__lifecycle_basic__adding_child.snap.new | 21 ++ src/widget/textbox.rs | 11 +- 11 files changed, 224 insertions(+), 129 deletions(-) create mode 100644 src/text_helpers.rs create mode 100644 src/widget/tests/snapshots/masonry__widget__tests__lifecycle_basic__adding_child.snap.new diff --git a/examples/calc.rs b/examples/calc.rs index 72be4bc3..00eb5959 100644 --- a/examples/calc.rs +++ b/examples/calc.rs @@ -16,6 +16,7 @@ use masonry::{ }; use smallvec::{smallvec, SmallVec}; use tracing::{trace, trace_span, Span}; +use vello::Scene; #[derive(Clone)] struct CalcState { @@ -188,8 +189,8 @@ impl Widget for CalcButton { size } - fn paint(&mut self, ctx: &mut PaintCtx) { - self.inner.paint(ctx); + fn paint(&mut self, ctx: &mut PaintCtx, scene: &mut Scene) { + self.inner.paint(ctx, scene); } fn children(&self) -> SmallVec<[WidgetRef<'_, dyn Widget>; 16]> { diff --git a/examples/custom_widget.rs b/examples/custom_widget.rs index 2e8e27ba..85b13b40 100644 --- a/examples/custom_widget.rs +++ b/examples/custom_widget.rs @@ -14,8 +14,7 @@ use masonry::text::{FontDescriptor, TextLayout}; use masonry::widget::WidgetRef; use masonry::{ Affine, AppLauncher, BoxConstraints, Color, Event, EventCtx, LayoutCtx, LifeCycle, - LifeCycleCtx, PaintCtx, Point, Rect, RenderContext, Size, StatusChange, Widget, - WindowDescription, + LifeCycleCtx, PaintCtx, Point, Rect, Size, StatusChange, Widget, WindowDescription, }; use smallvec::SmallVec; use tracing::{trace_span, Span}; @@ -55,7 +54,7 @@ impl Widget for CustomWidget { // The paint method gets called last, after an event flow. // It goes event -> update -> layout -> paint, and each method can influence the next. // Basically, anything that changes the appearance of a widget causes a paint. - fn paint(&mut self, ctx: &mut PaintCtx) { + fn paint(&mut self, ctx: &mut PaintCtx, scene: &mut Scene) { // Clear the whole widget with the color of your choice // (ctx.size() returns the size of the layout rect we're painting in) // Note: ctx also has a `clear` method, but that clears the whole context, diff --git a/examples/promise_button.rs b/examples/promise_button.rs index c7a51475..1826481e 100644 --- a/examples/promise_button.rs +++ b/examples/promise_button.rs @@ -11,13 +11,15 @@ use std::{thread, time}; use druid_shell::Cursor; use masonry::kurbo::Vec2; use masonry::promise::PromiseToken; -use masonry::text::TextLayout; use masonry::widget::prelude::*; use masonry::widget::WidgetRef; use masonry::{AppLauncher, WindowDescription}; use masonry::{ArcStr, Color, Point}; +use parley::Layout; use smallvec::SmallVec; use tracing::{trace, trace_span, Span}; +use vello::peniko::Brush; +use vello::Scene; // added padding between the edges of the widget and the text. const LABEL_X_PADDING: f64 = 2.0; @@ -25,6 +27,7 @@ const LABEL_X_PADDING: f64 = 2.0; pub struct PromiseButton { value: u32, text_layout: TextLayout, + text_layout2: Option>, line_break_mode: LineBreaking, promise_token: PromiseToken, @@ -53,6 +56,7 @@ impl PromiseButton { Self { value: 0, text_layout, + text_layout2: None, line_break_mode: LineBreaking::Overflow, promise_token: PromiseToken::empty(), default_text_color: masonry::theme::TEXT_COLOR, @@ -133,7 +137,7 @@ impl Widget for PromiseButton { size } - fn paint(&mut self, ctx: &mut PaintCtx) { + fn paint(&mut self, ctx: &mut PaintCtx, scene: &mut Scene) { let origin = Point::new(LABEL_X_PADDING, 0.0); let label_size = ctx.size(); diff --git a/src/app_root.rs b/src/app_root.rs index e3339968..a137a2dc 100644 --- a/src/app_root.rs +++ b/src/app_root.rs @@ -1238,9 +1238,13 @@ impl WindowRoot { if let WindowSizePolicy::Content = self.size_policy { let insets = self.handle.content_insets(); + // FIXME - This code is extremely tangled because we're currently using + // two versions of Kurbo. This should be fixed as soon as they're unified again. + let content_size = + druid_shell::kurbo::Size::new(content_size.width, content_size.height); let full_size = (content_size.to_rect() + insets).size(); - if self.size != full_size { - self.size = full_size; + if (self.size.width, self.size.height) != (full_size.width, full_size.height) { + self.size = (full_size.width, full_size.height).into(); self.handle.set_size(full_size) } } diff --git a/src/lib.rs b/src/lib.rs index fd6dd169..b5b3934d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -88,6 +88,8 @@ #![allow(clippy::bool_assert_comparison)] #![cfg_attr(docsrs, feature(doc_cfg))] #![cfg_attr(not(debug_assertions), allow(unused))] +#![allow(unused)] +#![allow(missing_docs)] // TODO - Add logo diff --git a/src/text_helpers.rs b/src/text_helpers.rs new file mode 100644 index 00000000..8c41df66 --- /dev/null +++ b/src/text_helpers.rs @@ -0,0 +1,59 @@ +use parley::Layout; +use vello::{ + kurbo::Affine, + peniko::{Brush, Fill}, + Scene, +}; + +use crate::WidgetId; + +/// A reference counted string slice. +/// +/// This is a data-friendly way to represent strings in Masonry. Unlike `String` +/// it cannot be mutated, but unlike `String` it can be cheaply cloned. +pub type ArcStr = std::sync::Arc; + +/// A type we use to keep track of which widgets are responsible for which +/// ime sessions. +#[derive(Clone, Debug)] +pub(crate) struct TextFieldRegistration { + pub widget_id: WidgetId, +} + +pub fn render_text(scene: &mut Scene, transform: Affine, layout: &Layout) { + for line in layout.lines() { + for glyph_run in line.glyph_runs() { + let mut x = glyph_run.offset(); + let y = glyph_run.baseline(); + let run = glyph_run.run(); + let font = run.font(); + let font_size = run.font_size(); + let font = vello::peniko::Font::new(font.data().0.clone(), font.index()); + let style = glyph_run.style(); + let coords = run + .normalized_coords() + .iter() + .map(|coord| vello::skrifa::instance::NormalizedCoord::from_bits(*coord)) + .collect::>(); + scene + .draw_glyphs(&font) + .brush(&style.brush) + .transform(transform) + .font_size(font_size) + .normalized_coords(&coords) + .draw( + Fill::NonZero, + glyph_run.glyphs().map(|glyph| { + let gx = x + glyph.x; + let gy = y - glyph.y; + x += glyph.advance; + vello::glyph::Glyph { + id: glyph.id as _, + x: gx, + y: gy, + } + }), + ); + } + } +} diff --git a/src/widget/image.rs b/src/widget/image.rs index 11b8e786..8d7edd4d 100644 --- a/src/widget/image.rs +++ b/src/widget/image.rs @@ -7,15 +7,17 @@ use smallvec::SmallVec; use tracing::{trace, trace_span, Span}; +use vello::Scene; use crate::kurbo::Rect; -use crate::piet::{Image as _, ImageBuf, InterpolationMode, PietImage}; +//use crate::piet::{Image as _, ImageBuf, InterpolationMode, PietImage}; use crate::widget::{FillStrat, WidgetRef}; use crate::{ - BoxConstraints, Event, EventCtx, LayoutCtx, LifeCycle, LifeCycleCtx, PaintCtx, RenderContext, - Size, StatusChange, Widget, + BoxConstraints, Event, EventCtx, LayoutCtx, LifeCycle, LifeCycleCtx, PaintCtx, Size, + StatusChange, Widget, }; +#[cfg(FALSE)] /// A widget that renders a bitmap Image. pub struct Image { image_data: ImageBuf, @@ -25,8 +27,9 @@ pub struct Image { clip_area: Option, } -crate::declare_widget!(ImageMut, Image); +//crate::declare_widget!(ImageMut, Image); +#[cfg(FALSE)] impl Image { /// Create an image drawing widget from an image buffer. /// @@ -69,6 +72,7 @@ impl Image { } } +#[cfg(FALSE)] impl<'a, 'b> ImageMut<'a, 'b> { /// Modify the widget's fill strategy. #[inline] @@ -102,6 +106,7 @@ impl<'a, 'b> ImageMut<'a, 'b> { } } +#[cfg(FALSE)] impl Widget for Image { fn on_event(&mut self, _ctx: &mut EventCtx, _event: &Event) {} @@ -128,7 +133,7 @@ impl Widget for Image { size } - fn paint(&mut self, ctx: &mut PaintCtx) { + fn paint(&mut self, ctx: &mut PaintCtx, scene: &mut Scene) { let offset_matrix = self.fill.affine_to_fill(ctx.size(), self.image_data.size()); // The ImageData's to_piet function does not clip to the image's size @@ -181,6 +186,7 @@ impl Widget for Image { } } +#[cfg(FALSE)] #[allow(unused)] // FIXME - remove cfg? #[cfg(not(target_arch = "wasm32"))] diff --git a/src/widget/label.rs b/src/widget/label.rs index 49ddd230..f81fc88e 100644 --- a/src/widget/label.rs +++ b/src/widget/label.rs @@ -4,20 +4,19 @@ //! A label widget. -// TODO -// - set text -// - set text attributes - -use druid_shell::Cursor; +use kurbo::Affine; +use parley::style::{FontFamily, FontStack, GenericFamily, StyleProperty}; +use parley::{FontContext, Layout}; use smallvec::SmallVec; +use swash::Weight; use tracing::{trace, trace_span, Span}; +use vello::peniko::{BlendMode, Brush}; +use vello::Scene; -use crate::kurbo::Vec2; -use crate::text::{FontDescriptor, TextAlignment, TextLayout}; use crate::widget::WidgetRef; use crate::{ ArcStr, BoxConstraints, Color, Event, EventCtx, LayoutCtx, LifeCycle, LifeCycleCtx, PaintCtx, - Point, RenderContext, Size, StatusChange, Widget, + Size, StatusChange, Widget, }; // added padding between the edges of the widget and the text. @@ -26,11 +25,12 @@ const LABEL_X_PADDING: f64 = 2.0; /// A widget displaying non-editable text. pub struct Label { current_text: ArcStr, - text_layout: TextLayout, + text_layout: Option>, + text_size: f32, + font_family: FontFamily<'static>, line_break_mode: LineBreaking, - disabled: bool, - default_text_color: Color, + text_color: Color, } crate::declare_widget!(LabelMut, Label); @@ -52,15 +52,14 @@ impl Label { /// Create a new label. pub fn new(text: impl Into) -> Self { let current_text = text.into(); - let mut text_layout = TextLayout::new(); - text_layout.set_text(current_text.clone()); - Self { current_text, - text_layout, + text_layout: None, + text_color: crate::theme::TEXT_COLOR, + text_size: crate::theme::TEXT_SIZE_NORMAL as f32, + font_family: FontFamily::Generic(GenericFamily::SystemUi), line_break_mode: LineBreaking::Overflow, disabled: false, - default_text_color: crate::theme::TEXT_COLOR, } } @@ -68,48 +67,38 @@ impl Label { pub fn empty() -> Self { Self { current_text: "".into(), - text_layout: TextLayout::new(), + text_layout: None, + text_color: crate::theme::TEXT_COLOR, + text_size: crate::theme::TEXT_SIZE_NORMAL as f32, + font_family: FontFamily::Generic(GenericFamily::SystemUi), line_break_mode: LineBreaking::Overflow, disabled: false, - default_text_color: crate::theme::TEXT_COLOR, } } /// Builder-style method for setting the text string. pub fn with_text(mut self, new_text: impl Into) -> Self { - self.text_layout.set_text(new_text.into()); + self.current_text = new_text.into(); + // TODO - Rethink how layout caching works during the builder phase + self.text_layout = None; self } /// Builder-style method for setting the text color. - /// - /// The argument can be either a `Color` or a [`Key`]. - /// - /// [`Key`]: ../struct.Key.html pub fn with_text_color(mut self, color: impl Into) -> Self { - let color = color.into(); - if !self.disabled { - self.text_layout.set_text_color(color); - } - self.default_text_color = color; + self.text_color = color.into(); self } /// Builder-style method for setting the text size. - /// - /// The argument can be either an `f64` or a [`Key`]. - /// - /// [`Key`]: ../struct.Key.html - pub fn with_text_size(mut self, size: impl Into) -> Self { - self.text_layout.set_text_size(size.into()); + pub fn with_text_size(mut self, size: impl Into) -> Self { + self.text_size = size.into(); self } - // FIXME - with_font cancels with_text_size - // TODO - write failing test for this case /// Builder-style method for setting the font. - pub fn with_font(mut self, font: impl Into) -> Self { - self.text_layout.set_font(font.into()); + pub fn with_font_family(mut self, font_family: impl Into>) -> Self { + self.font_family = font_family.into(); self } @@ -119,6 +108,7 @@ impl Label { self } + #[cfg(FALSE)] /// Builder-style method to set the [`TextAlignment`]. pub fn with_text_alignment(mut self, alignment: TextAlignment) -> Self { self.text_layout.set_text_alignment(alignment); @@ -130,55 +120,58 @@ impl Label { self.current_text.clone() } + #[cfg(FALSE)] /// Return the offset of the first baseline relative to the bottom of the widget. pub fn baseline_offset(&self) -> f64 { let text_metrics = self.text_layout.layout_metrics(); text_metrics.size.height - text_metrics.first_baseline } - /// Draw this label's text at the provided `Point`, without internal padding. - /// - /// This is a convenience for widgets that want to use Label as a way - /// of managing a dynamic or localized string, but want finer control - /// over where the text is drawn. - pub fn draw_at(&self, ctx: &mut PaintCtx, origin: impl Into) { - self.text_layout.draw(ctx, origin) + fn get_layout_mut(&mut self, font_cx: &mut FontContext) -> &mut Layout { + let color = if self.disabled { + crate::theme::DISABLED_TEXT_COLOR + } else { + self.text_color + }; + let mut lcx = parley::LayoutContext::new(); + let mut layout_builder = lcx.ranged_builder(font_cx, &self.current_text, 1.0); + + layout_builder.push_default(&StyleProperty::FontStack(FontStack::Single( + FontFamily::Generic(parley::style::GenericFamily::SystemUi), + ))); + layout_builder.push_default(&StyleProperty::FontSize(15.0)); + layout_builder.push_default(&StyleProperty::Brush(Brush::Solid(color))); + + // TODO - Refactor. This code is mostly copy-pasted from Xilem's text widget + // Not super elegant. + self.text_layout = Some(layout_builder.build()); + self.text_layout.as_mut().unwrap() } } impl LabelMut<'_, '_> { /// Set the text. pub fn set_text(&mut self, new_text: impl Into) { - self.widget.text_layout.set_text(new_text.into()); + self.widget.current_text = new_text.into(); + self.widget.text_layout = None; self.ctx.request_layout(); } /// Set the text color. - /// - /// The argument can be either a `Color` or a [`Key`]. - /// [`Key`]: ../struct.Key.html pub fn set_text_color(&mut self, color: impl Into) { - let color = color.into(); - if !self.widget.disabled { - self.widget.text_layout.set_text_color(color); - } - self.widget.default_text_color = color; + self.widget.text_color = color.into(); self.ctx.request_layout(); } /// Set the text size. - /// - /// The argument can be either an `f64` or a [`Key`]. - /// - /// [`Key`]: ../struct.Key.html - pub fn set_text_size(&mut self, size: impl Into) { - self.widget.text_layout.set_text_size(size.into()); + pub fn set_text_size(&mut self, size: impl Into) { + self.widget.text_size = size.into(); self.ctx.request_layout(); } /// Set the font. - pub fn set_font(&mut self, font: impl Into) { - self.widget.text_layout.set_font(font.into()); + pub fn set_font_family(&mut self, font_family: impl Into>) { + self.widget.font_family = font_family.into(); self.ctx.request_layout(); } @@ -188,6 +181,7 @@ impl LabelMut<'_, '_> { self.ctx.request_layout(); } + #[cfg(FALSE)] /// Set the [`TextAlignment`] for this layout. pub fn set_text_alignment(&mut self, alignment: TextAlignment) { self.widget.text_layout.set_text_alignment(alignment); @@ -198,42 +192,14 @@ impl LabelMut<'_, '_> { // --- TRAIT IMPLS --- impl Widget for Label { - fn on_event(&mut self, ctx: &mut EventCtx, event: &Event) { - match event { - Event::MouseUp(event) => { - // Account for the padding - let pos = event.pos - Vec2::new(LABEL_X_PADDING, 0.0); - if let Some(_link) = self.text_layout.link_for_pos(pos) { - todo!(); - //ctx.submit_command(link.command.clone()); - // See issue #21 - } - } - Event::MouseMove(event) => { - // Account for the padding - let pos = event.pos - Vec2::new(LABEL_X_PADDING, 0.0); - - if self.text_layout.link_for_pos(pos).is_some() { - ctx.set_cursor(&Cursor::Pointer); - } else { - ctx.clear_cursor(); - } - } - _ => {} - } - } + fn on_event(&mut self, ctx: &mut EventCtx, event: &Event) {} fn on_status_change(&mut self, _ctx: &mut LifeCycleCtx, _event: &StatusChange) {} fn lifecycle(&mut self, ctx: &mut LifeCycleCtx, event: &LifeCycle) { match event { LifeCycle::DisabledChanged(disabled) => { - let color = if *disabled { - crate::theme::DISABLED_TEXT_COLOR - } else { - self.default_text_color - }; - self.text_layout.set_text_color(color); + // TODO - only request paint ctx.request_layout(); } _ => {} @@ -241,32 +207,56 @@ impl Widget for Label { } fn layout(&mut self, ctx: &mut LayoutCtx, bc: &BoxConstraints) -> Size { - let width = match self.line_break_mode { - LineBreaking::WordWrap => bc.max().width - LABEL_X_PADDING * 2.0, - _ => f64::INFINITY, + // Compute max_advance from box constraints + let max_advance = if self.line_break_mode != LineBreaking::WordWrap { + None + } else if bc.max().width.is_finite() { + Some(bc.max().width as f32 - 2. * LABEL_X_PADDING as f32) + } else if bc.min().width.is_sign_negative() { + Some(0.0) + } else { + None }; - self.text_layout.set_wrap_width(width); - self.text_layout.rebuild_if_needed(ctx.text()); + // FIXME + let font_cx = &mut FontContext::new(); - let text_metrics = self.text_layout.layout_metrics(); - ctx.set_baseline_offset(text_metrics.size.height - text_metrics.first_baseline); - let size = bc.constrain(Size::new( - text_metrics.size.width + 2. * LABEL_X_PADDING, - text_metrics.size.height, - )); - trace!("Computed size: {}", size); + // TODO - Handle baseline + + // Lay text out + let layout = self.get_layout_mut(font_cx); + layout.break_all_lines(max_advance, parley::layout::Alignment::Start); + let size = Size { + width: layout.width() as f64 + 2. * LABEL_X_PADDING, + height: layout.height() as f64, + }; + let size = bc.constrain(size); + trace!( + "Computed layout: max={:?}. w={}, h={}", + max_advance, + size.width, + size.height, + ); size } - fn paint(&mut self, ctx: &mut PaintCtx) { - let origin = Point::new(LABEL_X_PADDING, 0.0); - let label_size = ctx.size(); + fn paint(&mut self, ctx: &mut PaintCtx, scene: &mut Scene) { + if let Some(text_layout) = &self.text_layout { + if self.line_break_mode == LineBreaking::Clip { + let clip_rect = ctx.size().to_rect(); + scene.push_layer(BlendMode::default(), 1., Affine::IDENTITY, &clip_rect); + } + + crate::text_helpers::render_text( + scene, + Affine::translate((LABEL_X_PADDING, 0.)), + text_layout, + ); - if self.line_break_mode == LineBreaking::Clip { - ctx.clip(label_size.to_rect()); + if self.line_break_mode == LineBreaking::Clip { + scene.pop_layer(); + } } - self.draw_at(ctx, origin) } fn children(&self) -> SmallVec<[WidgetRef<'_, dyn Widget>; 16]> { @@ -282,14 +272,15 @@ impl Widget for Label { } } +// TODO - reenable tests #[cfg(test)] mod tests { - use crate::piet::FontFamily; use insta::assert_debug_snapshot; use super::*; use crate::assert_render_snapshot; use crate::testing::TestHarness; + #[cfg(FALSE)] use crate::theme::{PRIMARY_DARK, PRIMARY_LIGHT}; use crate::widget::{Flex, SizedBox}; @@ -303,6 +294,7 @@ mod tests { assert_render_snapshot!(harness, "hello"); } + #[cfg(FALSE)] #[test] fn styled_label() { let label = Label::new("The quick brown fox jumps over the lazy dog") @@ -351,6 +343,7 @@ mod tests { assert_render_snapshot!(harness, "line_break_modes"); } + #[cfg(FALSE)] #[test] fn edit_label() { let image_1 = { diff --git a/src/widget/mod.rs b/src/widget/mod.rs index 692ca75c..16e64cb6 100644 --- a/src/widget/mod.rs +++ b/src/widget/mod.rs @@ -37,7 +37,7 @@ pub use scroll_bar::ScrollBar; pub use sized_box::SizedBox; pub use spinner::Spinner; pub use split::Split; -pub use textbox::TextBox; +//pub use textbox::TextBox; pub use widget::StoreInWidgetMut; #[doc(hidden)] pub use widget::{Widget, WidgetId}; @@ -49,6 +49,7 @@ pub use widget_pod::WidgetPod; pub use widget_ref::WidgetRef; pub use widget_state::WidgetState; +#[cfg(FALSE)] pub use self::image::Image; pub use sized_box::BackgroundBrush; diff --git a/src/widget/tests/snapshots/masonry__widget__tests__lifecycle_basic__adding_child.snap.new b/src/widget/tests/snapshots/masonry__widget__tests__lifecycle_basic__adding_child.snap.new new file mode 100644 index 00000000..e5fdf70d --- /dev/null +++ b/src/widget/tests/snapshots/masonry__widget__tests__lifecycle_basic__adding_child.snap.new @@ -0,0 +1,21 @@ +--- +source: src/widget/tests/lifecycle_basic.rs +assertion_line: 53 +expression: record_new_child +--- +[ + L( + WidgetAdded, + ), + L( + BuildFocusChain, + ), + Layout( + 0.0W×20.0H, + ), + L( + Internal( + ParentWindowOrigin, + ), + ), +] diff --git a/src/widget/textbox.rs b/src/widget/textbox.rs index f1e6162b..407eef23 100644 --- a/src/widget/textbox.rs +++ b/src/widget/textbox.rs @@ -1,3 +1,6 @@ +// NOPE DON'T COMMIT + +/* // This software is licensed under Apache License 2.0 and distributed on an // "as-is" basis without warranties of any kind. See the LICENSE file for // details. @@ -9,10 +12,10 @@ use std::time::Duration; use smallvec::{smallvec, SmallVec}; use tracing::{trace_span, Span}; +use vello::Scene; use crate::action::Action; use crate::kurbo::{Affine, Insets}; -use crate::piet::{RenderContext as _, TextLayout as _}; use crate::shell::{HotKey, KeyEvent, SysMods, TimerToken}; use crate::text::{ImeInvalidation, Selection, TextAlignment, TextComponent, TextLayout}; use crate::widget::{Portal, WidgetMut, WidgetRef}; @@ -20,6 +23,7 @@ use crate::{ theme, ArcStr, BoxConstraints, Command, Event, EventCtx, LayoutCtx, LifeCycle, LifeCycleCtx, PaintCtx, Point, Rect, Size, StatusChange, Vec2, Widget, WidgetPod, }; +use druid_shell::piet::TextLayout as _; const CURSOR_BLINK_DURATION: Duration = Duration::from_millis(500); const MAC_OR_LINUX: bool = cfg!(any(target_os = "macos", target_os = "linux")); @@ -605,7 +609,7 @@ impl Widget for TextBox { size } - fn paint(&mut self, ctx: &mut PaintCtx) { + fn paint(&mut self, ctx: &mut PaintCtx, scene: &mut Scene) { if !self.inner.as_ref().child().can_read() { tracing::warn!("Widget::paint called with outstanding IME lock, skipping"); return; @@ -636,7 +640,7 @@ impl Widget for TextBox { let padding_offset = Vec2::new(textbox_insets.x0, textbox_insets.y0); ctx.with_save(|ctx| { ctx.transform(Affine::translate(padding_offset)); - self.inner.paint(ctx); + self.inner.paint(ctx, scene); }) } else { ctx.skip_child(&mut self.inner); @@ -800,3 +804,4 @@ mod tests { assert!(image_1 == image_2); } } +*/ From 96841c189e05a2e549361d6ef70ebee74431b34e Mon Sep 17 00:00:00 2001 From: Olivier FAURE Date: Thu, 4 Apr 2024 14:52:46 +0200 Subject: [PATCH 03/21] Update Vello and Parley versions Add font hinting Update render snapshots --- Cargo.lock | 469 ++++++++++++++++-- Cargo.toml | 6 +- src/text_helpers.rs | 8 +- src/widget/label.rs | 2 +- ...asonry__widget__align__tests__centered.png | Bin 5631 -> 5717 bytes .../masonry__widget__align__tests__left.png | Bin 5625 -> 5708 bytes .../masonry__widget__align__tests__right.png | Bin 5614 -> 5718 bytes .../masonry__widget__button__tests__hello.png | Bin 2564 -> 6079 bytes ...widget__checkbox__tests__hello_checked.png | Bin 2714 -> 6147 bytes ...dget__checkbox__tests__hello_unchecked.png | Bin 2393 -> 5850 bytes ...__flex__tests__col_cross_axis_baseline.png | Bin 3888 -> 8110 bytes ...et__flex__tests__col_cross_axis_center.png | Bin 3888 -> 8110 bytes ...idget__flex__tests__col_cross_axis_end.png | Bin 3888 -> 8076 bytes ...dget__flex__tests__col_cross_axis_fill.png | Bin 3907 -> 8070 bytes ...get__flex__tests__col_cross_axis_start.png | Bin 3907 -> 8070 bytes ...idget__flex__tests__col_fill_main_axis.png | Bin 4197 -> 8172 bytes ...get__flex__tests__col_main_axis_center.png | Bin 3896 -> 8105 bytes ...widget__flex__tests__col_main_axis_end.png | Bin 3896 -> 8121 bytes ...flex__tests__col_main_axis_spaceAround.png | Bin 4197 -> 8172 bytes ...lex__tests__col_main_axis_spaceBetween.png | Bin 4192 -> 8198 bytes ...flex__tests__col_main_axis_spaceEvenly.png | Bin 4197 -> 8185 bytes ...dget__flex__tests__col_main_axis_start.png | Bin 3888 -> 8110 bytes ...__flex__tests__row_cross_axis_baseline.png | Bin 3569 -> 7897 bytes ...et__flex__tests__row_cross_axis_center.png | Bin 3696 -> 8007 bytes ...idget__flex__tests__row_cross_axis_end.png | Bin 3696 -> 8006 bytes ...dget__flex__tests__row_cross_axis_fill.png | Bin 3569 -> 7897 bytes ...get__flex__tests__row_cross_axis_start.png | Bin 3569 -> 7897 bytes ...idget__flex__tests__row_fill_main_axis.png | Bin 3716 -> 8018 bytes ...get__flex__tests__row_main_axis_center.png | Bin 3687 -> 8017 bytes ...widget__flex__tests__row_main_axis_end.png | Bin 3689 -> 8019 bytes ...flex__tests__row_main_axis_spaceAround.png | Bin 3716 -> 8018 bytes ...lex__tests__row_main_axis_spaceBetween.png | Bin 3707 -> 8049 bytes ...flex__tests__row_main_axis_spaceEvenly.png | Bin 3698 -> 8013 bytes ...dget__flex__tests__row_main_axis_start.png | Bin 3696 -> 8007 bytes .../masonry__widget__label__tests__hello.png | Bin 2237 -> 5654 bytes ...widget__label__tests__line_break_modes.png | Bin 12902 -> 20023 bytes ...__portal__tests__button_list_no_scroll.png | Bin 11855 -> 16401 bytes ...__tests__button_list_scroll_to_item_13.png | Bin 12420 -> 17025 bytes ...l__tests__button_list_scroll_to_item_3.png | Bin 12242 -> 16778 bytes ...t__portal__tests__button_list_scrolled.png | Bin 12114 -> 16741 bytes ...t__scroll_bar__tests__scrollbar_bottom.png | Bin 578 -> 913 bytes ...__scroll_bar__tests__scrollbar_default.png | Bin 594 -> 962 bytes ...get__scroll_bar__tests__scrollbar_down.png | Bin 620 -> 909 bytes ...croll_bar__tests__scrollbar_horizontal.png | Bin 477 -> 721 bytes ...ar__tests__scrollbar_horizontal_middle.png | Bin 394 -> 697 bytes ...t__scroll_bar__tests__scrollbar_middle.png | Bin 617 -> 913 bytes ...y__widget__sized_box__tests__empty_box.png | Bin 5301 -> 5247 bytes ...t__sized_box__tests__label_box_no_size.png | Bin 6113 -> 6162 bytes ...__widget__spinner__tests__spinner_init.png | Bin 16580 -> 25071 bytes ...masonry__widget__split__tests__columns.png | Bin 6465 -> 6780 bytes .../masonry__widget__split__tests__rows.png | Bin 6703 -> 6844 bytes 51 files changed, 440 insertions(+), 45 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ed73ac88..80390cd2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -53,6 +53,54 @@ dependencies = [ "winapi", ] +[[package]] +name = "anstream" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" + +[[package]] +name = "anstyle-parse" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + [[package]] name = "anyhow" version = "1.0.69" @@ -430,6 +478,46 @@ dependencies = [ "libloading 0.7.3", ] +[[package]] +name = "clap" +version = "4.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.55", +] + +[[package]] +name = "clap_lex" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" + [[package]] name = "cocoa" version = "0.24.1" @@ -477,6 +565,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + [[package]] name = "com" version = "0.6.0" @@ -593,6 +687,15 @@ dependencies = [ "libc", ] +[[package]] +name = "core_maths" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b02505ccb8c50b0aa21ace0fc08c3e53adebd4e58caa18a36152803c7709a3" +dependencies = [ + "libm", +] + [[package]] name = "crc32fast" version = "1.3.2" @@ -696,6 +799,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "displaydoc" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.55", +] + [[package]] name = "druid-shell" version = "0.8.0" @@ -746,6 +860,8 @@ checksum = "439a1c2ba5611ad3ed731280541d36d2e9c4ac5e7fb818a27b604bdc5a6aa65b" dependencies = [ "lazy_static", "libc", + "serde", + "serde_derive", "winapi", "wio", ] @@ -915,9 +1031,24 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "font-types" -version = "0.4.3" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b7f6040d337bd44434ab21fc6509154edf2cece88b23758d9d64654c4e7730b" +checksum = "bd6784a76a9c2b136ea3b8462391e9328252e938eb706eb44d752723b4c3a533" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "fontconfig-cache-parser" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db0413877146e4ea3a9f56c12917a1754418b518ac7a6982838eabafa8a92260" +dependencies = [ + "anyhow", + "bytemuck", + "clap", + "thiserror", +] [[package]] name = "fontdb" @@ -926,7 +1057,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e58903f4f8d5b58c7d300908e4ebe5289c1bfdf5587964330f12023b8ff17fd1" dependencies = [ "log", - "memmap2", + "memmap2 0.2.3", "ttf-parser 0.12.3", ] @@ -1263,7 +1394,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e084807350b01348b6d9dbabb724d1a0bb987f47a2c85de200e98e12e30733bf" dependencies = [ "anyhow", - "heck", + "heck 0.4.1", "proc-macro-crate", "proc-macro-error", "proc-macro2", @@ -1473,6 +1604,12 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hermit-abi" version = "0.1.19" @@ -1507,6 +1644,100 @@ dependencies = [ "winapi", ] +[[package]] +name = "icu_collections" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "137d96353afc8544d437e8a99eceb10ab291352699573b0de5b08bda38c78c60" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c0aa2536adc14c07e2a521e95512b75ed8ef832f0fdf9299d4a0a45d2be2a9d" +dependencies = [ + "displaydoc", + "litemap", + "tinystr 0.7.5", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c17d8f6524fdca4471101dd71f0a132eb6382b5d6d7f2970441cb25f6f435a" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr 0.7.5", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "545c6c3e8bf9580e2dafee8de6f9ec14826aaf359787789c7724f1f85f47d3dc" + +[[package]] +name = "icu_properties" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "976e296217453af983efa25f287a4c1da04b9a63bf1ed63719455068e4453eb5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr 0.7.5", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6a86c0e384532b06b6c104814f9c1b13bcd5b64409001c0d05713a1f3529d99" + +[[package]] +name = "icu_provider" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba58e782287eb6950247abbf11719f83f5d4e4a5c1f2cd490d30a334bc47c2f4" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr 0.7.5", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2abdd3a62551e8337af119c5899e600ca0c88ec8f23a46c60ba216c803dcf1a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.55", +] + [[package]] name = "im" version = "15.1.0" @@ -1607,7 +1838,7 @@ version = "7.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b18f988384267d7066cc2be425e6faf352900652c046b6971d2e228d3b1c5ecf" dependencies = [ - "tinystr", + "tinystr 0.3.4", "unic-langid", ] @@ -1693,6 +1924,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e5aa9f0f96a938266bdb12928a67169e8d22c6a786fda8ed984b85e6ba93c3c" dependencies = [ "arrayvec", + "libm", "smallvec", ] @@ -1740,12 +1972,24 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + [[package]] name = "linked-hash-map" version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" +[[package]] +name = "litemap" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d642685b028806386b2b6e75685faadd3eb65a85fff7df711ce18446a422da" + [[package]] name = "lock_api" version = "0.4.9" @@ -1758,12 +2002,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.17" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if 1.0.0", -] +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "malloc_buf" @@ -1835,6 +2076,15 @@ dependencies = [ "libc", ] +[[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" @@ -2142,16 +2392,34 @@ dependencies = [ "libc", "redox_syscall 0.2.16", "smallvec", - "windows-sys", + "windows-sys 0.36.1", ] [[package]] name = "parley" version = "0.0.1" -source = "git+https://github.com/dfrg/parley?rev=1940d1ae9f2a9b44b7c18967147ffa7d345fdafd#1940d1ae9f2a9b44b7c18967147ffa7d345fdafd" +source = "git+https://github.com/dfrg/parley?rev=4e6109f2ff5847a72dc77971b6fa0942b8474d88#4e6109f2ff5847a72dc77971b6fa0942b8474d88" dependencies = [ + "anyhow", + "bytemuck", + "core-foundation", + "core-foundation-sys", + "core-text", + "dwrote", + "fontconfig-cache-parser", + "foreign-types 0.3.2", + "hashbrown", + "icu_locid", + "icu_properties", + "memmap2 0.5.10", "peniko", + "roxmltree 0.18.1", + "skrifa", + "smallvec", "swash", + "thiserror", + "winapi", + "wio", ] [[package]] @@ -2561,19 +2829,11 @@ checksum = "be9e29cb19c8fe84169fcb07f8f11e66bc9e6e0280efd4715c54818296f8a4a8" [[package]] name = "read-fonts" -version = "0.15.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17ea23eedb4d938031b6d4343222444608727a6aa68ec355e13588d9947ffe92" -dependencies = [ - "font-types", -] - -[[package]] -name = "read-fonts" -version = "0.16.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81c524658d3b77930a391f559756d91dbe829ab6cf4687083f615d395df99722" +checksum = "ea75b5ec052843434d263ef7a4c31cf86db5908c729694afb1ad3c884252a1b6" dependencies = [ + "bytemuck", "font-types", ] @@ -2644,6 +2904,15 @@ dependencies = [ "xmlparser", ] +[[package]] +name = "roxmltree" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "862340e351ce1b271a378ec53f304a5558f7db87f3769dc655a8f6ecbb68b302" +dependencies = [ + "xmlparser", +] + [[package]] name = "rustc-hash" version = "1.1.0" @@ -2822,11 +3091,13 @@ dependencies = [ [[package]] name = "skrifa" -version = "0.15.5" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eff28ee3b66d43060ef9a327e0f18e4c1813f194120156b4d4524fac3ba8ce22" +checksum = "b3f54c6ecbad34b55ea1779389e334fe0d260f2f0c80964a926ffb47918c26e9" dependencies = [ - "read-fonts 0.15.6", + "bytemuck", + "core_maths", + "read-fonts", ] [[package]] @@ -2881,12 +3152,24 @@ dependencies = [ "bitflags 2.5.0", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "static_assertions" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "svg_fmt" version = "0.4.2" @@ -2905,11 +3188,11 @@ dependencies = [ [[package]] name = "swash" -version = "0.1.13" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9af636fb90d39858650cae1088a37e2862dab4e874a0bb49d6dfb5b2dacf0e24" +checksum = "06ec889a8e0a6fcb91041996c8f1f6be0fe1a09e94478785e07c32ce2bca2d2b" dependencies = [ - "read-fonts 0.16.0", + "read-fonts", "yazi", "zeno", ] @@ -2936,6 +3219,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.55", +] + [[package]] name = "system-deps" version = "6.0.3" @@ -2943,7 +3237,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2955b1fe31e1fa2fbd1976b71cc69a606d7d4da16f6de3333d0c92d51419aeff" dependencies = [ "cfg-expr", - "heck", + "heck 0.4.1", "pkg-config", "toml", "version-compare", @@ -3064,6 +3358,16 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29738eedb4388d9ea620eeab9384884fc3f06f586a2eddb56bedc5885126c7c1" +[[package]] +name = "tinystr" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83c02bf3c538ab32ba913408224323915f4ef9a6d61c0e85d493f355921c0ece" +dependencies = [ + "displaydoc", + "zerovec", +] + [[package]] name = "toml" version = "0.5.9" @@ -3229,7 +3533,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a4a8eeaf0494862c1404c95ec2f4c33a2acff5076f64314b465e3ddae1b934d" dependencies = [ - "tinystr", + "tinystr 0.3.4", ] [[package]] @@ -3333,10 +3637,10 @@ dependencies = [ "fontdb", "kurbo 0.8.3", "log", - "memmap2", + "memmap2 0.2.3", "pico-args", "rctree", - "roxmltree", + "roxmltree 0.14.1", "rustybuzz", "simplecss", "siphasher", @@ -3354,6 +3658,12 @@ version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14706d2a800ee8ff38c1d3edb873cd616971ea59eb7c0d046bb44ef59b06a1ae" +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + [[package]] name = "valuable" version = "0.1.0" @@ -3363,11 +3673,11 @@ checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" [[package]] name = "vello" version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9a4b96a2d6d6effa67868b4436560e3a767f71f0e043df007587c5d6b2e8b7a" +source = "git+https://github.com/linebender/vello/?rev=b520a35addfa6bbb37d93491d2b8236528faf3b5#b520a35addfa6bbb37d93491d2b8236528faf3b5" dependencies = [ "bytemuck", "futures-intrusive", + "log", "peniko", "raw-window-handle", "skrifa", @@ -3378,8 +3688,7 @@ dependencies = [ [[package]] name = "vello_encoding" version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c5b6c6ec113c9b6ee1e1894ccef1b5559373aead718b7442811f2fefff7d423" +source = "git+https://github.com/linebender/vello/?rev=b520a35addfa6bbb37d93491d2b8236528faf3b5#b520a35addfa6bbb37d93491d2b8236528faf3b5" dependencies = [ "bytemuck", "guillotiere", @@ -3710,6 +4019,15 @@ dependencies = [ "windows_x86_64_msvc 0.36.1", ] +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + [[package]] name = "windows-targets" version = "0.52.4" @@ -3806,6 +4124,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "writeable" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dad7bb64b8ef9c0aa27b6da38b452b0ee9fd82beaf276a87dd796fb55cbae14e" + [[package]] name = "x11rb" version = "0.10.1" @@ -3843,9 +4167,9 @@ checksum = "0fcb9cbac069e033553e8bb871be2fbdffcab578eb25bd0f7c508cedc6dcd75a" [[package]] name = "xmlparser" -version = "0.13.3" +version = "0.13.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "114ba2b24d2167ef6d67d7d04c8cc86522b87f490025f39f0303b7db5bf5e3d8" +checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4" [[package]] name = "xmlwriter" @@ -3868,6 +4192,30 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c94451ac9513335b5e23d7a8a2b61a7102398b8cca5160829d313e84c9d98be1" +[[package]] +name = "yoke" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65e71b2e4f287f467794c671e2b8f8a5f3716b3c829079a1c44740148eff07e4" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e6936f0cce458098a201c245a11bef556c6a0181129c7034d10d76d1ec3a2b8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.55", + "synstructure", +] + [[package]] name = "zbus" version = "2.3.2" @@ -3958,6 +4306,49 @@ dependencies = [ "syn 2.0.55", ] +[[package]] +name = "zerofrom" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "655b0814c5c0b19ade497851070c640773304939a6c0fd5f5fb43da0696d05b7" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6a647510471d372f2e6c2e6b7219e44d8c574d24fdc11c610a61455782f18c3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.55", + "synstructure", +] + +[[package]] +name = "zerovec" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eff4439ae91fb5c72b8abc12f3f2dbf51bd27e6eadb9f8a5bc8898dddb0e27ea" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4e5997cbf58990550ef1f0e5124a05e47e1ebd33a84af25739be6031a62c20" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.55", +] + [[package]] name = "zvariant" version = "3.7.1" diff --git a/Cargo.toml b/Cargo.toml index 320388ed..2ceb24cb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -74,15 +74,15 @@ image = "0.24.0" once_cell = "1.9.0" serde = {version = "1.0.133", features = ["derive"]} serde_json = "1.0.74" -vello = "0.1.0" +vello = { git = "https://github.com/linebender/vello/", rev = "b520a35addfa6bbb37d93491d2b8236528faf3b5" } kurbo = "0.11.0" futures-intrusive = "0.5.0" pollster = "0.3.0" -parley = { git = "https://github.com/dfrg/parley", rev = "1940d1ae9f2a9b44b7c18967147ffa7d345fdafd" } +parley = { git = "https://github.com/dfrg/parley", rev = "4e6109f2ff5847a72dc77971b6fa0942b8474d88" } # NOTE: Make sure to keep this in sync with the version badge in README.md wgpu = { version = "0.19.3" } -swash = "0.1.13" +swash = "0.1.15" [target.'cfg(target_arch="wasm32")'.dependencies] console_error_panic_hook = {version = "0.1.6"} diff --git a/src/text_helpers.rs b/src/text_helpers.rs index 8c41df66..f153321d 100644 --- a/src/text_helpers.rs +++ b/src/text_helpers.rs @@ -28,7 +28,10 @@ pub fn render_text(scene: &mut Scene, transform: Affine, layout: &Layout) let run = glyph_run.run(); let font = run.font(); let font_size = run.font_size(); - let font = vello::peniko::Font::new(font.data().0.clone(), font.index()); + let synthesis = run.synthesis(); + let glyph_xform = synthesis + .skew() + .map(|angle| Affine::skew(angle.to_radians().tan() as f64, 0.0)); let style = glyph_run.style(); let coords = run .normalized_coords() @@ -36,9 +39,10 @@ pub fn render_text(scene: &mut Scene, transform: Affine, layout: &Layout) .map(|coord| vello::skrifa::instance::NormalizedCoord::from_bits(*coord)) .collect::>(); scene - .draw_glyphs(&font) + .draw_glyphs(font) .brush(&style.brush) .transform(transform) + .glyph_transform(glyph_xform) .font_size(font_size) .normalized_coords(&coords) .draw( diff --git a/src/widget/label.rs b/src/widget/label.rs index f81fc88e..340e087e 100644 --- a/src/widget/label.rs +++ b/src/widget/label.rs @@ -219,7 +219,7 @@ impl Widget for Label { }; // FIXME - let font_cx = &mut FontContext::new(); + let font_cx = &mut FontContext::default(); // TODO - Handle baseline diff --git a/src/widget/screenshots/masonry__widget__align__tests__centered.png b/src/widget/screenshots/masonry__widget__align__tests__centered.png index 148ddcf4bafcc77902987ea730bae6f9749a66b7..a563f8d10f10e5efe4f7caef1f72bec908755e15 100644 GIT binary patch literal 5717 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 EKO!zV(EtDd literal 5631 zcmZ`-d0dTK7e428q9emmGGuzuM1^aLByUM7N-Bk>V{V{OX;6BPTndpWV*@2oN>rrL z6pG5!ppr|IifE)#-?PvC=lj0f{iEM+zx%Ac_S(;S_OsS5(8PG<@S$=;IULS#1ASdn z4u=~|{v-!uhRs>{g2R!`GtkvG_vC)9unX9+!)wTQ%PlW#D&?gOver(RvEMAyevAIy zSZ}j~CYdwB20sZglCgH#`8hHr@UWq}{8jH{g;brW&GxT4_2SB=C5N6Hqo$uMY^-DH#O2t_5YI1oV=jX8rM# z@hK+|(8E<fZXQqHcgd?)izs6S zMkwTR=gx`yEGeLikFlID+uqd4Gi+`yr84AMuKOf0BF`mw`mGXDYrZco5Q&kHz(oZeHJo8b&x!Y?*>>F1 zG7Z)Y>()11=!2y@XVT2V&^D4Zjj@u$f(vVd$jTZp;un=F_Q>T*DZC ziQ8aeJz79dnpO1-%pRx1usg3bjE6gcGWA%Ui=QQT%ER&IHUXE?rt&TDF>~W#3miDu zfMK`353>cAO-_LX_T$Y`t`LWZaru@TXdD4T;YeQL7-wsWcZK&pUWIvIaXpY=6$q>j zZ5RdbDN4Yq!XaMf{4tIwAJpF_^=bs1+(vd)FTPg7@CvW)tt{;-%rqj|J%+2bd5Wd@ zHX)7Y2Yuc}J>oA4WG*5xFS9NXx<>=XSAnu%24=@oF-BfyxS%vLWRT5#mBG-EVRfI! zucH0g$$VAZXQ|!R;2lTw3n|JDQo;G@TMWah=9c$`$l#+m5sdM;t2iBLjDwB2?GYLA z{r`y%pDnV)BnBpXZytu9T=DGZOR{bVS)>3HesBTtx%(c=SzP%f1LFW`eKSioW<#hR z0q`sUbeeJ>gkoDqa8W}h!`R8V8O#~R&4w$T#q9tV!R8Dr zZ*wUPLxCF2Tv3lYaEZ+a4;5%8?Nb}swHtTf_qPu<*r?13!!~hu%!s3&OT$=K zzQBGp!_H4L`AigYCUibDMFS=Q(&Mfta>nyZlJQ}0!>}pYo7zBMp*&2a6Si1M&ynI% zN05U@=9%IGunIt$PE&^)Hg^+c#(TEOJ?q~pgPCNUwon(IrX@xLvf|qytyji&!s`I= zbZX);>`KpB!>}(-{~*keRE0iBd0ESg1-=_B_`T%yRQzxQ^Xn2JC7UsF~cCg7pYL!KIE*T;8K;W)}UEh!?K} z{X)~lNu7tf$n_3~d*|B0r~$ci;C|f7Yov%rIiF)W{AkN_Sdb2IzWx3}4!#K|Ii4N% zu$$y$JIv>)uOZRw2mOEF<#5QUZkNi^1v;PRQ(S zE$I1X)&A+kk^^@$`+s|csb~MN%ujc%&p(^fJG-_m((g)UYre{{$*w_+o@hhS0qXo8 zKZ|eVT777ZZGAAZZ;#ifKtI)!nysa^u@{|ZM)uZ3woK?Mv2vLa+1DOjn_eHGGE(!q ziC1%Sj!KJnY0H_DJ~fZTJ9bw1W%zuO@w3S8sp?njs_qy5%D3!Gow%%TW$lOkEw=6F zoOq^EKl$<<-Scx+e|&bTX;$ynJy$gQd)w|c(|oA@6VAtiXzlbYI)z*?E6`LcHWKyyZ;J*(qHLX^rQ8qOWzK!pMO=^yP1f-3E)QQ* zn>WGblJ9}4rbIRM>fZQTC%gT7JH1;T-OcW(zBAjSPv5EY$-$9Jw13p8=Un&s-PE7l zk{CYEuIGJx!K>(;w3grDWBU|}59T^;9QSY-ua4jQ^Xcs7jP^H?eLFk58{?BAe6{x0 zJZo-SxvX2MHoK>@|J1v6mNpA|vYs~|mY8DO-#uZwWl`j^Wj&c)e^sVem6qD>|N6m7 zOU52`ZGNipqXd=j52Z4=u8nW2!(9CKcU?PCP*m2lC9$A-$(aQ_j=PozJP*^{67m~a{<%VBbPMa9yht-%~~Myif)Rqb-h* zM%5QSnoe|}u@>b+-fE>@lh=?V3UI2kp55PN{|dVMQTe+NB7F-|+T8V>G+{go6bKca z^j+>;bkxO1AfH=`Vu|~YaKGDh2vKB1;rsj4){QRjh{7I61lvOglde1kCYWs;Q#^@F zIiU+#aH|rp1TJ+J4?YDcI~68|tj*Y7`c(ed1Nc=C3YCAIDl{BI6A zOqP<_(#n@IUL6rgq7T)9pGHENdV0bmoJ8A0Awc3^Ch@5L}|?T@mv zU`CZO0XBmm^5Fjvxx#yU(+IUaZPahv6&h{3!ENPTgcl3JiweEGrl-%b?Kre-!}7n( zAz@?J?($RvKKdB@lthk$TXG)hh|A!9=canncCAGXY}i~OS1=z}0Qfjo9*rQOGwA!) zhm6621q!#~5;+@UKFa|&$rnh9tAjPt#u2T6n^Py8@Cy2_DLM=g9~CShMtR`cmPU<> zILL4*^U3t^f(bzw4?v1gDf^STbJ3Ene&$Y)TZGsr=6^CGs|JoP31w(Tv-;MSDim_u%PI5$Fp|hQbje#O_7H$esCtQG=3aOoA=!#Nz z>R+JPsrYdQ^$wchXmOc5F>CN1P4B#FMchv>wqebuCz0s^{`ujiB>Y%{TsTcwFcQuc zu~0@^WjW#{vk^h)QMuGQB;`iQW%5X_!Mn<9-&Hd)7EAv@q;&DcIs)}yz9DmQ0{aGx zSqsM8TQ`r8iUNls*Znkrlt1>G)FMaZDRr0bGMMO3!xKo=F??awD)^ZJbs3%S2#QDH-ShgR zX^<{?)7iO8=-c%yRKwE2Sn9u4BLE@#0>A7|o1TWubtNdUO`8p@SxODyU3OMttR&JZF?QO^Hg z2^=mV!emHz$+EQjjc{3}gDWAbUkf1HRcXfiLw31X3$H*6|Eu`?Pf7YceA8x%_X%>= zJHm~~+!;8meLtVPl9ffP+$H|2(hwkMrx~h?=|s t;T*Eok?v$3^@WNV@8wU#Cp~vIC(yQ0XR*8cD*R)YW3a+lH&I7;@ISGoC0zgj diff --git a/src/widget/screenshots/masonry__widget__align__tests__left.png b/src/widget/screenshots/masonry__widget__align__tests__left.png index 84e11d1115beab5473f9fcf8466fe883d525af18..093ee418669fafe6fecb8e0c874d0a04e905a809 100644 GIT binary patch literal 5708 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 DNRl&6 literal 5625 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 Feg-A5T)6-M diff --git a/src/widget/screenshots/masonry__widget__checkbox__tests__hello_checked.png b/src/widget/screenshots/masonry__widget__checkbox__tests__hello_checked.png index 946d33ccc60954aff364a067e948d4df64bc84c9..7a4459d6269138969d55707d5e7cf5aa5e521e18 100644 GIT binary patch literal 6147 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 I4Yp_h7uRV%xc~qF literal 2714 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 DCAwYe literal 2393 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 AkpKVy literal 3888 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 diff --git a/src/widget/screenshots/masonry__widget__flex__tests__col_cross_axis_center.png b/src/widget/screenshots/masonry__widget__flex__tests__col_cross_axis_center.png index d581c81d87612f64b713b1308cb95cceb219aa97..971944aa0791cebbb875b8ed1fef8b230f78e15a 100644 GIT binary patch literal 8110 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 AkpKVy literal 3888 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 diff --git a/src/widget/screenshots/masonry__widget__flex__tests__col_cross_axis_end.png b/src/widget/screenshots/masonry__widget__flex__tests__col_cross_axis_end.png index c434c6ed35e269659e50bebf2c67881b80f09bf3..3df7d4dacbe8edad59885044f2215b7700131109 100644 GIT binary patch literal 8076 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 F{{;nOGXMYp literal 3888 zcmeH~XH=6}8pmG{1%@Uzq_Z+>K_P=MUtA}SzK6e5-&1W*D&Fo6)jaVZk zfh+x>@dE$=N=~Qj&jWze%6un#I}cpe!bnu9*A$_Fn=6e}$Cg}t zb?~a`;&_SQIYrN-WkFBXhfmup`P}>x^piob@$ukuKb|HZhM94ESSNJGsx!KtUCvwv;yVMy zF+iVb2q-`GD-Jc(KW<);PC-HATPp50l1MsBhWQS zxz?uDgJihnN?V0-@Rz;Z`NCVwCtm9udT3Vk{NsKMLmS!k(gCw6euf;bE%f6~G))Dr zEAC$+8snCJ?+?g?G;Ro2CR1RsyLTTP-pNciJPOxLvITl~4TX-G(D+n(vL?FL*fEuM zym~a6RXh7K?l9a(8#gY&^mtxqWKrlk`i@CSg%p~Zh;L)s0YzP`yg-kYWvImA?9OJI zS#{WKeh@5#auVEKpimds!k6&MG*!6V_7c-GveJ=#TCxsHIaKK_!z1Do}A+sjch*NP47ws*Y8w1@g1Ad4l$BLHOA$T--n~ zuW`3~tHt~opF;P0FE3DXxDDG>njewJ>fZ10MG}2)8z7XjnbHkDOQUsR~t8sM*uS*$}f4WKA7Eo66+3y<)uCn#v{a<8hwzGH`3UMn-^)#d}&pOvF` z?u=KS7{O}ZQ8!=w4Y%CV{Kn6roq4HnxfihlPHLsy9K!NK-0bQ{OLX^2NzLl*JBF*L z6;;jTP$$z7XhXbp{k&7L+Lf3B8aI|d!gqAvlsxFw&q3viQv<_QWPaZU4m^M2>th;7 zK@+!%!b{wy+z+Agis>b}ZNZmwe6qQdltdaq<&te|U|u}Lkjihg#;MvHhU+&e4m!&svm zThmb&nN%xycYk;Wmo^B z^P3bre=+i+b&H(LRV9~5(AyIX-=?SI@{k-VzX)>8(=KW* zAIg0%n>e4zhAph7MPJDmGH6y{ZkdQZYdG?A;E;= zZmdAQ@GW0EXX@OQRUzxXFSfow#vg>x`ZMgp9K`E2*>+)()`Ic779O5?UX>i$(NJ@F zxdx5d0@CYVA{p%G2G8pr<}WiTMW%G2fD10W)au~b+P~0*?R0W(FL^Oxm4yvc+#hxw z+MP}+1$u3Jl2`6*ql>xu;TI!q)?K-b}@FvM(CNg{Y#kdHgbNvnC@+ z-DINm=%%p|HR5{AQ+4_OMfz;ReMRVz#kZ_#9J@@GRl|rgDGgMD@_(VMMOYl^Q8>Is%= zJ?wj+ERRB}g};c4d9X!+Gx#zvb6$XwK7$1UdK{QNN51g;JK^-Z{!lsrIo>ci3F29d zQUjT%^kSlB|A0@RY%+I-(#0W<6(Ik$cT_g}lKyPH~6*yZF`{o(aq z6y#{D{k=({N1 zZchYy;JnRKe52}vo>bOo#Am~)0HNPh(pt7V*9xqg^PlupQdRXkQfY*BVzJkiP0BM>@x&R2OT;YXK)w3p*@d2D(SM;}>_Wjtt|9oQb7Zsn$u>glL98(RbI!``H!UH$Cy}GK5$n zP}O&A#&f7@Ju-)Y2*nWTZtD6z%=C+o);dSpe)}1Qemf^Rv9Tndf0;J6Vj%a^j0=EP#-k3=VzaH~QGmvigCL4Twu&K8;Sm=5QzYrOD zX`i8whY?2GcQKjmmQqcQRgO<7aJIFEDtP*XZk9OxW=meo>>py}>Z~pU#MpJRX5VFT?xZ{7?J;uEuvY{(Tnw4#WQy3=-KN Y_RKV*qWMq3n=s(y;9_6$%hg~10m-io7XSbN diff --git a/src/widget/screenshots/masonry__widget__flex__tests__col_cross_axis_fill.png b/src/widget/screenshots/masonry__widget__flex__tests__col_cross_axis_fill.png index 1ed7c52e3ceaae4450bbb2fbf54e068f0bcca7e5..c32af7964fecb6158c4e0b4cc8b3f2fdf56ba34b 100644 GIT binary patch literal 8070 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 Gcm4-P!$;fz literal 3907 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 Gcm4-P!$;fz literal 3907 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 N4P#3q%=P<^{suce3X=c; diff --git a/src/widget/screenshots/masonry__widget__flex__tests__col_main_axis_center.png b/src/widget/screenshots/masonry__widget__flex__tests__col_main_axis_center.png index 79be6b419fbc844201b811592d342ba91864cf73..ed4db56dde4e8d209c293c70a6398691228e4182 100644 GIT binary patch literal 8105 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 literal 3896 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 pu3MV}oQ%yIVTvQPQE?GHPR-60X{TGY0VebF{ diff --git a/src/widget/screenshots/masonry__widget__flex__tests__col_main_axis_spaceAround.png b/src/widget/screenshots/masonry__widget__flex__tests__col_main_axis_spaceAround.png index b522d5a877b1650cc71d6d4048b0a9604d87545f..72493d89ede9ec324665c2a8c1cb31e4a7383115 100644 GIT binary patch literal 8172 zcmZ`;1yq#Vw`ayd2}z}E6c7Ok6X`*elr9m8tDqt!B{?u7*P@0iAWB~eQ5vPwD=7jZ zN{5ot(n`L4xbMC7)_VR~i?!xE-#NR^KEL1I=X<2DtIj~jO-DsV#h|Hi-jIq46M_C| z_QD9M`pgF^DuLIU=T(foF|&R2QI?)WsUJhO*h7&T=cI6p!wgOOlF2o*H2K~TLXxfWN)nYY*er9tnF-GA8VG~NKLD(BwqVTp~7HsH2d{!x~Up? zbV=yR5QBMq!uxOpnIuYk@Ct!+u!8(vgg_#gVzENvK1-~4Lh@HEHDkoxX7MDLPtC!M zr*=tRq-DlOM3bnRv<541bjOlCu#ZSong>0&USM8ApbI-o%y?SI&81M_W#BdUFAEVz%~wthM(8d zl!#%lp6sAvucs_haRF4Mb#!VX74*yUgeisGW)`rP@Rk~<@s=mUe^)M^Q1DnriX1@C zsew;|U?dR@*g(0P6rSKVbeI|f1H&dX5&rKpga1QdUg2%R(m-*Vb8a0dNOr|yQ(cR4 zE`nl1dYXtU#b&NJ8s^4ah@*>(u^J3t*&SAgVOwFFK__@};^9(38)d=5jJHt94}qV! zA_+X9$jP?W1{beNB20qSlNOF-5Op(@L}eeEnTd=OC#ScF6JphzP++3838bjZBvVz; zkxok!k!}!|(Sz+s=i{9x&WB?3$_o!DE&t7==C|=VNA=`&Ue>0S@;lvleH9GG@NK%8 zU6V-sZGZnMqok~6w>E_(z2S#~jMHVEB1#MS8aYFS@Ai`EV6*7X3_OO!&}SllTPe{f zcJNlg-@r;pNaPO%Y}65l%)PfzzL(iINxGCm+40`c-lM8GoB%vC#H+ zijqP3jpHYstGBEjlqvIa?jN2WcdcWKsoTS}>BsBU-!PIIsTto?Ib!~0!nW~M^OZitX_*&bJ)HArQd@=J3(>(Lo>qvI?*2Yfe z=tyRQ*S5eyia?8w?yRrE^2hY9ND;kYYI^oNv&AaO$Kce5==L5T-K2}mXYw~1l1p2LY2v5*zR||o2ev(Y5cZ?v`@2?H8 zU89e~HR>_^wW|EdbJIRe*4{c3Du1XU5h_ zVL%?ue(-mHaEm6OpO8&2FNonitttvrjy@()i5eDvMy&Afa0*x2(;(2b!pe+adF;Ul ztBo%Lu4jFFqK(LFEY6G+mHWc;RFm?=BYiuUd z1R?u3@a$Xd5kw-g)WI+wRV)Ugen+TB?~=G_mtp_bYg`|KNjP7i)XKiI=Mc&h!BnN& z_X8T)K%Kr7#B^}*G8atZ7Q+*`-%k(!OAPg}we>u4WLS{~R-`#*UO-kXfE5e%b@3`+ zz}oKnB&wdh5$}-Ud7cB}SkV&b{;>)*g)})fpSWF6K{nB9fGYXvpEqaG>keQ9NO>-O~i^$Zc@*wuF&1 z3@<_)7u)y2FjONx`+yhs>P(ym@x~S)rhLa#55%ZIv{X7|T_Z_1KoA7-Rj<$V5jZT& z)VM}wOac@_@x`0 z7dQxCW-Fs%zKsS}6~fXF*z-E{+RJ<1jB+8-pMesvMtDU4#X? z#GcVFl0#Hbuk%hY=c0c zBSLVckY4vT#o-hI#q_r0jI2kWgE3dTKF9Nr&0n`tf*9A6h@B^$ddo*DmRcv>LxXU^ z5ZU1F)29#MQ4KgGD!rK?UvWg=n9S$ZfBeWrP60iIh4YU6CH8EQM|47qii*4!n}!^F z4g3-neB83EhghU4m)&N+q$`g!P$;XbqWQPJyt-8KBmYvV+gSRZ!U+~ZwOT8`S*|vv z4M*SXJxmJHrdgNx>Dd)7%l9s|Wf-Ik56mka9SrbO1x8Aqpz@=Mf}$}h^{*!^`F+mi z^`2c@p7Cz)Z`=y(kf1Yy9(tm5(tUg|L?L|W*vsR8@%juzz4!xZ#z6l%iJ8Ri{8>2)w z)K5&zZw=~BmdqCQNzPSm3@*zh(nRTi9oZ?rEcM=rZ?w2126tKcDW>Zw3o%4k-szED z?Y_3=y-*i(Ya_jm&ujB=^iD89p+2bvKXBk5NJVg8WMN+_#xzdTD zTN{j;cj`j99@I|fRVs*LVXDo zp)00Y-r1|pc7_u<%M(FNtvZ3Lt5N=+qj{(Oy&@e&C|*{|JrgR)FR=`<7fGjRI_+Mw zXlyU?EBbm|e0Cy@ox9`KH)$DSm-L;Pr`>+@mAAgR-ImZlL-da}?rv{4C_k=rqG!hU zO;J((Lzcb#a$O2?Y{`}p{#JBUtB1G#IhU6Xh{oE9FC?c;gv?qfeTm!wjM za$;qdMvmW^(OsCfR%UhR%zE@|iKEjwDk*AkL}M_`BQgJG`|#P(2>bTSehr^W=WF&b zW!%%UIA&E*;%-(Qa3?%TiFmnq;pFv;^Q*n|SUbQ_yUA2f4_YCN>xbh4;rHl4npLju zn#hLI;$JBpE^3Nv{f|AY7o+@n9G1TuEPTmr4W>PCBz0cDRcRw@xvJ69Yanj_qlepD z8aZ+PA3PVEMCw@zH=_uUu0k?zBLg)`9DBxd z=NRu)xsKe?+&T2eqKo!kKZXgG#&W_*tkC@4DM5sIDl|W79GGwF0^3rNX)wdZB*HW5 ztT4hJC@%K6TE+sT+5y(u&E*s#E+Yd3>s{HmOTjWg!EvEmfPMInFMxt08&m+8S*2aJ zVePhG>N$YjQ9~f}0*PQmQvVL0Dxpib0J`=9{O{dUt^i>E9>D*7ule+0)E>S6AWjhL zxJ54vD~KS7sAw4mMnuD=McaG2vcEFK;(~!+g4;z*P($SfO`w;A0W%^6R?hAUtgVfe z8lXR^W*&;JdHg2)q#~1nA;>;lI>}O)1{z~1XpCPCu%mKp9bT-Pm$AZfG2w_zs+Um} zbs!eHYi#OQ24kgNvA{J=aWRA(+(A_vcwzhXdh4##SSX?n{e(&vVD6JQkRsh@$m58rhVjb4QSTwT*!L0khRkF8o#%%d;RRFdDq zoVTU2sHcnusnI)ZR1gbO?1dyV(!t80DO4ekkKl1_A z83j-`6nK1+L-}G0xnp~~gJrisn1%vjN@B_v6lXkykZPnzM8fJ7$h#GGiTRbRPu zQ8J8Du$Yis4X#xi)u=Ah5&VRmg zKmo(TYOGEXsz*+pOIF5wdgx<`^x^0v;j|7C#vpolaj3weD|~2|)oVDhvS5jU&j8kjzil8yQU28ay9AD#v%s@8BW3LB=- zxoCwfZ{oTnVLKWgp*D9|=0V{(17Z3&$?E z;O>k4NSNQWo2lN}UidkpR|{<3AV@jJIVGH+_djRg>!SlAwab$aYCk-Cfk=~i>}Q)8 z%_;Ez)KGsY7v06D(n{fSQ;l!#dR01jTuhJ?W|z3k3m~t#7A8<_@upZW%p}vaA%&vE z?NX6{VxW4gLsx$G;6C1u{O=wVch)PgYsXZTjs4Mw6BGRSX>hPA|3qft$M^K{#MNi6 z%kAoQt@87{AsosvzE`}z2`?;nwAFIm@K*vEQJ1RxFNE?digo5%3&dD&hn37%$xfDx zik9ARdrNH{T09gW-YWV%kq3&q=;3&)c!Cb-!>z}Tqi$o+%e(6p zll;ubpW`yQ4;^xTS@rubDW_rF=1Q#}u2t_47a9ULC%sp`*yV4`MUK?-Y!xEwP{q@NB3W}hC8M*ajr=J5Qk5xk0z%f(vM)nCgZL& zIWS>Oz}S29Mbw{Fze3??=(q0^JBQU-@yCH8Za?16hr74RX0Eby7W^EOn%8}y;hb2# z()sG?>FLe0Ur8_Xp$4p<>9N*SUM(AYV$pFt5w0w4yrbD2vT?o#pzdvlyPalKTt6DU z?z6aHviN0isWpzRsbz7rf=%4C_SZyPaERo(*5;1~LwZ4ir3*?9oimpTY&B2R1`*P5 z{$a(2vqjxbv~S+LIlstavdBamBVo}w{lj&nK5ZxBM_P=PZcu6$nK9~e@>IwHyvYtj zUH}~1{f0G)5i0-4qBCd$SPtWjZd>C=2+1Ge6n>mFLiASv-EU7%9O_=oX+PUpVGKFc zI8gVy0+6@j>s$wiGXr|um-Hzi#yT~=w9F5g@d5M*32pR&jr1LL0Y<3Ej@UotK^)CN zE4ZJiy2rjd1|rVPT^B}u80}}MoIi(sx(6%uB>*+D11uyEYCw^)SHu1+TI&d#5XY;q z%b!%xhf%%VFS3h8;Jo4jd6QK=Aw)G&#zf~@;gWCh?Ng*z8?V9rrMB~e0T zlm>W}gSYc&3^!dq7z_?Ddvb$IB7Lf54cKN%6 zP$UdDy27WrM_Q3bO@Px)JdQrdi70R)Dr=f`m%rkK@Pt^L6F1oR-_1!Uy3suXQje%` z*mD;m)=>sum9^?&(?|p+V85VRMwkz=$%5GAucuu`(Nu#Vr?b(aAm>B;V7Rx6npc>R z{0LS*>P|;=@eE!(E3=nCW;`bpQ`rw!pz+_kH-M|a>nlKLDiU8lg`kzfWq;|-pu;Ey z6vzcQjfGJYRE+#CG~)-$h==*AknO5VnX5f;2|!4Lkf!yypjw2p z0+^^G;Utn1O^}4kkpH#w|C=8xVWWh_-3P3>@BEz(X-EYPwtW()URCAbyh7Sfv@(NG z|K78p1Gm}9{ZNkdzd3gZRv&!=`DR*ej0(bj8e>U1w4ncI zm*db?jUBjFH<_V@TtM|h=AENxxDLp-ZZaB%Q3Yth_MIL7KUe(OjBj=mjmA+_+P|3t zUFU~#pBCF5QReS;D|P}CpjJ{%?vsz;SD(e}b6@}$l0&frgJciMyu!lM=@)yH(PaQV zhY~kx_$U5ep7`M$p*i&$+@Rldgx96Fs- zerV8tDZ95pFLSupVdur9=;HW!EOJod9~Fk?np-= zfxrQu3CsL|t##yWFz7TGK_{kB%RM&K@4H|V+hgr-OW=L3Q5 z2b08zQGSg@S5r5*kFk6#U`g305Z_nm6ht^geNcx)$i*rSl0$iA3mU%KTB|p#d+hxE zph~$_b|R}}YgK;uCv0{D-&+3Jt>xFBuEBSi$+p%P#e=???j3r&ZapJVsJN5^il3f! zJ=b-@tIw%xd7xpqE~JBK^g{RL0CS+QbNQ_GNSMr-f%&tWKi+-1mWa3^Sq=-qhRR{# zM&KQ1A?tSoH-SBV_~dD9rJz0!WB-1dz^#~%NCJ?M+86FsR^5#C5Z<%^>Q`#^?fxbLIw|?^ z?q=^Gz@p2ERk$w$s-r&)mHelpb^yG17r-hPJ_9Bo2D;th404qHF?foFE;9CSM+C!B z`f#B0UOqXG`m8U&H^!MmrU(tn0K>}+%20RtN*Jyvzsy(Uni2sS;9KXx40A2ir6z*r z#InEHL5{7k^g|!&M*PS4-FsseY%SbV!}$MRp%03FJx!hhp;IgU!GIHRr2h}yFS6pl zL>6C#1;0a{#t@PmR1|=!tgWc!$S4EMTX!L?K$L9YOPp=Q?Kr*HsJFfaak;fRfG}Aa zI;|77=Q#ewrkMX1)e!`E5dt7G7D zKhXh|0AxdG%>VtkK_V;xZZEa8AbvIk7&Uy8?;DZ_b{9a6)3ZjPMyC-FS=6=<4glit zGi~C8GZx*uJcWT37#lA5YJkDUL5*>p-U9Z*hVge@3gTUR932Nf?XTj05&3I1<}|gA VzDCJTAr<^-UeGx<y}>x`3gFVh9tOp@b3=Hq7jv-Lrf4%bxwnwURUj;=BsjkCD)z! za`b*@+M2l>jgywo5P1AzXt-(7#jf0gukL;be38$Beiknsf6ol6@1hcf_CuR zu^si^(x>-}ej@<5bm)-5&8?bi7N^yhILy&L%eZ$!tEa4Vaax$B`Q6Z!rbODUlC9R& zR@lrFk=aZre@DIVxC?jh32ZL$=ML8Lc-JUL)oUomWp5ihK-_nDfy1fI_i{YD^N_{J4{l`)loeDUfPPAaxWtLb9IdiI5K=0g9+k0&V*ltp*e zX6r~JGnw{&G5e~g%jJ7@KNVZ~qdbVAOz1#4xJq1gekoIx&Kki7dutxUbsUS%s(0(j zqRigLy7i2ym~1RksuF}_q-&4W73sp%^|ztj$yw|HB>Md zjIut9DKjXPs$x=y!=+(C-rnpM0)dcVjW`^w=-ZXfYMTh1>tU8da8+8YAz1d}rq9@r zO(**4)2AvSjKLD*6jQa}lYoHJJ%{mmhHs^arT9rW6=|gzFfHfrRq51>*`4Na*(e$5 ztZY+TuueI6U$H>!A^-IZ_`%M4mI%gsV|H%lMC_t9c0Q-fLS@-8jBI=9hLWlG-Op=X zMyf$`Yh6l-AS>N-=Wl7~cP8onynJ2(HOnHbqb&%t6+BP<_X+belD4^?MNozBu_*Yma%^t-=kB7oy)2Rpz^ zfj@K_7YTUwpG}RASHxe@N|4+vY@AC% zC7a4Tyt2}|wbD5KhzaYzmP?cYl~~4}_RAD5GDYdEG|`h7!KTu|f6=V13hb4T*5@*H znf-=Dw1g@qmVjiZ7Fi>-P=*Ek6^>1E&dAMSjhW~lT*VHIsKFY6r$V)%@1M<)|BBw- z-4)k(V4$<}xu#TH*(KBwxtWFy--&CSjVqreuw~G(B1$9jS42s&`xp(*hOn|Ld5CA_ z6z1M~HhG{m7uHGb`1~QG{q2+Fc3Os2tl(+x39$3ds{nqlWCy#U)aCI8l0S;g7S{?g z)7hSWq_NTn?=V;5fG<1k%AS)moXa5Y-TmeR6N}hdvBSFD-HAirNI9P_O8zxd4{7q; z__Fh!oth4`GeMD_ube>j8qVRi~2Ul2&n^Aae)fL+8M*dc+Ms-YruwgV~6sl*i)@^Yx%>`SsU#lU1ber z=}Hj$L^ER&);)jngn~jP&8+#ks(VNEFD0F{42Wb&Uf9iBnGYfoq!E4-!4#n~Wvvsn z?o=^Z&H@!o{ZytSBEi#9f@H9pCLfN()4)se2#3heoQ0_bFD2@$`KE*c8h!s{|ROGf!Z;*k9hsx@>>h0?)0z zKN~;$$-$j8-=maT9WEEP$q+Tq;Nrtw+tI@Bs9z)(ID|-FCkx^Qm+!?S9i5&v#LBO1#1VAVHUo)~9b_2?g;s~da@roLqGP|5~b#HfBJSzh%y;>%;%QUV4+ z&xL2i(9FrAY`9>MC|4+2@waZ(KJ+CJ2K~#stgec|82xa!gwtEG8f)*lv{4i93B;-u zYezPj)5MQI#3N|h*N)U*C+PpjSEaTdQuzn^3jv&|&Ol%!XA>p%43Eb%_zip)oa>Ri z^8F_B%FH7VAD@IYd2lC=5}~W^vu&t3=*KI!E)$JdW-nabcy$UTvPju?p9ouA3f&m! zp!qbDm#YnrYyKprfN}F&G77xGKUEL*;am#D;nG26Y+Ucvgmp^vFx&Xnd4RxP-8Yud*5z)0 zT%fF0Z@)L~9g{yZ+1x-f)Bt$(=>cCy7u5uZvPK25Aqv z6iO;0l<0Ml!8jgQk{?l=vs@R!31b3EZ}Z+;Sy`EYC^stL`D)br_g+fGN=lN-WmR}N z^132hKUl6)UZNDFH>50F8i4c6kGy*IYAVcMP%y@XRQ3{sQ8Y=C5~et9ZElbD$y_uY z+gutgPXGjovRgW}@3)PYIm8qtX{jXXh27WL90Ix8#tpV2HWmhS>wQM=xh?b3L*hby zxXmbELHUULk&k0zViafgaHeLU?b1|h^RC#Z&O}tgQCUa3UK1ZGLD#mzPL$`ykcxY_ zvI;XiiLM8S*+*?$bO$cTvFxLCI2)?U?!C(}X2<^bpb}?M1qFp+N+5&>Ujg-#V8R-1 z1m_LkTQG%_;6!cJJcJ)~bRVY4X8`_tavqN4tLZy-7{H48>bZPhP@F|?hq9EoyyFAF N4P#3q%=P<^{suce3X=c; diff --git a/src/widget/screenshots/masonry__widget__flex__tests__col_main_axis_spaceBetween.png b/src/widget/screenshots/masonry__widget__flex__tests__col_main_axis_spaceBetween.png index b28fd7834447defb453dae8fefda52b20cea5a54..1658b8e2e69149ce9d9563fa133af03b1eb3c895 100644 GIT binary patch literal 8198 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�}1ynGIf7 zFOxUUvlIZL7vYjyTrsb2r?KpoJ1b^Dkbt|TM4RiWA7;cQT{_S$o0;L4>disRqYf>k zdq;ho{lB(7F>Hw{G0ru=SD~NMk!NKUFp@9xXl*UYE_Dkn6T&?6Lif=XuJ7N!Yxldk z2DOB8h}yJeoW8|>YJRW!=kD&?@7<%ITUYX7^kNk&UYzIc9!xjVnNq{4?ViyDo!4cK zvkr6h3OTnEM^D{7pyw+-BGx~UAZzcne3YW={_o3| zU?$5hJ_0sSvF)JWbdfifijb6>2NP(~!FfV;|4p2UMm#lWG89WRR@FRIWA2-;Ia zXHhrkPdznzj;E0gkY*cR^u0zFz%sHb>Lv))0;sq%9g?U@{3ngVh-g&P${1NTis8&Q z1IVCFP3@p(Mm7{**KsMtO5Q*my_w0HZ->?ZmJX1neAhbyS zSI_@n{RAm%pt#qd%3dQo5&$_P=)xEk{NUCDTfVYxmBOy6=W%QV%pWLS)klK)NumPS zppZji0rBjmDA z;2F=OnP-qEp)om>DG-Llo=EJU4r0Uw^I*IQw=$TCS)0LOGdmuMswDP5@^MLPARGw^5v3DY^F^?+qTlVrD29)r`v+tO-VNVlc0X~M7+^hz!{LL# zX=+aVuqp#>4Q7WNjYJFrOU1Koi&h))L2mmab&)$)^^>q08oj%vTv5v`#t3eC|JSjt zxbkBoNd$x2DpmfU`v6K3j6n7nonmB>6BVF}zl_Ydj&R%%w^=t_K>RQPI77mHR}}s+ z(2$II`sD5jlqA{{OsGa#{l=)1UIG-d>S)f+1v>ixCo-zOj z8uXG_Vab9WyIz;!?U)=70^kfZCfoq@^kDt1IuL_5-k&7&?f-IwHU^81&Gm#K@OS_` z9?i?hgZ_95bM#of*`fb}%FsznfN%{wa*b(378W(KfLQxQrXosi4SguPP!F=zKjBDK zpcL&BrDxF#Ao_M)S2q7X3;#%dl*0aLRNU9MP+|JX*zO`M!@loI)!Upbm9@n|o5uJ< zQ}p$R)Mg81G(+N`3pRxx8X>ejzu|31I%p?4D8{^RA{DiJ3+V7aPYwm5Jq z`FcyLs8-}n_0>1?vx{TxW{!H=TYi_h+*Mbi!Bjtcr6Y^R|vS& zyZlbefRoS*S|k#(>96=yLLxKP@E1HSG=B65Ms?sM;uy;#WwSAf}*cIH5(7PT?K z#{;#C4*5=sJ5iG^cCX*`{;*^NpRF#T&v~Q&HYtN%5&?YXaLz{TV{u3|zVy`FW+`JRKd z+O>M~l#T4HMDQ=$L>ay(p6~T7Gq=5bzT0JL=#D}9vF73#_!<`aX4}f(teUphcCjTz zNhSHeUw^2N%B|b9y^-Gi;#gV=z7}q@0W?86rWqyJ`ykWKN~^B+!n*MFK;j3rmBykU zFFp?z4XSa}39d{j{wO@$YAYorHQMyyu|j{~Gw)V|jnKGMnB(YLSHd1{)1FS?jtXzpyu8`-mf9W43Y zvY1#|EUP+s134yB_;*L;W%{1}r@DPk2h8TpUAqgP)a`$u84;H3+qXX@WR0=^>DYbS zEi^Soej;f%O>NUdImtqH1b|~G78O8byH}G24@A;Y+G|Gb(WBPK(6Py=THi9x}iPvjoAzVv?py}qPj literal 4192 zcmeHL`#Y2UA0Hib5ee_gtXnfa1&e>kbQb6(BF{`4`3 zny>BIox8e>x74|j9d4Mqidv(#I_aLTEBxlXyg%2D*8YH#+v1L2Pd9pkVf#Nq4jxdAZjm<)3ka^w)GV%s*5{upJe zRV?GJm>gkmqrcm}J;Zi#h>xFmCg8lEJn`6~cw9^rlkTdyXG072?;Cv=o42x{Mnat& z-#6LZwMO=p#2j~nJuNu{#2N%K5DpWP}T zsv=gGavndX#~Si^Di1`^UOi_@|1ThHHZlpMVML zFW1>UXeVqiA*}BS4%&|yg$n3(+~Y&4hRRXQXI9a{c`iM`gQ7l&4e2m<){H-g*roAf z>B&hr@@dkowfR@De7q8yU2kmTyiZK# z2?#v8_{Q(|@vF0Gy$?1)QoW;Rm`OARp_nCG;0=7SZER)x6C^2e&3{-Zx3(XEx9hvx z#QFs$e1x!ne0J&nQ?GQN_A0~v6047ow_9`$@5iWg-7D583PDC%s!-a8KJMMweM==VL$hlE&E8^J~>7kbwZ&~F#4%FzA@nvN~n%D%F%#umP?6N$Q{N3fwh~u+(4vX`^%*ZT5Znt+9(PTK@gh0!)H48J&^tVf$miG>nuVT?S`?ffg?5FIBFRGlbOVLP8K$ z?x(Jtd+PLqPctmAThih(`qj<9wnY++pZ$k8pH*YHmf!U%6^4TdRyughycJQ_NCDM;mT@(~Von9~J{!oF4He900%zQ!BDxma2$0^1=N#%7G&Y@fOSm*lacrE7O# zzcO`!3480R%h3nb0qTD4YIN`Miin>)-9Yv&_w>)XG@eCE z2&)d(@Rnh$fdNmFJ3`V#ZHXE2BCUU(C-4PICeYV*x|^FF9jdGYTCSs-qlbG^CyV#m zq|D|6D4OD1pt%%C_wqcn2K&`_$alSn7eK-m`K%u4trc!j&C55A zQ655sa6F+(MgGi%TkISdEx-rRom%ILG7bYry`H_HClzCTPjO+4x858P#T4c3VR!VH z+bMfef!)d3R)GRdT`PM82hT$ze+X;f(LNQtN@_RnDO;- z;`;T7xQ4xqsc%`@sL0QiWPDs{Hm+a8rzE3^RO`>GA$@gNUz=R$oxy_VSE#ZC&Gfks z4e{LGWztEh6;VQ~mTRsI@b>;ZE7}fH=r%S2d2QaDxlc~+kdp)G+#cnBhJWvB@ESLu zgB1OyO?r4#sptEjMVoJg0w$pq^WhiPp1pd($`;}27QR?%P*YRW~HX!iis-MuMBdVnqv#pf*FBJ zIw!8LLHCbdcxGt^u=-D*UsI3cvU~Eh^L|z*cP_cB)vOWsTzGqS4&?v->cGP0U@ zF^O>nMT5lKFMm+F6f#U$=x?KRiH>q}*W0$X?#NI$QFKBW8Ym5(s`RF^i` zV#B^@re2kaV#=*%31Yp~H56GIxGCs1Ab9bfBcQLD+W~|9k8}C^`?$0%SNTKwab1cQ zy$3<+x&-G0e?PCTq*;Hw1gbjs&OA_gsq}4J?rN+_|*<9E*rxKXg6T@y_e! z#8a!d$>IcdzQr@nZH0+K-9118$TLsg2rh$I)|L4OXiPK2p*01L&bk2_DnZD5ZFhkQ z=B9B6!hpoUO{Up|>^vtNCvdz=C0BQ8OQomQ=8!bcA)3}c5BqgD>(R({$s$|Mvm97A zARu7B*f+-k3S~78&o)ws%7EdpB(Bf+)9^8)@9Ms=Pq*0~uqI+=F0GsfMSTX#MP9ph zoHMSWu^Uz3b3Q02C|}cBr@n1gFpn#>^DJl*jNl;q<#+~5si>6B%od-P-7Z>5S2Yno zI&bo;U-#DTdz~ic4VI_Hj5Id)F&FtX3wQ8JMWccPq=CAlqPf|)p0HG7mM~GvAf%-% z8rPx@$kYJ~_7;O;5D{s$ehmiwHo|GY<|rTk2Z?AZVwT+~KXtKRe!yoMC!Z>riU_%8)#bTFL7RhD;%Eeeq@{-4xAi-&O5m~)}INz^KVN+25|rY diff --git a/src/widget/screenshots/masonry__widget__flex__tests__col_main_axis_spaceEvenly.png b/src/widget/screenshots/masonry__widget__flex__tests__col_main_axis_spaceEvenly.png index a931e57fc78713d4f12adcf90428108003b454d6..0485cc59b563d083831cf2e762a1b444e797e2d2 100644 GIT binary patch literal 8185 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 AkpKVy literal 3888 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 diff --git a/src/widget/screenshots/masonry__widget__flex__tests__row_cross_axis_baseline.png b/src/widget/screenshots/masonry__widget__flex__tests__row_cross_axis_baseline.png index d24822ff67fb87d160818e03eda509ea1c6a04bc..3f551cec600356069460b36faae4749b1e21d075 100644 GIT binary patch literal 7897 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 Y<+k5Hvw4^1D+f4n4B}n=+l5>I10+?2;s5{u diff --git a/src/widget/screenshots/masonry__widget__flex__tests__row_cross_axis_center.png b/src/widget/screenshots/masonry__widget__flex__tests__row_cross_axis_center.png index 889abf6a8d6cd313e0e2a090a93c9bea00235282..4d76e84ce81a5104327304691a7c9e4cc5e8369d 100644 GIT binary patch literal 8007 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 z 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 F{cm$9<6Hm$ diff --git a/src/widget/screenshots/masonry__widget__flex__tests__row_cross_axis_end.png b/src/widget/screenshots/masonry__widget__flex__tests__row_cross_axis_end.png index ba8fca691a5f5ae2bf6f5c375f285421745a562a..fec059af8068709cb94de4106ce1dd27baf48945 100644 GIT binary patch literal 8006 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 R^`9i<*q7nKj4#f9`yZPy?S}vW diff --git a/src/widget/screenshots/masonry__widget__flex__tests__row_cross_axis_fill.png b/src/widget/screenshots/masonry__widget__flex__tests__row_cross_axis_fill.png index d24822ff67fb87d160818e03eda509ea1c6a04bc..3f551cec600356069460b36faae4749b1e21d075 100644 GIT binary patch literal 7897 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 Y<+k5Hvw4^1D+f4n4B}n=+l5>I10+?2;s5{u diff --git a/src/widget/screenshots/masonry__widget__flex__tests__row_cross_axis_start.png b/src/widget/screenshots/masonry__widget__flex__tests__row_cross_axis_start.png index d24822ff67fb87d160818e03eda509ea1c6a04bc..3f551cec600356069460b36faae4749b1e21d075 100644 GIT binary patch literal 7897 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 Y<+k5Hvw4^1D+f4n4B}n=+l5>I10+?2;s5{u diff --git a/src/widget/screenshots/masonry__widget__flex__tests__row_fill_main_axis.png b/src/widget/screenshots/masonry__widget__flex__tests__row_fill_main_axis.png index d5d41a201384f59b3878b1108d0ec03e23fdbf56..9dd8b16e820075dddd45d203c88a140a585e75bb 100644 GIT binary patch literal 8018 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 G=f40_LJzP2 literal 3716 zcmeHK{a4cW9>=oPDs!FgvT|y7?ac0JYU8t^uy zkU*R52eyMiAe*4m0pEc@R=;elZ68^7ido*nAkeNeK>`1aD5zCU?jThm@a#q6m2l^C zKlTrIjDFSow;o*Zr5c>dL&oPcC8b=dX>SRSz`>w{4+}%{qh9uP=Jt>$$0Ff>^4AU| zAj7T4BYry-^;zJ-E&cW+mf1YK`|MA>f%|M1Q6t8B4c7Iuv^uutF;}fOUb#Nj80dBc z6dg>2x`Co$n>LY3g6pnE1Xt(&yGTD9d;)Z1+qNgZDNl;6#8KFzBnBvY$H1+%42QhY zAG|L1-KaSRPs0~Xw`fOCngzP$eV%EhLag~?z@%%0&fM~8JqBM7gBYg@5hm?Rp~Mj{ zCk6Y6dzymj4+biv6!PSfjaSk$D{*on)N=FQEV?R=?z7g-sfj&P<=Sy`kL|p_-F^th z9NU!=1a8P|>yW&9=F#R#eba@Sr=~;aUb!Qleaz-vL9?;C|TZMT%ott%v1to!t zUGD}&*-q^)mE93_Ka^OvTgdr9Cp*Q+9zB|Ju1m$qTd=^%A$X7r+pLRk6oWq5{R!yv zO`A>x{KYrWZY!&UpC1GTSbsSDFogdB6Xa1=)yG#K)_BN%)6Mh1OV5csTg>HCMS_`7 zf!u7!9g*nBFy(+fv28RSeXeWlseUkbYJP2dPXyIrT;oDd|#QJ8=;LrYYKswhEZ>;(}fb|exG@w z5?+rBi-TzgY9LrleC}W>LQ-g#haD|wL9*835d-_fGt~?;)3Io-ll+IG7S3rMYoxSQ zV3udJvs6z6Ro;Z-_gwNBUs+t^SH>|Pe0lbp`w1N8 z8m85MZDP?Y@7*X(%Qv@_xf;0SyLXT2UNtHYIZbpk+UD~T*>=pMowow!6J&t=-H>~G zy&?XD#gQV=@-wC5TkMQQerBTv@%-;wd1HZQcyMh&fk-rCQezYGD8)^L3NVXJwuP@q zBZ|?Jwk+K1W0U<0ZSIk|}UDp#3SL%^y;5kT)Q|7Lnr zm|oBAap7UC?g^TqFRPNHv08d@7I}i?-SthoBYJs^94Q{_4{}CRN^GUZp9)32yVgn# zVs*A!l7$+<`4B_=S66)XlTLz3YDJIB5uYp5PqiYcB+R*XR5OYZ_Sm<k&%K8%)^#BIKaBzaSvGT(Po7(i;I!spKx7Fj zA|9;;fCi3!&baqDYB?WvtI88?aB$h1ETk(is&;9t)u@h67!q3YG|CjhyH!BPu@ zBV{+8>oSHi;dALc7s~R_zLDeL5x|4t^B}3W1d!$8awOf7HRQr~FPpg!ZM_dGV#?- zq{u%sxXkp}HczxiI>#wtDfZFjBygt87rv^Onop>xvyMQ6pMJ6tJWW*+q;_sZI0igR z@Z26_=}BTZmmyAfL{7Rlt_9&ahe;Y{a&X;jb3KM;-x~6Ji3|)ue^M!+MJLyrWig7qp5Dy8H8s7?(o1F@<`b2ri zy`xOby2kuY@&2Oqk64$APM^io6z^rz0S}LMz;At9>g3uU@bLZ{jc*ZzvxGo&&9<7 zN&=l(?x*|FQZKpVY=3XUh?1kmTx)~hxhV6s^l%&z*d zs13pOSqX_IMHTc;uy;$fXFA_vs&0tMD|gCxg7-wj!j7Vr-=(UKfZ8h&x!ZRX3+g_U ik`LwU|FnFqV)tw1OpjLBgynY$3i>uAfbg#i*ZvDZy$V_Y diff --git a/src/widget/screenshots/masonry__widget__flex__tests__row_main_axis_center.png b/src/widget/screenshots/masonry__widget__flex__tests__row_main_axis_center.png index 334a43e20cc2f7821d58b98ac3e653d8f5b8e4e3..c790ad3cf07b00237b977bd3c27eee8b4b00a51c 100644 GIT binary patch literal 8017 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 NQr5VbbHV)n{{c0C7I**v literal 3687 zcmeHK`&-gk9>#LgoicUWS<72ZZn=%OZ5^e&QKKW{T6RwX6=$tb5ouIHMZl@1Y#JoT z*)k2S$vGjC0g1u4SVXs zU6&WJBY@LL*3ajq`S5>YaNyg31onmd&xc`8GKOEXj;_JA%>~~17c+z@7Tt>9->m3% z7f3#dJ9s`nX=m(DKe@2~YTP{yhPZZ`-;0!W{Sn^5)74t8X+Yn*SvIZKF4vskmis^h zcYuYAY$z%$ z`yB<`y5oqd@m{*Vr5{X&Qatbn^+_%+Ne&pUj?e`*UJk5EzU&s%s(I(EjB?u)zE}ch zW*iFtCF^p4RQT{8w_7`>I7LcUB6?xw5bo)w2LAa!k&$|-QKl^Q7Go_v?z>L!p%sij zhPS8f?XT7wflux2`Ek(~bKp>~khhfbhw0RQdaY^Vy(pb3Q5Y213`7%Yx!01>dq>r6 zl)6Wm2D93@i^KC(Y}N6VI;z$^0vyRUcJ1)**Q$mN=)24@1!q zyrm~POg#0w)efv}3zRm^!?29UrTTm%SE_4;w6y@D``*R#JpiASHz(t*SvP|WdhmB% zi*Dl=8EH!95L6sK>^FX+gXgp?m4qHq6Wn z&f=LD?`{e{#dM9c7z_exw$BwiOwapslM`?TPt=aUTw?WA_1s|2YW$sPV@e(68(AL|vAycT`I(QB81T;v=P;m1nI% z0%NxxlY*BPA}AX*H2{!nmA!*z({!T13qK0qu-)_6d_${M6Uk}fZ0$!sv#Af5i^FLMJ<*aX@`|8fsCIw7%2dbrsTf(DkOIzR3{uH zwWb!$-U05&p%BA2Hf0Vq=f~mbDoWssNdIl`)Qek9V#<54Dm5A^nLZGy@8jtBmO1IG3+se+>mjCg zIN7`xC(1+tKF6_w6#QK*QE{HLC{n;T1~y^XUP78&n0C%d{%~zj4%8oQSlA>{2*0^_ z2xqky!OgwrS@1%6rd{`L)R8!pUO+Yw#lp;Y4P_uD2ZkYH}c4T`R^xlAvC=0wrVcn&@hlrh2GB zA@AMU4mdjcF<)$t7Cj#?Em{Hd>95p77`Hr6)xB`(ARgc6tztxF-KG+ncmh z?jFhU-6F>5dx|tqu5o<6^E$Ip;`F@nkXZ23w)iX&bCc57Kq^}?6UKL9rSIR);O2WA z_yO$E;}zS@@rY*C@`d$YBB$P$`BCcSX+o5?-*Ui^n?l^ZhJTgKa`Q(`^Z>bV%9w!dyPVNrN%v*q<8j`5 zumJ2p#_^MH+HYZC%KFH*fNNFZY!q>RtOwKiz^JZ;8Ww8DY(wKb}!h;!^nbdpFU2QQn2i@)|-> ztQVFa-p~4+3m*S0`T}$EaCMG|AtjWttHN;b7PhoVcgtD%iuTZ;!Uwhb)>Iw~;yq|L zULjUvq%z`}q4JvauZke(`7w$p_wGcj^uL96_;01j_~Aov+KxIHgTx+1ub7sVjmH!b zg9RpyZCCxp80nO>Z3a${1p{rNY`)5xS+!|(vkFxxQP0O6wb9&yN}he$!; zG|l{Up;x}IrZ`jiKhDPKd? zfHe_iU3WcLRQ74-+PS|F4XZlK$5|&rt+qS|nzy68mS?aWonIiU9vIxXk+3X z?O3szYpIV^REqdT`2a3r{#PcD{CVWFA58K@Fmp%Uenn+^St}(})M(44vgHBDNM^%+ zddSGN|I8{KoICM+oALlC$)~>E7HmH_><1A3F9T<}<)gDlX1n`VvI?yqNKo8Y2{El- Hrk(vA5}MkW diff --git a/src/widget/screenshots/masonry__widget__flex__tests__row_main_axis_end.png b/src/widget/screenshots/masonry__widget__flex__tests__row_main_axis_end.png index 7d9f759e9af0351030bf4852aed675d2b81d97f2..d9563b961dd0c7a1e9044552b949b9b668ab5952 100644 GIT binary patch literal 8019 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 literal 3689 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 G=f40_LJzP2 literal 3716 zcmeHK{a4cW9>=oPDs!FgvT|y7?ac0JYU8t^uy zkU*R52eyMiAe*4m0pEc@R=;elZ68^7ido*nAkeNeK>`1aD5zCU?jThm@a#q6m2l^C zKlTrIjDFSow;o*Zr5c>dL&oPcC8b=dX>SRSz`>w{4+}%{qh9uP=Jt>$$0Ff>^4AU| zAj7T4BYry-^;zJ-E&cW+mf1YK`|MA>f%|M1Q6t8B4c7Iuv^uutF;}fOUb#Nj80dBc z6dg>2x`Co$n>LY3g6pnE1Xt(&yGTD9d;)Z1+qNgZDNl;6#8KFzBnBvY$H1+%42QhY zAG|L1-KaSRPs0~Xw`fOCngzP$eV%EhLag~?z@%%0&fM~8JqBM7gBYg@5hm?Rp~Mj{ zCk6Y6dzymj4+biv6!PSfjaSk$D{*on)N=FQEV?R=?z7g-sfj&P<=Sy`kL|p_-F^th z9NU!=1a8P|>yW&9=F#R#eba@Sr=~;aUb!Qleaz-vL9?;C|TZMT%ott%v1to!t zUGD}&*-q^)mE93_Ka^OvTgdr9Cp*Q+9zB|Ju1m$qTd=^%A$X7r+pLRk6oWq5{R!yv zO`A>x{KYrWZY!&UpC1GTSbsSDFogdB6Xa1=)yG#K)_BN%)6Mh1OV5csTg>HCMS_`7 zf!u7!9g*nBFy(+fv28RSeXeWlseUkbYJP2dPXyIrT;oDd|#QJ8=;LrYYKswhEZ>;(}fb|exG@w z5?+rBi-TzgY9LrleC}W>LQ-g#haD|wL9*835d-_fGt~?;)3Io-ll+IG7S3rMYoxSQ zV3udJvs6z6Ro;Z-_gwNBUs+t^SH>|Pe0lbp`w1N8 z8m85MZDP?Y@7*X(%Qv@_xf;0SyLXT2UNtHYIZbpk+UD~T*>=pMowow!6J&t=-H>~G zy&?XD#gQV=@-wC5TkMQQerBTv@%-;wd1HZQcyMh&fk-rCQezYGD8)^L3NVXJwuP@q zBZ|?Jwk+K1W0U<0ZSIk|}UDp#3SL%^y;5kT)Q|7Lnr zm|oBAap7UC?g^TqFRPNHv08d@7I}i?-SthoBYJs^94Q{_4{}CRN^GUZp9)32yVgn# zVs*A!l7$+<`4B_=S66)XlTLz3YDJIB5uYp5PqiYcB+R*XR5OYZ_Sm<k&%K8%)^#BIKaBzaSvGT(Po7(i;I!spKx7Fj zA|9;;fCi3!&baqDYB?WvtI88?aB$h1ETk(is&;9t)u@h67!q3YG|CjhyH!BPu@ zBV{+8>oSHi;dALc7s~R_zLDeL5x|4t^B}3W1d!$8awOf7HRQr~FPpg!ZM_dGV#?- zq{u%sxXkp}HczxiI>#wtDfZFjBygt87rv^Onop>xvyMQ6pMJ6tJWW*+q;_sZI0igR z@Z26_=}BTZmmyAfL{7Rlt_9&ahe;Y{a&X;jb3KM;-x~6Ji3|)ue^M!+MJLyrWig7qp5Dy8H8s7?(o1F@<`b2ri zy`xOby2kuY@&2Oqk64$APM^io6z^rz0S}LMz;At9>g3uU@bLZ{jc*ZzvxGo&&9<7 zN&=l(?x*|FQZKpVY=3XUh?1kmTx)~hxhV6s^l%&z*d zs13pOSqX_IMHTc;uy;$fXFA_vs&0tMD|gCxg7-wj!j7Vr-=(UKfZ8h&x!ZRX3+g_U ik`LwU|FnFqV)tw1OpjLBgynY$3i>uAfbg#i*ZvDZy$V_Y diff --git a/src/widget/screenshots/masonry__widget__flex__tests__row_main_axis_spaceBetween.png b/src/widget/screenshots/masonry__widget__flex__tests__row_main_axis_spaceBetween.png index 90ac494571f8bd8ecd06ca94db6de51797bfb2e4..80429cceaa4d9ed53f0471a4474e39274fbc39cd 100644 GIT binary patch literal 8049 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 bmZd-%2Zgl6tbzm#{L@s^IhAqJ>ehb&NE8t- literal 3707 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 literal 3698 zcmeH~=~t6i0>(pa(UwM3W>C-wmJXeE6lx<-6B2Ae5DP?60STL;fP}CKff5q1TD7ui zkHxYjRVG_N%eQ-ZoRp^?eQkZ9N36Tm@?wu;^Zgo`(zAzL??#?|k~TitdD=dovE=pR`3|2BvFQF6;nYQr zDAkM`OCR*#>~Jy;AQ`29Jws4z8iG_ z&7{Sj?CkecXPm1!6&;szhOHSb^C6nLVKaA~FwgFC8E~~pjXPS^(q%~kLtqap5xDdN zXWJe+A21N$BI}kdN1(YcujfykJC#uLp}%HWV(3SC(c^KGKhrseTHHg$J+7&W8NZ+t zt7#*RRvJ!>1%Nj%EWaQXYJhCbj%}q)PL+Hr&{&0xattsXL(@g8-<8r>svhl(w>loa zwA?RBYaEfDc-K|KEL#5MhG_D;*}*zMJw39|9W?mhXqiaY3ERHQC;b8*n4WLso)l-o zIs5?YubFYxUh$&pZe7|?Ff%hXT4CZ`IdTM4yWJzWLy4)_)%uy1f7~AIdK#|mNN&K1 zYP4mEanef7E?8cScxxE)4~OA$mo<`#3b16_xz5RyIw5;qCf12i;;Wm1+xxCA)}%Uj zvG@LV9o(X18q@H8AJ<#~9dg*|_0uU7g3^TIK8~WrjF|r>H0e>}oq%kZAH`n&)xifN ztQTPzh;)AaVQlax-5iTHQ2g$NV{rIi>m89BC*q4&suqU>9qE))Rn)f}obv)m#?=Au zu69Jkr&Hq2V*M?{m>!65qYzkpsv@^d2XsTE7g12 z%2~%IbjgZNRoHGA)9>Rw*?mOq8aXkcOOl%$UXvU13;I$v-p<_TjPB)b_0P7#rpwzE z93v6!;JiO0WU9r(-4yC_DD8x}?ISgDot3U%oyphFM0X$x7r{46Gq~mt7HQg0 z=y)}o5rNceicBkd<@4ii#)%LGH4*UxYpFGFVYElpvscrJ`8#Tms#3d$qVou3@MK4tt-DSd!6 zP7Vn!4T@*Q^B?F3?QMH%{xc3O`~et%?_K=~=Ye1_CAk>|htD?wN~g1R23OyV7{ZH9>MUNhpgRXGz;;PT*sWPT3*Tpc4>!P4&{^hRTw!^~Ao!*6 z*tQFy2VylwoTd{uIpf`fvD`~2I?K8uixOkkM_{wxH;QVmOwrmcKbs*E^bH6uTiMFH zC%TiqFLC(MLDhiIf12{tO4$4~)3d-X2g@F}r4DW59BNySNK1JE`8;UkTI2l?Q%P$3E8ZahIK{wynr zE8FRv8DeDc!;}`ITl2~^{*5+4lp8ITOrXP^CQ|BFq^0G%yYgFNS|6kg){YTF!DZTp4I?$%b`(^AIZRB~{8{GRi51-57bs#v11EpLQY&GK zo3PcVA1bBC8#Xg{W5=Cp1unKw6-Tl952TB~bM{)AbVC*wighIgazwjMgc&L_isiEN z2RY{V@n|>>1tD&nlh&O~^&Fj47kVT!dkXV3#1{UygH$cD%%!=AcQHR%au4%Dt1*_+ z`k_PqV@!c?W{3(`&DZ4j#;QL76dGA~aQUtg=D)Dr=Z1)C@`!w}{xDS-i)k?o-(W6y zog=KX<^YeX=hQiJqKNR6^Tb)LMwTfGp*-3;2JFU35YrD0XA#-cZ9T6TS}rn}cL;0q zh&{^vnEdLv*+HY!jqU86Afd;y`3CE6jscNyb?+&*h!0nfH>^ks!q;1^gZ5wJ_?;0yl|f!ZdVXibjpNVIzaZoT%_>o)Sbb^YH~ cPm}lg^aW19dSsvNEeQ%e8WBYQJn5@{1LtJz5C8xG diff --git a/src/widget/screenshots/masonry__widget__flex__tests__row_main_axis_start.png b/src/widget/screenshots/masonry__widget__flex__tests__row_main_axis_start.png index 889abf6a8d6cd313e0e2a090a93c9bea00235282..4d76e84ce81a5104327304691a7c9e4cc5e8369d 100644 GIT binary patch literal 8007 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 z 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 F{cm$9<6Hm$ diff --git a/src/widget/screenshots/masonry__widget__label__tests__hello.png b/src/widget/screenshots/masonry__widget__label__tests__hello.png index 5d92915ef1666eefc87f035db7edd622a2ed4356..5aa1acd7442eb07b635b48b6bce90c4766a7b2fb 100644 GIT binary patch literal 5654 zcmZ`-c|4Wd8s2-i)t1y28c+45NFfcPNqv%#u~Vklr8%7Fh=k%(oo3lOx{?e{Qp%Jv zvpJp8ghQF9O0f+|88Y8z?fb|5s{~gywCftecsaCP_JUwZ7MQ);D=Iyk2Ff+tmEe?V|bqaum(5 z0#-;B3V!&d%1b`dMX~H;|B;-o{_0Kjxii)}Ldv^Jjk3l$_MIk9|#1QLec|WnH(X4)ykEbe!mTE57a$ zUpHJM!{PGy=N2Z;qbL5dQW)8rHDbH+W!|ZAr8o7@PRVIfV&nfQ3liN*gEi9{PI`1T zD>_YCk~`F{FD~*QeqCi)==aX^Z$+CsuNMy_biG)=?#AUg>mwumd=l#069mu4KsmJ} zT9ji}=u;YAcg;1YFG75NL8Q?=^N7t;1s?yD1*PYNe9ijN8WE)H-k99g8RV}e@ay|5 z{>N~R+2f*)%nlpz3J+kY*#R-*K&+6^O+iy|uk>{7-jZu*o_;kYlB}IJ-+q z{2*>vv-U_)P>K55{k_8N6tvYp%=nfsQ(B(W^LbY9>~(`t_PMXq)IIxJ3xZ4Q-w%Ed?QKsx(bFfZ zlcn;O^Top7$K!?Xy14{L%eY6SjLM(xU!UAR)Dd(K8M~M{+k3F{g_pqIV^>ea>$d*9 zQ)@=rca`#3B&w*8bhF(!cSV6E~SoFsmq;J44`=Lh-wE{-?aJwHA>-}PpB z(HsAc-$#aW>-+|;yA1meoAl)lce_=WXGs8?%so0Z@s5kHS6yGA$Jg|xm^EM1Gz2HQ zt$viBoir!%?5nFb!*2KXm`4s8X7tuYy%}-o*2(&CM$30t!!3PjcH2Hpv--g=sZAeB z#FP#SB08MO9IMbgiwau%-N>gmvtDPU+;#mxrNzCd;jX%_Pjl)cTriB(AiwOuL6`O}2 z#~g_IW+GxyNC%xsnB zPqU?&2@_gYlJZib=RfEK9lR@0`4dO4_1TYXhxfJ&Sit#aG?96mgy zdBThyrx}uvQbekHfmtWbZ&sn`j8*9uv4vYWnNJ-E_!&ah8PXHxP_-=?l7F0p5e+i$ z)wHoaO+22k z$?=#mLoa4~&Ku7Yp0h7qj{W2Ld`e1PPX_5cr%KUEu7|ve;)##$Z1%EM=_etN)u)+v zNrqebl+YylLk8#0htD%3pg$Zc&AQf_K>HcQ;IG%3dprbuif=_T8*6XmAhAL_n%TR9 z`3@xo%85<_cJlq`Cdi9p8J3er=W`XB5yfygd$;NprK&l)a{^)T^IX;?3#iONjuUP) zA>PGl^mCSzL)}lP;Vq`sA}AVphPcavr8)S15FUcfc}>8!v3SqN+hYkvdS*&)6m`xE&WHgw{HBRL`N?H z_A54|=))aV4rl(Wm@Z>19XKX9s=Q<|>2xAzV5#awCLE#?H`0uH!0%zA!yI!Z%Xi@J z0X(#^8xKLww^gU;DVb@TC2sA4TT9|fRH5?~BDk+zUx%1EkD~J*ZoVy$sxf3lT5x5? z0W0E41RQj|JC-=8#mOAA_j<+yVkdo=&7OQbplSh@i`nceCOZV2Oeu%C{LM6TdVA=8 z;K%YZs`S9r)u4M?HQ)hfen=J(^Bri0yED3nAkTzm8n4)d(pH=^PFrXuCCzg=!tKZc zs#&+@5meoRjy%H~*j>_XJ}C)C&lEnDEnaH`@17!F)dM=Z@XZG( zt@D_@R-<7aoAU@kvet2PMKFFt{b+N$R$`00bYr|4?e0dOfSil?>P@{z;?)R+={nJV z>)2PN`4vVq^V_qgU67}MfvRe=U&8XlV9{81@)p4)f{xK*F_U*JgqDVxr!|^Mn%J;R zbk~V+nldkCI;C9DO2ng);X=oj3jn;qYb^r!7zIAH)j1A02_VwMea@jccNbOttM<)F z#Bi`>-jo;t@h8^zDZ^T2|EviarHYMd#$&g;Je2TmXi#+Fl+Hd|PN6a#y$p!2+z?0* ze;B!yiIZ!H%=+|77d{rTKu;{WS0yo8yb9 z>YlHW)aylV3{Pm_DVRrK+ki6q$$3Hu!U4x#Pu&Y;0TN^yK(nV68#W*3%evFYuEpQ{1(pjxrsRp%dY;7JjvF7yEL2A3hZ{j zoud0;2JX6!yWT#k5fKkJp)r4IR*6yHqY`D2xHg9{iH6&f*9BW zW0DYxznpd!>WsneQCj7>h0!jYYG?`1mkj;3hBWi=_U9c02NkHsYK77)%Rg|{6X1Tk zw$nuX!xW^ZGS=p@1RoQD?=w?8XG8rAwD&;us%s=(+Yv8~?H%4K$hc@CuyyLM1&~w4 z=zbno-REGtyR^b~8%7~x+947q55ThjOqU_zu>nE7dGVhzA*WD@cAS93o_Vkw$t-5j z79C%1Lc)%ikI?REV1JqN?~(tQV!g(#1yvhxLy^( z^L^a%?rrl$NjQ#zG-lnbkyPm#;MROn6ue_-L!dzJ)uCFc8jKh-aUxJRoD3nSU{{{; zEJC3UoYFEys?;Zrl%_KPv?5N6hd9L`-;i2AWxk>|^^u=|&(<)9zY?9J(Ds<5k-6|D z%%EJ}d6M=#npaC=nZJ0Za3Ds0z%Z=Z%q-(CwC2W38hVLWKePbg-QpdQSQ zXE_b2i3TBW2C?|$dtZX`NASBWm*ZZTpv~soM8cc9ok$h+!S8jxV1GgaLXZG|(^)cE z=pue~g=VI>M-RkFU7F}*Cd%US?#!o;!wQ(Ci5(Z;>f;(pxPVTRw1;D`+V79C6c3Mu=gMuVagM?QbHjZN0L?UR^x8E0dwxEcGAGOyoa#5jC*7a znVR2ep!P$a$_)|PK8Hy>S@jT^;&Wh?&W#N(@?6^EoL>XJ7Cz%HFQUjy3FA08kQS1TRK3-L7denIme? zBOe=!U*T-DHo{Q7=`Cq*|B(j2Y9`aZ09l=?+>0%Y2s2Ca#b;75zj5+8D;wrnRj4a2 zw!DOj+OIf+%q;3io6F7&fkp#*s|qSgezzKl+I6TgtJac1R#X%!)_jzB( z=C>%0wzzU~<8Cak`IfH0G8ss2QzOqmz@yd_Gs~AICtRb2ndQ15I}g4khB2(lHwo?c z%q$qX6!{i+&m>?U!ZrSDEF>wW#WO-O4vgYam;5({fZd42(zs$mD7&HFcA!LqsFypq zn7$BPPQ;^hhlA!K(G%>h(srH=mrT*KR8Crx_X3fwocVqs(E;K#c%;7^csvKVe{9=~ z#@;yD((8Ya^qoA?cfxDuzPmng?M3*pdK-6~?k7DQcWN?QuM7`quJF zD2>IVcw3eO0kESfnn6tb<4-cE-~d$4-i3iWlA^c@)ZYE1i?e*&MN8Zn^+&Ce3K``= zBYiL;b4`(qq2 zi|d0d?D%cA(&48}k#q_MsH*Dp^W=U|)AZB-%!QVN7SSOrCyTmgSdS8nXa)9(QF!?c znII!!*Mgd`7g@x}aD2SY4kvXm6NnF#o&_P^%0EyES;G&&G}J>dR_5wJvP{4)6RlCH z87;WAf<{d+OvAe3bZ7uN{CkEhemw{fgATjCEFw&bR~V$#GxK3^BieAE zSM(U1JdJG3Esr6E)i`=UDdYeE literal 2237 zcmeAS@N?(olHy`uVBq!ia0y~yV4MKL9Be?5hW%z|7#KKOJY5_^D(1Ys6MJG_D&v8V zt9{HIpP6``n5?4u%&{UsE2-{{N}E8LfSYsRwyl3G3VSmb3Te&O`IwSCYeR-c&qN87%TQGkrS1tbP33+kD^6m)FMrep2yrX}sU&;_oMv?dA0MY$%*1 z`~7}4!@v5oTpSE@v>6!{ejfUAYTf>S(#c1=QXkLCUMI)SCnIrtTduscS&kGtzucU2 z^Jc4h@3VckGyUa`Pp9IrL!_JXrsDs@%t} zhS!&_iQQcnHTToK>iSv73g1k;c9W^dL?k@+>(u0hKenum-rl>^d%wMy?yp-F|Nq+i zyEDw__TxS=QMrA&b@zUs%{RZj`}^)>gHFtj0;%H>o71jF?EUpHv+NYBc#Ofi9gn;( zzd56~|4;YjiZAcq%{>;Jme#jkTqnYym*Gq(&`~jOZg0<*I=&_G-=C7{1%K8(zWnXY z%$diGe?OUQd)Z>y-pSs}KTbKVXT8tvqdmin*+C9K+n(Rpn*DvpyIt%1!{h(HEqU@s z_V1Ew@9x&icZ=UQyI1phZQ-FuN4NJnxBs)X`|}~6xnZYvJ%7sKHs8n7qVwi`bDSr$ z{eIo+9S_^``>fypIal#+=T~)k|G8(o_4DM+@7DlbdhzPxWwY~SPEWgAo%8?k)bP4w zX4!;3?{Woq*}DeyFBY~R|Mc{G-*Nf>CreUfZd=^nnEd?9v;XTeOUvHx*_>?i^~$co z?|1Db%I|DUx%GdB50c=nK|*kXJ3)d&65KVoYj6lIA!u-ScfYgN zZ-1x0sjM1{gfPnwkOvr>ezDR~Gd-PP)?Ase zFz~X`J%WVGQU~{*8Xk`l{PUH^L+v&3kfi_T5&n%2B$M6tHG~ew;5&_h1LQGIk~-xe zthEwVNo0U(*h9t#QMz><(Ta(Zn_ltcUr)~|xl2V76(KYtkoUOhKJl+puVQ?{(MBBc z;Na0wpW8lz$?xHWN0-ixK7zn>!{em;_=qX64n!hK`yfJm;E-tGUPQl!b_@O`R9X6v z01!Vw)#~9X?E_gBkC*=febX-lycutqWJ(KtlL9Z@=Mv{V8%-BS3>;dNkEjpCC~EOL z^hIgPcZkm^6WY6aK(}ZN2;q0uTWctG1d;@8tq@18pEQE>y4*hp76k)?LAVx?8 z_NEuceTI$M190zUB=b8uV7#vnod|rn#`9T_bO+DZgQmR0GA1a!b?qJ+S(T!%fOW<+$s1m?El19LqHDt%z)Qh-+< zY)uRPG0&H*KMoROoS%RT6@*9#erYgHFDDKa#4G6oYl_xI9Z>+i3j3Bxyr_6H8l z1vt?KZs{4U10ugrFZDz?zO(+TaVi-OsdJq``k#1W0xBzeUh3l=3c}|~LwIF@+^o6; zVwg%SpmK4HR!$725;QIQB{f1jCjud+7lH46#rTT`7HziAMBwdw+jN0%DpA?=`9Yve zl~0(zgi6r>(bft1CV~%hegts-r=sew+%E&5BWe#iL(?7oQXJ}4)JMQ^t@%>l{a}t1 zO=d-+31&=t4V@FdyTB%sAo5aZB>GZDpDS_vDZW5 z1)<90UsE<-y%njDi<*puhF28m8KOm34V7YN|^RPgkik2k7le7D~N6n(P#^xJW2!ys?IQ{5;iLqF@U-v zrB$wfJSYag^akcinkZV(z+|}c8Z^-18q^R{flyO29eE53HGB|iDVCu%u(|UYNM}+Z z<~2k=flXe0Xo!BH`2(HwzLeC!fC_XoJJ?jlaRG)yN)fbn23P?x}Z|ko^b|2t=km?QztGlGX>gB143Vw;~bxCNMPGPy|w@Wn>`q023?GN z5Z{7vmqB{uFVpIb7>|dBNC%D42}Zfs&=Bzg{ygG0dJi+wSEdyUf)~H4`2uDXFEDD5 zF=`z;C_b7XCf-MzHPaZNK&qk~U!skPSRfJ!}N1XA^nIPAa!Gz=d=UoX?x9iX1_1v3mDt;fEKDf{;xh>C#|mu^)9 zy{jo;A(4Z+aRT_bTtRmP59T-mUmrXi?dZI6SZDtISA#MgwT!I|tmAlL)k7RG7h^-C z5-wT>7L{xuDmAhupi>79Z7Ko|sq>Snq(97B5}`E|z110e5HstW@@?c5=_eNPQt#rW@{)8&jzF^{ocGM(Pgd34Y`|8*T z>Ih2sBrv*DKOq)E(8l=JAZQ6)*X1D7l&x|yt?1yFYWYZiVX?;zhQ8b|=eG&WgAm`v z$2g2pd6@r`2VbF;jloL*4~l&2&4f8k0hqK(^Kl&(+R!GW%D(J+m<$47P~jNj-ap*} zGjgh^-JAs$*zu+GASUT?lb)*oc&kb7vM8jjF_+zY2XTLCX%$W~o@2KnNgQ6XverjH zSF9!YJV*B1ShsH(Iws~fZR;O}{RFtUxTvp(Y8a`jC)4wREi@mybAY=G-3{a7}jBu6G!FXX`81Iz#a77h6TA>+C9%1zblbOf!#s!Hh6!Ymk?h|4O8H znf9k*G)GRZ#mjST&RICBSi6?DV`UlZ)y2m$>XmNA81IMhO8+0<%a2ms_rKrWJVcWV zx@rERBN2lj1M@}O#b!c@So@q8?iQ=^?bk?8@6Y%6XWO09`?ni*UPzy9kJE6U>x=5d zy>sJXVv;XVE2biN@paPf)9w^Q9IO7s#;De7iO1jhoVKMsZi%OBJ~jpf5yki+Ve~9` zAB@L+d#>ERr-4#HVC8F&%#MFmdd`9ovayb^=hHTa@F4Tp}4MpE3R3_bquau>_ji2~kzcaj(Y;PAsn)Fw_ zI$kp!P8Hvi=A;_ga+M!%-)2h()ZFxa zV;nM3Rv=3sn6iK7y9=E}ap|v1ysx*&f&1zA=0*IQ4cf#KcuxrOoXoSk!%1mvL(<{f z2*bBWGN_%hw!${c{gJKO1IlCQ6|KLWGmJk;`;$e$r0g{t~HqU zkZ4aI?%0r?tC*Ilt8wu2q?wQLZIwALF|U36?S^pe3+F%2c-^^0M_xG}+-JW_cI+%< z-0t0d5EVeH2{?Qj>#577+THARHzb=6p8(&W`n`?Jc{P1VhWf8P%# zqDndhVLeq|#%08(kNEbt`h!I@vwm|j;hcfY;vRj=D<7u&o8pRfrLLM zyHjX>*OR_FNZ9bg-@e9fdO?z6d%rVjz8$Hnv7Qsn%;YQhWt>`NH7&*!nDO_~shYlv zVHG+2;w^Qg09^{dbF5L<7ny^3K_@bsLIF!5!?AqB3X4DQEf($#EhbAUJ3E=aqfl7w zGrQ$>AU|@^ixfb{Bq><8dO(==gX@Scx7eg zYL{x8h1Wd0Pdv{K4(2t)Rm8=_a^55@cOjr$Ga=mh9e zQ4R^h4->FA%wwIM%;zMl=jHl7@WfC8uLl)uek7l33JjGScRQ9&v7K!G&MF8>rL=9K zEQ&ck$`TEY*e}%~vEhviBDc&4$n}wskf7B1f;35AfOZF#)P@x87BBx9J2k8qYDM|1 zH}^LbXWZ2UI)d+VLFzd9)72)IkoomxAZAPbXW}eh`?Wsajw2QP_0TXMbb`K+jwK~X z^ll4`d8f`JTJ9f5MqU>j|1hjkJ&f5@ZQ<6 z-FnBZihW#T1sb7yt1sqe!@u%S#almP5RFUN#;^8$(~gN@p_FFbMA}IyWDJh&SgLdT z`m?Rm?l|@0>@$YUwS+GO>6E*A9DIh5sDtzK)s6>w7SQPm-i7Xv>{}S$-(H<=g%Xv1 z>!|eQ>5KncO~gW@9~zC+r=u9Y%Z8^}WggP{F@TpW7*zr(>q$yRe_v&)&U&q`QBKo` zsi@R&X(VbMN326QIP#16MrR7Y`Y4}aR9nR5mtQB|m|yG*f-eKrrsoR7i(w?Or9rpT zC~xHIuutJX_;5aIFLl5ibAo~D^9ixkUa zQtsOlU1LEvfs8p07pmucZa%AnN!@!Sb&6tNMVt=qgJt=3hPkS27ABY@HsIZMD7?w2 zFBZH@6IZ=dWWPQyvFc-v$A1n&P}@0?ogiJ}mXqb~cq#|d$pe5lk>@$ti}%{TkXvD&g$2 z;N(*&1YA%>Wu>{L|Kwtut4HU}C`ui+Z6}6@r*QjmS;^F}i$;yXs=_%7?X&hGAh6bcWTNWqCWYDF3^T#C-VsjoM59erYR-WLEHs*q;u zqvgnNq1$rALLOy!c+S4<)tgI-X+qkRe5@@3yj{=X?R1E;F_$in`*S!PHz}v9EJ6no z&%8^Nf9?;b+$0w1-4&ni&1ipT)u$R3UQlmwfB9j8to9NICz!707uqiMBiD=!o_5cs zvnpIg)1{`2>B`uTov}{&lfSd{ZJS#-?3P0R{a}&`uvK#Nl`Re()knzb`XWQZLYj_R1Rqmtt<6wec#3pf|7;3g&N;qu3bNx-i%95 zc#cMczewZ85tOcJj5pzu#QXAdM1QN5)J8`Znet&EEBgfAuh9MW+W-$03&NCh2Cb{;NVybV4e=k8m3{WLAZd>K ztj`q|9DFDTU#wRO-7U9x1xv-;L3~1xAAzmr=R)uirW-BRCc@A*_x|H{;U!z3QvbV{ zl2-OB&TWC=bVbfwyQh=EnOm_=eFclK*Knu0>3cq38L+$&mP~eq3db_F@LDa|YxY)I z&yhz9y5GmlHC|}+GW`{U)PTga+?H!81$~kyaY?K7BKLf6=Aeqi8u?aD(#oo+Q~yqh zs(IM)aPirlZXVd|Y}ZB~t-QWm|JJcI($Z#kcSc~^|NWz%i=@$Kbb?V~$ACzpqtL6kzkZ4x3y$wF?+m*?&V1UWaOYUg zd~{ii>7hA=+CiAc)rS4N4VlcCL5Z@Zl{+4Xu$ z=&$VU7d?;=rF5fqs=q(#_r9!dO7prV7CqiBtX#{A6vFkG!e-qPbvew`izII{y}e|A zTlpRnP1Sqsl8wqs6T8LL7vtz`qTE=j@8NEtaI|v68>wYbIai)ovwEBKPVSSr1n$AK zSsLywx}nu>i(gu3u|~PyKoXDs+7-KkyDr}+D|*lCQ#=pF7c`yEKuR#tqId+}-??mZ zJ5z!%geJiue;3ZcuGvR zZYh#-8>UNKb`P}6arF&oKDU|^my6+r()o%47x$S>%U#1FzfqcZ^DOG888Me!1y5z~ z6iSwTpZh`lS$^y2G10#3euwJ&?*)~;4@o>WFT?{MjhgzHXE^w|qdM(rmiDS6?(&(V zOTwd#6#POt&&&!!7YYuhh;`dY;W26Rt3|>*2iXTw(;JU>1)7y8oj5oMNF-H36kaM^ z=H=HNeqjF?6;8_2PoLJg8A&cCFfwBOw@Opr4;g|#eBIiQo*85#yX3BE(|lEP&%uU> z9)2)UJhM71{P3N%S>ss`N}3q2*KM5w5+;XG$t$~M6VI^uy*j(Bvx~}k7vttd|FE;| zIi{Cp3i#Rnk!ah&mS=|@PpdaQZ}u(}43*ogAC54Bg&%H<@j`f)ujM=?H8V4{WDn+t z(Ika&j%()=>791wnObg-3l%ngOEt=5Nn)Cyf!lsF}r zmzPHf(g#hoA`f=m-Q7EBvRwxflo30A*kt!7!@_^ZPtPU`&kpR;okL!^9)qMavhAx*=?joIDQyhN{K>uG|6@M7 z>UB5Ba*KruIYQ8&QeOpIx6x%^w%gU6ztuZysqQ38BlWGOwQgr5Tm|*n{YwJTAt?lm z&EOrm5$SeX1knz5LR5z4!^SuD#kOHKpPO#>A!{`ZEVfUnn5Z#k<)k9X$Ca0keMxsV z(!6nR$%?T~HI_cK;VhOL)0;1~Z-Fg_%5Bo>FH*)8rOMCg>5raZZi++_==fjm;d!jN z45td8X>y+b^2|aQD{wt||M%(j_0Eq;ih#!~HO}*{`t@T&n{Mt8ci5^aboq}jg_Y23 z5%JQwcCOqX+lC|yd1^fvlD-b?&jfocS)6u91j7KE!%Hq~2yv#_c%kk$U&|B=e?Tr3rlrqLBCu9~j|ulzNimO*{mat}+Z%pe2H z9|McZfYayO3)L~qmBP~I%wf_(s@Gqhi}HRT+ukc}Dfu(ATXg88JGsMtq0;Q3`7|Jq z+;6tdPW-MgfbVd7`*@A9k5)yG(n{Tbbk<<(v*P-Ky`1ja3r6bhh^GXczv5$$f8w-r z+OM)Dyxibo4){?{w9d?Ljo7Og$1d&k~BpdK-mZ^WwKTtsrC#1ndw zkL#=5I*w3BTe8o`6EERRo?Y&Lg*5r+)u%Vun2+5O!KO0uUO5L_$VHn@-bJ}S=Rdm5Y^bzB<_!PdI&sZsqudOkF2RDO(#p{hFlV+eMcTkZ<-*5irf7<)IiHwQ~ z=XI0yHb>SE&2iPAzV49GPckbM`KcnNYlA4xqy{1LwR|`yOW)y=cvU2MS=8mkfT`V<)ym4ZS7gIMGYvIi&H4zAy1vivEEp;_P?`b$mqs$o(Nap z;0Ozjr3)vT;x_H$M8jsy?|O3Puk3@1QX<6GvC4nGbpLY5btYAf5&Ts{Lqp4<#rT1~)>2F=%;B{TY$9~>$W-0YHgQp8szJ|&Ufn} zLy|fIcc1SRh3{}kHz2hH5?!boAVG5698svRZyq}{4#=xX;rSk{#U_1A%IV@L9M&hpFt2GScW9YORL6MV2-MxXst%0Uo{2 z<^}|*UXfwlsc3<^!rDlNxTToz2SsvFG!{d%&ouD+OC9=%!ibam<6o1l(KY2fcLr*r z6|eS9!h?xy0^yfuL3~=x9wDEchEn)hi%ndIauM6DES*J?_H18OdDp8IC#@FO&dVvQ zdB{GM`+_g@$me-0?Gm#L=foBl=X{CylrQIe@UN>d7BsYtQ+EvF@PlEO#b{m80MB^! zcJ4yCa-%N91KmYKL{#_pqrLfs48_;}as;MRjm|A&MXs?`7Jp=0P7vHVj4@XJ1_7wX z&&la#?;$z_zZ<&zJ$Dgq_oEx73B_&2@clSbGjUKnkZ@AKFtJq0@T6^hFiAa<<48op z@szEN|8?$@PWd~9Rzq5%?+bDtVjmr1!O_X%<5jGq_gb=_to1Vjupvf`_1)!g3?e!a zOSaohhF@OC04L4`vz3ezb?3>(aFPZ3$q+mgO7t0Ef+27?XaR^u85(pTsT;sE@WAU4 z0A;ZCgd_BSP#S>CWKtdqLou2tk#&&JaSRX45IlmRs_9U?vf+gp$i6`G#{)9^=A|AL zAQj3(cmo>QF$G`3P$G9I*3)=z{tu=Lux}$0w?Y$nepnAafFEkE{DOh|l$$_>-#sBE z98h10Iwh!&9z6FU>Kq1w$$%H>e9dZLpp7#CZ5k&H*k*<+Kw~@rw~bzSy;p!DZs)Wh z&$F5PZ4WhpE!1Zy?jNQG^mkF3!1w_?V~>B#`!5m)ubfYPvyq$TfBn75r&pq5 zI9f37|F%Fy#*+-SaAZWOe(ifhgAN!SFGjq0UtJB2_=RJGcHh@N&R>vrDn)!D6)s2Z zj?6p%pCLl5rUf8fet!WrkZa3bpy&t=J5p>EIN zL_h_7{ZV8n|Ke+lf%WOnE3dw zYI*`v5Ct$O^yoXg=@%COXL^NM0J6iT7S9_jJIqO6mcpHqLdx+%_1LK?ZzMZig)QAW zy8oZBq5?yC$6vmUbl&&370w4jKU98XsuZfd_PTRQ+1^TfTo=}gCh%}YuXcZF9H-OZ zD5D?x0jJq)IBiJJZEG|K(RJ@{^-OQ2d;$j^A>oTU@}j;tR#x}(-QPz5kLut0V>V`P z6#Ei0rLG(OmV`6Ew61%{?R9s%LF)H#Q1ghPdQDX|r(U9Cm;1$j8P4?AgoBK%>|*ZhVo3$_38lYMi;ba`>j4GiEe0loRP{c4I$lWfe0c9aQup%z2sRxI-*MddvapmBvRU<$mzzJ26_%!J9 zZy+hNivNP7c2&daYRpvt^7DiAjhRH`Q%(bXy0C8ouJ(mhia&l`CX*v&*zNp1vwPa; zdBY7+kF_g87`ME?o%||ilKlsX%k%p2UOPxHFUB>a!Iz+?C%R)*_@Q34J_)OLx)ROr z*AMp#`jq8tYCYYIj8yKA6<^#n04%uULp-SOtl4JKB9eV3=eZ;VYYAd*wApDUk`+i`ummBWt%pwZuc zKJG{m6mr}0^X;>*4c!W;`~9GH(K}<)l2_WFCY-iN-ewnswWpH2@ z$uBsZWR4c3x_`K7~f4&qR_txNt+l$34cQ^$t7?YDMv<`*ZKQk81j|*6|O68vkz*Ft>vLg@8F4$56${ ziKwW^G3)KkIRD1vcPqQQY2=x}8IOumviOr5>$p9pI`Z!Uuy_A217HCL{|Nx|XdWx| z4lUAe5!I@-W>r>xx?0+D-q+8n_#J>q1r2-I?R=K(ALbfNzx)K{cxIf<)dn|Nv9TVL zR-cXJBXaMbjUKmlVM+qY(oB`&@a6KVCUZDo=i}}aZ{Ad-^S1wcv65iBUjtFN%FcMB z=7`2n+Czk8awMhn&3GK^!&?%bW^D?0?TjG3pDyfe=IcGtS%2sJWNdfcL(>x2>NNJ7 zYReOEAGEwKm+13$HV&6M{+g~N5=uVbRA$vYu9uHL%&b_6*|8|SX}PUXYs|LAYxWc{ zv7OX)md+4cLbYc(*=Q*a;LvXn$@rUNAmdwv_U=&h{DNkLYgX zAKt1WixGV8=S3dJy;KC>nJCXxve0-&4q9wRkHW{nwB>Rp>kzU92;q!v{1UBxvxnZt z&d%Dxa8QbpFV`(zAC>H_v!fnIUH)o0V)p)3+JIz065a)xj<)Ua9Vk({bsqheq9}CV z&o9xR(#Vy!XnX#L>#q94z%2vduf~w(*yyeKfwdgGm?fEq}ia=s-CjF%Lrq zi|fXtU+>=7z9WVQlm&b+l898(T&4kl4Ip}8w2#F9Tv*2i34`!)7+)0ktY&m{HI4KB ztd=xe+zRi4zf0Y`2B;zDZRh{Ai_c)*?p%_#SZQzy3@1q5YVAUFr!=RQ43l9mT@2gw ze>xCuh}AERZvA}M81XancMYydU*>iHGA=?zmS60BUtZaEaaqqwH(wgDV^x+PzSYM^ zJ#q4rXWc-nyI*qazZ=czhrqWb0|v$PW96aLa7Ele9}FUv?cPD1dV9IIqezHbU6u5~ zRZp>kgv^TA;6LoT&*;@f-DYFE#mx_q8pbPiqf)&n_~vmkSnC&JxuT<`tw_3LBX#>f zBX#!Ex5XQ_lvFqbVMbADJIk7iEGIK1zei_ztfYq}Y5bx|-S%DJ;2dz>$7hM!UpDA8 zCku@F%k`d-2uLrwg?Y{zPmy3;8c?_zCrvDC60S@=XPmWO@VaRtapjU_Bu;(l3nvBW zfWuo%M~^W{;7^->zdO~Td^~R@hRw^#sj@v$ydvYMUf%H8H*^2Z|s4T z`==Zj*9>-X|3p0jP7#-E;sd{d)Vm6>>wae`)9`sxUC4FP=eln#;MT}^MaO^c{OBvr za;wvZ8>G7oK~d$|ZIQj^$A#v1i+%uKE+8*YZ|ls@dmZ}zZTYg3rO+ae#Mzbo;4frr z3-`al(K8?;`db|m(E+ld;tkVT7TFCr(*U_D%khGtcz_R@enP%9Kyg}0d=$~f56CcP zY?AGaYDJFZ4&DFaWVL9OoA#@%8SBx{H8?59CS(6_^%3hEkC8jf<)LGH*YD90xKRC} zNGg(k@%wK@#Me^TQ9oTz>U1F&GQo+LyYqLr-#*nDlw^3`)L7dIU>|mlcUu~r-rpRk z#?D5*@OHH`eP`X4EK+XtdM+~yH%Y*?z`)vUec*>*uURds9u`jChsmICp(W{6R#)kq zA0{N~MZWLk_575W6n)~`+37(Cc5IP}DmJD4qZ#7bce%pr`gnLlTP_-H;h$OI431}A zk_pHXxjjW1zX;5E)%_ys=OQKL|A_cuD#ps#kDO~cBV?}e;VaL)i`?+A0TsDoU=Gi+ zL-o<=)}QMi9Be+6qOYzmycNPFW2GWX>?$ku0eIoK_xJVTA^dE?U=ok2Q?*#5AvG2H zP9DZH9ju_6=jxZkj$ps?r;yU@(GxDq)0*wyS%%Vs5YAcgz_1ZT zhrvXyH%3N6ql%}1x$&uyMo36c=yH+Tb+_EQ!l>(Qn{jdJPmW3Eh*|`J(R!C7JkPo1 zE(%7X@i-2TO9NV(eaPnzzdO=|JZrp2P!uoHyTcF12>%;ecxT;Kr1=o1=x5@{@B7FE>~(AR2W0~Ydw#k;>H=8PJs{kRiLA?nI3WpMNW@(<82a%33%Ufi0i}?U+_(nDqJDng+ z3AUD&%QeZCi!q2N7`D?Uon%n7anTb_VDezE3Hy}te}fvAFgL+wbDRDX&VFc)ym|Pw|EqP(%q*`ZdC@4Dzs8;&MRZ?z*)iJS~gvC$16F!H?tbAM_ zSjCO=9nMYW#b?#vh-Fz8>#Q)sFL`6*OPNE|J>$x0;*!=r!&?||HTo+!7UVV&0xoBRpC;Li9{`ojM`}wqF69Kcwy`*ZLO5eKEM!{d z%VZ*yDv0Ou9>(STL@z@0{lDd-98{Ea3BRnM`L7RRkvw>F?Qh0MSoUZLLKj0F>kT#h zGYDQ88x-4Q49bP^&A)*hw@8P-DjfPNCV9$Mq|WwL3leCa`5(yLsJ0L$y+x2jBYHip z41mgCgwoPm3`{ej4>*?~Ggd1${tF{F5(3_CxeL;70ceU__5x^D{Sf#GXa*$9tM^fW z=josR1g2ZMH3bf-GX*6Qnuq%!asbL{jHpuBcRNU!43J6&q_!y!Gr=<8ODOGpLpp&H z+D$;qHap4jS!J?WmxN~A@PKWI$EMor2igFO7D}~bvPs)e%aJv8UG%;2NG%b@vjV__ zZxivGM#=E)QGox1NlqTwuc61P6_bAj1<36c`4T2#L9pao*XNY5s7pu$ELb7FEW^OS zIMF7TpW^ogRYWPk=-a+C;T8{f>+<|MnEh5~h@Tb-?*sw;@pDQ*QIwyI67sz6{aDKt zRr681zwcY&Xt>R%0JF3`W(*>)7mdyj3D4e9k^>x}u}JeoH*lHyZK{B)$>xYTF`Gd! z8K2`5(Hgyymgbm&6n<@m0;W&BX4cpmPiTW?>T%E`eL1Ma=q zs~}Kg)Zwx98fKDyS+|k;%l>?K`Z2^volJ-Tr%|jdac=X@^I{HLq4I@#v*>}%LbJF| z$G>A~5|xAiPfCAAUvo-+%Kxcvtv~LpzDf-j_j8Uy3LhSYw`9%78J4A`&)EiTkmHL5 z_cK!fz}xaq_*x=qQ$8^pN>-Ml0=u$UP-bsBXlPgp+(9yxs5f-hqDBcDGI&_(kXpSw zS}Ezxo{9_(j_T>rDwuTA5#_M)qh2l%iPOFZN?)zrA>IAxdy{HtAH5=lzy# z42Ayib|Xz=j`64CR!lSDB&7!cgi@ML0s8^%7(nv1v1SPzrZh}UDz<_e-&pnafCsWx zUQ14V|C2YI|GSgUjD*iFlHiidTuI+9a`Nm;#OF2vW>UFtFKAzXkuYy8)u~^WCs^x* z?+Yv5i23^U`J$zc@l=!h1vz_PLtsz0r@KkUyQjJG%EtErVf)> zsHqm~KJ97Y5fRbzf4cRhYzhbnKz-Hy>(>i4!-5ja{;QJ>(?7Y))=r;$>YP7}H^}sT zXJ!Q8PAs!_jcZdJD5xK=_0#jrspx(oWPXvKk`9^ zpXRH9+$2|riaLcQf9p@4Inf0F!Ozm6FW1xzRMb*fu@AQ!YHQYf*>3Ou4=V)bj!N(U z9cgtla0vj~+mZZgbP8mQ=7&b#psBV(=z5u9mg7ny2pZRuLG`uz4dlKCryZwtYRN~+ z4v)`PL+IVMg(VQF{$qJy9Orv9SPf)K^@gb$CQS$8aU0kJdyFZ@83tQ$iq^nehM+RWm8@8Rc;*!`5R>fObXT~|&~x-tcuL0JjDgw@z43o(~vd<~lQ zPf%0;Ao}E$Eh->LP^oqs0@lSgIb*>N<|LH$mB6`0J9oL_wKsjza=hsO5i!%0W;FBl zOV!%p9&zmIanbw-KyPP+FD*Fel`W`*XK$C@E8Fg*#OsS>-Vf(^BAy=)qJ|3OCGW!MTtBhw__#OyRo9zBOB) z^q5gi-tA)l$BK*gn(_(SWyf5VMP-%ELs`{_Nlhao!b0JO_4!OQJ}Z#xpY<4zq-Siu z-(xB()NKq>MR4bQt))8NV=@1ew}G94(>&N({;h;PTJRUkA6H!KZ?QZ|*|-WR_} zGD-08UVQxP7^9HVfKK9Ahu(&d=^lion{75M)PPI!sw_?6ZmN8x;n@%UmQ*2R>R?Ps zEliTx%#QXBi~{7m#Q!VCuS;!t{uA!|v&jWn)c2@-1fU+Ik`+zG@qR#Bv%xXJ<7|9V zx_v|L?z%Sr*g6V)YUET@P_A}Ln~snBV{-sislb~5M_Gi{04RqfP#ti8)WSgIt1n57 z!QtW{W?SSn``Jx#zyjqM7Hd_%J39)SZ$2IEA390p&yTe$sI2n#E-F!=y~hBxpMi-W@~b zIwiS3U)lKeQk0^wZrGoKrdCVuwkcg_CTeuiygF~{8kX0Hroy#9 zXbM+7*!gg^6qM#z`e>3u$V21d$Y?=>O-wY>tv6=av^{`G75g~G?#1{XYfI5M3xkA@ z4TX2U^PE%A;}?%3C^tB~?`LE+Vv!ha=70L}28|a^nzM`2gi)y#YcXSz&NBdNmsk{u zt5wvsIufFH-Jyl|f2-oeA-iQ<`xO?x4ki4s|0=+9(dA~Zc8RS+PH64>(R*q-Q(YJn z`pcdrR~)zO8Ix2&>I%bn`tX3QP(nB=5A8nwY1mTg&DDlJB6UQh(6z>#gOt-Vx_XjJcg>O5QGLNsBBg#I`Rx|Y{4;|ZeiEsY{GRy=EQB|qQ%UDoLQ6p@66p9`-o$2Az|}^l0v9q z?@l7>u?Oza7+6doLCqC`&F-Bq^SJ{?+M` zE3xPI{)-!O=r3}yc(vxT@%W-3xf-i!jxSw`4O#Hc$s5(LfMyBJa-*Eopsp*hkm}Vx zSCo5#RX3Fc=g}T$Lq^N%cACGPL5~`^u&HW16;8^>*C4FGPsAyC=&%xr@2xb1ukLK? znVC4U0KOdKQLBU3XQWkyR9DYG?0g|$+{S2mxR+{r^YL?%bKh5)<9T-qkj%ko->*Cl zOMIVT3LJH2^s>WzS}~mE>Oxy-Ztg^3J%puP2NKbPvK+@sOx&55?12^X>P1Y!k7bGi*rNkx)sGnHGGAZQOD zr9bNwB0TJv(6GH-jg4gBUQ^Ljuu#`&@ft>VTY>VcJkF=zYBqjqT1@3Gv75_G9YK9K zpE)RLYtRE3R&0r}PH4o$!~KPy*XqqkMu%H~y+(abD<0AE0rHGls_Wm6*%7!{od{X? z8f)tkWMQMax`wFzyMFeKdI(42nru}5sO_m#ec`9`?kBogTME&&feXwr{k|PbQQhP_ zxvv}C&I%ICm7O=)_ElM|soh*$>PQBg^K}B&XS9xBpW#16UB61d^akr<1P0POqug43}2oO(5phbg%@Qz4!)PIKw)X z4k>c7qD{RAuWNP?@&Ff$TX9MERJUMYak&rnc{ERr1#_w?dqjAJSI(^U=Fz-^BDF=4 z-&5$qHOyJk*1uHG)W2#uc(=8M;B*IiR(*)0`u+i2me z8=w>oKxfY2=Q0~kC6K>wx!F(B(h1M6xBm=|Gm`Wg<4jNep zmVokS+uJs18Lx5i@OZMpskg~6%}%_tA3%N7iObWDej= zC9+fjpWjRc$l>5e@F??duzQ2tz4-BT-wrE_zD{Xmv*~hK?(g`MlJ!K}A%|%I>szB9 z!3FQ|vT;aCqITcG*;$sXOGeSJH?zHH<7K*RY^#Y$eC2%S&VFu)KVeP`DG7U`Pu$*#)!E{f!s@NLO==ve`F-vq7SJXV*wicc;!j{?pQvW|iy$SGY< z*6kWiQtZ)A<^jJZQ^{pWy>e=uY-U9has!Q zU*fN3A6<&KquKf-Az_B*&0ueMLXSk0CsHcZ;1(ImRfMBmM{5XhmTSM+ZfA|WB9`x5 z=`A~z^eEv@1+=|kQXhCkwD#XE4-S@`iK`^cGdE7#60(yex`=*!!R2DPgZ$!zq3xsL|M3e^{ThS{n#cQIT|8wkR!L|?d1g9JfdoU z>sVReKBa{$Be@j3~vcYj^p z;l7&DvMU#gss?MSLvS*JT@GRE4LIw7e~Y^$lOpPWT}a9kg=?NQ_m$;{%O5LB0^q=EMz0m?hgkJ zhxqH(BC$jRs2L=kA(k926<$l2UbeN;EGW{X-m5MFV@tN1-S|hRU*sN_HacuH=OS{H zzW*$V6n$6*N|_F2J31pc>Avj~sGUOh`8*&0W|B;sILF%!#m$UaB@6OTOA2TPA-A|+ zJZ$rc&*RfKKeuT*Yp~aT^mR-}7@#c%5ZBX9+~Zz)jML3WCrajhXK^@P)nK&m;nu4oWhv2J}G!V~Dn%Bfqmj{*>1{Xiu(d;9)3SI^V z8R3a$%W)p-NfGlyJp`RsE}fHm*?e%ddQEP94#Q`-!FlL!oswua2MmNOG030%P|gZ0 z2!gka$orY99;_U@Oe}*!y=a#9l+qvh?45Tc>&~@LC^0qHR6;Z-4vKdNj^qII`djM) zKutsqFao<(TP@bJaa5r=Jb>5dZ5kVYzEA^)21$aJl|I)m3oI+N;4biw2HS~h- zxD0ztf{7Pc?n05SUYdtE{M)(dnmpJ}kc3d6KZ5kBcc-L_oAxbkD^j4M0GWV`(nDLG z^Bc)w@DDg>vjT^V~Kiz?C3` zPd+X+AE`cLSFEvLe9w47E5jRax94VDRi)zja5qT$KA1$wpPyKQAbY^|WGP6mCaHSi9 zi^!ijoG<K1#I)6QA`mIuS2VSn5K(K48dH0C+CCDs*pPnQh)&+##7Xo@x5MK#{tx?75$OpiALw;MXK`4yd>dv>|aYC!B z;k8UU(i<2QgfUC+vOtrLK_c;)@hy$m&-#elkXAq$oK@@ohE1Nu;Jv<9TIJ8BdwXX* z*2f!V(1f624J~^1(D_DL=?(Y)Q- z?tkEdkolT~la^9JFDgid)VbLjb@cl!);s8$^DA05I&@!zIDAURqgaNJ-xTt0Q z0~e?S7mlOu!7e69g5GG5ooP-7{h>xU&}YfDEbJc70e!v%p6JYbmGA`mfQSu*9*%Lz z$wKA$!VShj@X`tTjbJ6}7Eq$TeG|V0QvugVG}kCE^7P7C{>+qkvGz z4{l9Ds2tE_4T!`K+O8fv%(%yAdWsEvf)FU&IJ{{Y->D_d|HqP4@DXb6hW}L zPmmVF1pWd3lrM#lKpQ|LCJ6!|yGJYIFifHf7%QrM#`Fs62NUQ>xZnESSbhfsMVSwN z=+|(q37dmGd|(78rjKO*Z3P{S-u)#8U%d{`~iW=$lU63PB+OR-}(V@Bin1AAlOgh^HrjJA%MW15Lr6 zmS4Zau7Jq_zK%d{^8Z_$xgMJzrQbKJJK8zxMBJM`Xmjf&Jqg4 zYQQBP@JIBzxgWhDOz=QX0r=&Q%q29K65lG&yV1-J2dGdGj(CTaKG}(^ivQ0*#^Riv z`e4kc=FjvGSgw9FPh18**@_XE@li{YAmuX!5Gzc8e!O(#@MNeJ!1FeixV1e5@<0J# z20AUp)AgbcNbLqtz+KI1`3CltFVJZ@L4h+3CxZ^i@la3)@{5{`zz69xGJuYUIpCE# z5tw4nC<(*>&(1+9Ogqj87%76x(JaBO=4!y;@I zFL19Q*f}Sh_5qJiad@l>ajKGtz&%z7GZIu-2${vXFwJAB@L@U#%rHVVrRRje>r^2d z>?d}DTdTR))6O%asQ2QRKo0G(#^&AQ0!{JF@&=|Uz4~Y1wXoYjYhiP*UId4| z!E~T!WBxsRcJ2;11f_xAz1eWw8_byjG^J_hx5zSJC~f9oaRGY0VTGF*@GK|bF;DY= z+4uQOV|Q=}asWfHVa2fr+AQ9{BVQ7LM`CsSEOp=ps`EH74QS-HHD*%2kPzH4O`r9N z6!$wwb&%2oG)8!X#8i-(9uI)Ad%{%gj&kE1g#$Jo3JJjYWLl;bDFCwM1ZbV^oTq2+ rfK&pdZumJcwb^ikBgRbq!+-wVH;>fcDux0Ngk$h@^>bP0l+XkK72SN! literal 12902 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 D?5?)B diff --git a/src/widget/screenshots/masonry__widget__portal__tests__button_list_no_scroll.png b/src/widget/screenshots/masonry__widget__portal__tests__button_list_no_scroll.png index c2fab6df481b7a10652749730a3a052b5902d9fd..084c33d3c0cd6029fd459a8dcfb7d52b3b95a3d3 100644 GIT binary patch literal 16401 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%0Dxb!-y-Mx)ct_khpSQaX(E!zMay-*3ubL? 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 Nu&e5d`B!c~_&?4~&6@xK diff --git a/src/widget/screenshots/masonry__widget__portal__tests__button_list_scroll_to_item_13.png b/src/widget/screenshots/masonry__widget__portal__tests__button_list_scroll_to_item_13.png index 9e7a4cd9cc470ddaa74c1ee6f92490bcf26a96ee..e82bfa2daae1d3e6f8462c077008aa4fceac14bc 100644 GIT binary patch literal 17025 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 literal 12420 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 Y69{FpQhnHB4}o9uGAhz}w;w(GFD2o@bpQYW diff --git a/src/widget/screenshots/masonry__widget__portal__tests__button_list_scroll_to_item_3.png b/src/widget/screenshots/masonry__widget__portal__tests__button_list_scroll_to_item_3.png index 9249125b51fcf20d872a30438d2c9cbccdf9231d..55b4da3c24dd686d292b5451072d196c65f5e7e6 100644 GIT binary patch literal 16778 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 literal 12242 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 diff --git a/src/widget/screenshots/masonry__widget__scroll_bar__tests__scrollbar_bottom.png b/src/widget/screenshots/masonry__widget__scroll_bar__tests__scrollbar_bottom.png index 1b6c2c4ae7b98bb58d311fb7a1b74378bed0b7e7..1f148bd3a09c46265ecc9d31218876b131ea7a22 100644 GIT binary patch literal 913 zcmeAS@N?(olHy`uVBq!ia0vp^MnHUmgAGWoGTU^Hfq^-~)5S5Qg7NKa+pa7}f!5!B zY;8>)9i17AW;S-NE@WMI;>6XA7hEm^^#@{DCVpShG|@aj_sim0mzC2G9J9Q;ebwvV z2i}A|{`kZHN5lU0{4*TgA1HJ!T+r&qHECh^LcyZ}7o3z?PhMDkp(9BnW8uW6loz2H zE`}moE_gT^ebF*mB*7JB)9Y~jkwU;9w_+*71rEwmjgQP{UG89HmAc3wvj5^7Hy(`( z9c~ML^gc65a%gljVLF;`vRsh4D}72#x7(zNsdWu*M$CSC{>mp$7}+~0&tz1ezI6qe5mTVq z`{2gyxtT|vHF;;U9KZL@N7+m~#!K1aTUol)#+?s>qz-P}ZvB70;BGOKr`Q6icH6|N zy>d^OUFY1`^Y8u7yzSCzlRYy`q@?b@|GwdF-r=7$*ZzCQ#WjDa+G{ZT?4cSv{=aqc z@Auq)e>iI^*XyrVGX3sny<$ryM6DHDb~!UbM{MEUy#4R2WcW<0ZR8#n?QD7e`R6U| zx2LDathk!h>bLxJGRMiM%FQR|&6)V$`|k^dvuVaXZi`>Yruv_A;TPGkusJ03>$h;P zx`V4$X+7BWQTv6$$G7)4A9nOAZZ&`8($Z|vSfcH$oTo9D>tctn$95x=M{So@3iJ{b zUMaXd>VlCBG!{fMT$G7RF&83pNWui z^Qo&R-j;EFZ=56hMDaMk<-rkp z)9u?PDymGjwG>_(binQJZ@$@Q-S(g2)^9%Ou)mvA@=>+_VW;W)1A=fLV>f M)78&qol`;+062x8rT_o{ literal 578 zcmeAS@N?(olHy`uVBq!ia0vp^MnHUmgAGWoGTU^Hfq{wB)5S5QV$R#!)~l2pB^(~! zPu$UeBtV4OS(JrY{0ZBgDI0GWFfUrv#@589mGmNemDIWdM>aL)g#6ChtZ0VQA&)Tv7S)DU@78& z#~(XRKNXsMQsvs~QmfSJwk@~czW7>o@%{J3aqE|R9!cBW`LH0uX71CXnQAdd<6l31 ztQ@sAjEAi`-DTSK%4y2QJduJyYr_`b%yHWpwzgzduY0Oi!pQ~unc0s}^nWL91hOc1J?z@j_?3Q26UVd3~-SzCK zLQ%!vf9;lC&b;&f`n+a diff --git a/src/widget/screenshots/masonry__widget__scroll_bar__tests__scrollbar_default.png b/src/widget/screenshots/masonry__widget__scroll_bar__tests__scrollbar_default.png index 9ad2277ac075532283ec52925ebf221b2fcdf4cb..b9234e42ce649fd2cba6f80cc6664d90e274988e 100644 GIT binary patch literal 962 zcmeAS@N?(olHy`uVBq!ia0vp^MnHUmgAGWoGTU^Hfq}Wx)5S5Qg7NKa`z|di_IblNvX^wN=h0U5*qv7#ywMv+Us*Z#Q*D|{KV4jyLSDn znco)t@@tjr+FfJJ;`R^&0*9GYMa-?#`-+J#^%(lUkb2Oc~+suh;b^sdWCe zn0fF%yQ$&lKx51I>4tyv#WPK$uHTRhWv@?)Ql2M6?o4$8E;A5dx)iCdR_jE&t{Q3_!4TR=xjAxhl z_*m3V+U=0>x7Q5Hb$bq_ANHs?RwtWqq(A&ejs)lV8|#^SethJb&#T-hSv|d7Fh8YH z|A0rrfqPFAk4Q&8;5HDF*ic?6@zG7}2U8CV+nZQ9w>=YC_c16pGNLN4H+U55{k19f zh)rj~{`+&AXTZErWHmQqXN=Wx!*sRdGX)Md#y+XAxm34*`Qe8j3@3F0efqgjB5=Vh zm6P$GH|~tl`?hep-*V@(X_xJOY>HbC43LX8cFRBil(~3g{^Bc_E~IT-d1m0$DIChGjpy#Lxfw0i(iC*_VmiC!p|ioE;)~sf zI^?SN8TWjM`Lf7h(eZijd6aF$_iFUK*!bM~FvodUeJo5nit0{{zROv>=wc-*NmEOPNR@O6$DkQ}GSidTwSm7Y+ SnfbuH$>8bg=d#Wzp$Py=eX0Kd literal 594 zcmeAS@N?(olHy`uVBq!ia0vp^MnHUmgAGWoGTU^Hfq_ZV)5S5QV$R#!wpoiDWg0&I zcjH{*p}@(QZOxsZ@Q^p>i(NI}`Uk2ydm3(KXlm3=F{@M9Va%-kPAS@6dY(MXGv%Yd z4g4(arFxHnwE4mRKJ0(G zbCQnqgTJ5KAaf692cu>Nh} zlnIw#ioE`6)hl(|fU?~j>w zI`zuyuNBqR-kUqFW{Li-vsat!St;OLR^4PU`|P6viz&htb#;E)g3mu&9(!DeFj1D(^f|cnSmg2oC z%EtQ~l#ew`zI@rk$mlV*NfM8Rr7dCM`eYSL@h?p5jgP{+E_X1oN-Yx9s9S2$s}Zn3 zQ3{{n)7caLiuK+w_FL_soVn+X|K$$b$6L5eCLKHd&xDZhy~?QbuF6*8F;m8GDQN?vL=ues-V@=U+wMpC`=_J)P3?v3+*_kH)7w9V;z zj@19@-+ML7bN5}owhEKiY{k{@&M1dHS}woj^2?6J^4S;O?lj)`SLjjQg!AY9GtFjS zth+PMTG%$=fSc~>b|(G8373{!;OLbQd=P$`Bd07%>ZDtG$warF18K{bPRuEB6VE(? zCVW)-WS;Gw6OK-DKSX;U$hOE{@HoM|f05vx<_*kJoRts4O`6ID${dsx`Tumeec(I9 zm!a~cG5#XQJ;xi3=0a`%&Wo~Zo|W#s&>_fJw-t{)U)}Py&z^Jsd4|yT=jUAbMK(NS zx0K=AbTens+a0#$YE=swceT{Ua;dXJn~@W`Y|Nq+Tj@zv%@cjeL(<^!`CgQu&X%Q~loCIHZX BsE+^u literal 620 zcmeAS@N?(olHy`uVBq!ia0vp^MnHUmgAGWoGTU^Hfq}``)5S5QV$R#!d$Y70WgI^K zpC#?#G0TK=iRaWKxo<>2hSqq?JFsMH+sipzJmwZCaCYuo?ylRO_L$gM*WGvf z^0v>Oe`5Lc>C-D}YkM!h6xkc6-*-HD*QqJ@CoW&U{7?BW`$xf%(<eX9+|JF(sKAjM?R_yxq>zO5yTf^=;ANyBopTNPmYYie3d z<$sT@`Y8qyPxyb%KAU!rBUt2UrLqsmNnuk`e@;Ai^X=Q*J^S}R|Eo0hXwt;_C+hb5 uZ?3LG1hh!M_m%zsS2x~TdsB4h^ZAs` zW+UhGSyro+91aIX(GzM>1cLE+91R8onM@{9uh)wjw=&~gE*F_jr?OZq&c9F0bDzuytW0O9u+ftq=&vh&UHYn)0qy4|jrHCPzFmt>WWm*9#c zP%CaIMuLDo0)MsbcI*8v&ThAp$KxSp;jXWQL~N5l?RY%OY&P>&60=C3&*!pUuWfRs zZ>0pn<#PEQy4mJ5>k(hKdD+4Go(B9$5O}{yH;YuWqod+QVIqkvO;R0E$G#KxjfBP5?pTH0&PJyFvm8qOfR$TpR%eDULNGDI|a(3X4X_ z#SuV|;#f11LIMb)uxOtlbH)|{1hGYyew`qIAWoE#By15t5L;yF*9ig$;zSuq!WIDp zu|?LEet$jB13^5W0HmKz0726EaMg1H2;%t!ApLX#2$If+tDX};5YHz-ndxg78$mQw zi5N>GfFPxzXJ8Ek5JW?jh_N&R2vQn)2G&3TK{Ql}82?Kkx6dO;ZYb%t<807*qoM6N<$f*H*u6#xJL literal 477 zcmeAS@N?(olHy`uVBq!ia0vp^CxF<9gAGVZ22Od%z`(e~)5S5QV$R!}w(A%JCE7oJ z_iMZ0alvDa!y!Hqu|&piDa=*3H!ub+m@?sq21{#G!F|il*Y_s;e>?a2bf06@R!1ir z7e8BlG2;&Jf#{X-jyq$vc`Z%yob*Ga{q)nM*=LWPd%oHK!0IcJyYFs`TAQ{u>@-(v zlm79mxD!r(wmK1*DT~-ecko6$WmLZ+m6w{a6023<(WQeWxMbGN#7H; zI@IFgse8^1_a}X=%02wh;FbqpdowQ^vvmJ)JI4B@i!YwY7wfa0eRf&s>d^Ui_rF$c zeOe^>ue|KYX>O}~KYvd8_ak7&`RBF2YQF!rwF%1Ie!GDEp66e#Z@+7IFxV7!v2w65 c(G}gdev}`(%YOe(V6-uKy85}Sb4q9e00--}A^-pY diff --git a/src/widget/screenshots/masonry__widget__scroll_bar__tests__scrollbar_horizontal_middle.png b/src/widget/screenshots/masonry__widget__scroll_bar__tests__scrollbar_horizontal_middle.png index 0025570417585f29f3a96481c413c270cf8a52c9..2ffb18daae80aa62850b8d268498e3641d63d3b6 100644 GIT binary patch delta 674 zcmeBT-pM*axt^)P)5S5Qg7NK4!~8=A0&eS9aBO4{(q`7?W)?Pn#Q&jOa>h)FhzQAu zi4ClZZQI-=?@US>FiB4K5CQoAM!H^oKX2N^JdnbjrZT5F0hzV zwmY}!$mgF^KL6CY{`#uRJtalKBa5%TElb@PaU#KB!hHX*mtU*utZ4uJ$Gp)7H`5P(yvX;y#A;KFUh3AUlQnkzX6bPo-j->v4fDSCdaI3G|DJ_u zzoOD6{Sz)Rkvf@UW~|+Q`0+gn8Rp}M=6)97)acOL^Y~-Lvdb&i`Lf?woBSYxWk%G~ zDIAM7<>c(rW8#=J!A`D!)BXDQlZ|)#_cbObPCxMe3CE-l7IXbJ-F|zdHqdw08QYz2 zKr(uN+vD^}?E$ldVcCyRi}eEz-1IKkX{RQ`gKKcud? z3Gjv{_4fkJId)<51~w*+MGL*&Yy|q`l0=o*H3tSqlaNkZG1Y*Z6)Y=xRE3XvFgPZy z(VD3RblKE}DT^dH6+C)ERfAJm1eO?0@exsOEO$)u@l@lO0`!9F!H-7LECNT|=6Xg> jVrZHo&2s#7j=&GL7rIG>{@Tqv3_#%N>gTe~DWM4f23r}I delta 368 zcmdnV+QmFUxt=l5)5S5QV$R!}8@rSo1sE<^?R9Wu7IyS?H8B!9693Vj*VVu*=wO5+ zvm=Z0-q&TZc{ii`y36l1H@=#c!L_P=-9JMKo;ubKOXt6Q*j%(z=4_gA*4C&f(c@pM zdLMt3`2O2=ZN+j&y9^U4L%IINck|r0-|h`sIc3xR`;R|%+|8>O|NYlatlM?Y`R7wq zFDvLz^-@)v?CG=o@{8}kHG^$lfBm&n^Gw?29e49Ioej60_&?!XlA%;D*KL`ZQh$7# z_iTw;E5X;UskJSpIfnaQhQJSY-cOVGSFFCO<$82lc7cUVkjpa1xNWy{b*7)bkzhp6#+!v{uw63p{mYaS4`6tuz)0+~ji?6>fidwtO{C@nuZ+je{?9Y(<{LD1}&XW31 zb%7D8C==FTa%h+|I_xfDin*l+O^K_R3Yb<^o8Wr>mdKI;Vst0Mo^% ADgXcg diff --git a/src/widget/screenshots/masonry__widget__scroll_bar__tests__scrollbar_middle.png b/src/widget/screenshots/masonry__widget__scroll_bar__tests__scrollbar_middle.png index aa8bfb2e06085a0904c740c0ab6fecf4cac87570..0d1b7a55e0d322ffdb1d9081ffd7740e9aecb142 100644 GIT binary patch literal 913 zcmeAS@N?(olHy`uVBq!ia0vp^MnHUmgAGWoGTU^Hfq^-~)5S5Qg7NL#ynEyZm54|M@<_^>Oq$3e+v+Cb?8e@kqT=knQ1Ix4 zi;l{YCocqMfRt89HLg4Ay5L9eGm|8T#GPV(1@+ z-VmN0C6!W|y=xw^XDmrNu=Mn0kIWQNdk1AvX1&;XZeGf(e=tg|lqh)l$s|ZB@+kiW zkE0FV)BPnhW4V7Zh&MhmpLMx|kyYx~&+_k8d-d+-h5!1yuWkG7wQs&x?~Ggj%kKH( zjUJ0HPB@vObogNaTXW;NJ#p((w?>_;v73JS>7tD>{l}Fae~egmd1a5=;^S*v13lJX zpZxo;-sYQc1kZnz|GQy(ly2ts+y34)ywYOaI}4s`PkX#t@6yW>l?(m65=9UFbmlw9 zi2wZYV?x?y$+_xJ4$Xbh$|JOuC#^uTv3o~CiH?(UpFynG#SU(_<4PuvI4&=}Qg8Ig zD0>r!xaT8Al}r`}+nbZzCRH$aN-;Y4Z(A}^Mb2T88^eXkx|u4S>=Tv+k)$)h$PFheq#%8@K0X9(mT(eTk!Q@7`)$+{xq-%cZqEy*n0`Xt^j86wW%bQfvzkBGwlPYSb;Z z?3D;upeO}T3RnbPomVuw1w2Wv%~Ww?6J0JS@-re{s&k^_(M%RsyKB?kl2QT+r5q>r he_c9JLNer!d7@O(-SBJMmjSaHgQu&X%Q~loCIH$GlBoay literal 617 zcmeAS@N?(olHy`uVBq!ia0vp^MnHUmgAGWoGTU^Hfq}`u)5S5QV$R#Ud$W`RWgI^4 zPh;lvoUGPp5>{vWt?P%@zNP#MOOt$<28Tv^5x4jOr$>k{5dmC@bpuo zXP+x&_}Wd9cem}?yVrI7^=`lA!fV5{Wjkm1s2R%jCtJuIE8FeszN6^G;ls`)yYIgE z{`+TF&B_q1z_nqIi*_DKFzERFb55Vp)9NRWA1nW#`>*%Mr5v-*w|@Vwo>lmC!u09W zS6t1?EQ#Ov?bokaZZVciV)Twbew-|IH++rg^9dX4@0wHSrzaC0DgL|sa*Eq`(d?s^ zDV8bw?;lUv=&|^B*Vemv(}6ao?2UWwtH1fC&e=TQ<(KztyP0#TNBh0J=C{@!x5a-H z>UZBgC!OfE^irv^&&IGh&SjrBEqwm``HJhWEBAXOZjE}XU1TG7`OSJ0_kB4p)SlD_ lIDfMJBut^B;oAQ&3QQ{u{xva40+@stJYD@<);T3K0RV9O5_JFo diff --git a/src/widget/screenshots/masonry__widget__sized_box__tests__empty_box.png b/src/widget/screenshots/masonry__widget__sized_box__tests__empty_box.png index babc2f78e8c90b3a72377f7bcedc550edb71005d..25892e754d07c49b99a50bf5fb95b96cc773087e 100644 GIT binary patch literal 5247 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 literal 5301 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 bk%`&yI`J)uKdeJ(_-C-eWPQq7+f)AoC_G2y literal 6113 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 F_8%5I3sL|8 diff --git a/src/widget/screenshots/masonry__widget__spinner__tests__spinner_init.png b/src/widget/screenshots/masonry__widget__spinner__tests__spinner_init.png index 9b18214b6a9e6bf72b9afef788bf5d64d42fb0c4..5aa4ae26d8ff03fe6a56122a6dbc74e293a97b5e 100644 GIT binary patch literal 25071 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�-xRVaBt(N3O6&0c8>QJ- zXN!zQo*NN?I&q5_2UAo&x7bLCi#wIY$q5c-=k>N3Uibzg5^#fbU#`U$XRNKXdCptX zG-1yr7<-t8X;IJjZ;G>UCVmyu(qabuRID8b?d9K0;W@ZI*J3X!JWH}<-;dqQ;X>?C z1}3K5PTvWdvA5}VG^`Mi|@Xm`w`B!}ZlHHHWK)l~iV~YA!L|(nJ zov&0Ee+)o)z$qM)ha|v>n_F6{d}sY&cNOABC#x3^S1q_CNd<0jTr>RZx=zOy?3C!2 ztmEg`X-OrE@{jw;UN=DhVirjZ2KgRL&Pm!Eh!8XBkS~@kRbW|I;k}$V9 zLaDFBZ}dfWMNVme4Bl}@?6rgJ?Bt}VZ1O(R3FVBWBp!7cJ47@;Db2pWPFKfTxTTN| z5mYhzxY%Q=my;s; z^T*|SPYQ7n+PJ*1P#nn684Hi#Qohrr97ibRP3N}U`03ksbsaUz?}h?DFVdN$yFk^R ztDi^=K5if`)ick^CIz!0JY04MAs1``K9j>tTE4|GpLdl8J{YQ@uYU|{TCgiEE3^6c z{8WQ>p-Bdxe9Y0@!{k!rJ0cLo_c<8)t=CJ58OrA>;C_fJL;IK2Y~;;{U$U)7m4a>$ z+0fGkq!rtMro@dt{c7VH?BzA;R?NRKO%Pg4UULbD6@k%3B)$AlA8mSNo$_?i*>go> zVPt%7@wlN6URqjn{4I4+L#FZpl%$uNkr^naUlIX|jYwjQF253Kd{1nNlPJiph~ zCF)Mk20<5E*oB3a5LH2R2zEQA<#|lZ%tbUZ(O^`gB9erp*@*kA1BsPZcg=y+K=^Q7 zI!pP0C_;|(T0Dhu%$Kv^S-K zL&||15`(l;`3)qVp}ZKFkuAmXyS;8Y(8NyqBQu zaK;8Ru%1>(I)UOpoh~&ffIuJW#%5>AzwZmyZ?05)NAN^yvAML5i~G^tyhltsM#@y{qEqa@Xbb31^mqrP4d z>B#kCH1QkpFNltNklh3v_Q-X_g1}~{)ZR~(fh@Ha{sl;9ns~azu4*#QrOd{17w(Mi>B{BuE&t%3kA|V$dvyvXWoA}R z|}ESiMM{0{6zdIh5;*UXX9VGj=pVj7}W zK%y1sBc@M&sL@jTMymWrO2@Iiu}^~%h(zP18)vz z71sDGN=pS8lp+@~w}*RLV+}jJ23Yp`rOaW)-l)=ho=LdU@gmGkNNMr0}rMXy~c}!6DuJHh+FV$pp zb|y82oD64w-)U*#Qyrr7Lc|Sf*hkLnBj`meDL*onu*(AZsj&S*bzExdvBie%;%+tr zw7vcXhObs?vdf$Q!OVoooM1G5(%AcMzCeK>a2Pd6sp)RG5NmC}(xA--fO4H@DEc)h zH$q7T++^Pc!G{sKyz71@=)~`HT-bu$qtVmh%BibY6Ub08p}}ayhccqK#QMeSft*6d zu`HV*7RX6qiRF3gI+UR)M~AbvkcV-d;?p!Hl?6gR1kd1xdugZ0z)j&WE35-+<4kVx zfmjec6*R2Fb*1&%%lsQEFXy()QBWGP^Uc%!bzW<$fIx9qCb2`q8(dUaJgMoCV$(;$ zg5?|u1U`80ie`2kBiQ5K>KNd(Y}imGKCrCT7F z$Ii_$Pm=-AMTjl}V7-WxG-mdKvPIb?#~7*d@mTh z2G9H1B@+#Dbg;4NQk_*yg=dNdA~rs5Dw?ig2o&sXqNet1Xx#~K4G6X%G&p>mQ{mIo zoOEh|qWJW0&)rQ5Lx}uwuF9vO;!u1afrj_1GN`oF<^ZCoVp@TXD-cLZje0PXAPyOs zIFr?xjiDsY;_0nkaFPN5m!l(3_6K%-4tcRCHW?;c)IX3k#M8@MSnz6RS4a3quzT4vYQ)Y1~*Id_)~2u4H?IkedtPy*AF)C(Mc z*{~IR{5dop(=(A{0ecTF+*6$e}wIZ`djj2PC@iuo|lvcAU;CMdebi#pso ztdbKAp2txM$RIfuecEg}0V*Tirqs)Odv43rQ$f=*YbN#-NDpx%I>Pkw^76_$6{Kb4 z+yV~IHD-hRu(vfM0`5w$$Rt_I^;;r#CycVcPK$F&)r^xoXC75$<@QC|0#F`M08m@D z|3d@Ma^9z?-FVFI&GNopvaRY#STwMffq`L?0E9~A8G0g>W%`fe*489-;9(deGy11! zDjFnUgGRLddhO?(uL$< zY7L*|#uK%j^HlyZ2VGrV!#d$G3M8EH#y*9E^hm1=l}i~ww7VzZ>sU_d-W0egGu@hB zly|WmNoBQEiuO!)VTMVC@9gZfo^VK9QUq5aUXVOz0r}Te3W23*PVA4d_w0JX+*$Z` z{k0FsL70mDwjVwKTSNH==!LLwGyT{myBMv05|(RkK~WLT*yo}5QDO$^miNz`)2t?i z;T^i{)_+UIG8to?f-ouGmKRCcSo2ATgdoZWM-u`@FvVAjDDShe8V%W}YG98?D;)-6MJ!G=Rt2eLs$y_oN6lSoZC|osa z8j3_AV`vB@KW|GgW?os6vcE2)uHAbZtAjBZj^q4~UYXlQeF{`^v!>%B;9lYTaFhDk zJa+Xb;9!=~cGKg_=*YIm<>ax0!y0zp(EIW7@J#crmH)D|Fp9-tp2&!mlOl!;|88>3 za(Et_dZZC=HoFP=fntlS(Fe!b&6b#zRrSD+Z88_&{|&H&;vl`*u@?DpQ76}6k>rpl z5>FU_o@Jevh<>Jd#H@pj$!pj#q$ebYm|Hb@D7FJg<$fIo3vT&T;Z8J68BUyt=pglT z{&(`7J#*KMaD!&2n%bZgKuql^XBerl$#ac3mKTcd_}L%29B1E-FvYT~03Z$IISz=e zH`D{3rHKh|W!C9cD{^$!Tox_1^ujGp_JG92raQ17tk?DiRUZwqy}SET1hKqvm##4z zmuU%%M5@VAS5>w8u=4(SiE#b&1{t0gh_C3z1Xgw}!aCJnmCIsu50REFUKr@;?6;D= zjYl`kw4HgSXEYw2p9q-uK7rXLUP~rlLf5qv@pLnVN^`75Y-=3)h|PdTT0*e z+-nrzjl|V|+d%zY^dGPC8&Z;I90n;V_{kwPX5@w=9jb!Z~+A>?Hg-Dc%~^^y0{{W6EIu2f@u* zj@GBEnF*f^e2I{^;j{?x#y!8Nf+-oWsm89ctWEWhG!^N@(|wTGkH$wv{s={pe*AdX zefib%Hvn-djSI9Va$vKqF+d?P-=X+plv`}%*euh%ciDdIsmF5_BpV?HnwnD8VIvOA zmQcXwK;Yrb&nfPY^J3o4K9Pl=bLf1HOp%29ITsPpn;OVk6cwe&xn&&sr+biAK|6v* z6u{sz0Y_JaMQC7>3sub*6u*a!!R5%}V!y6r5Z@K=X`b$9ob2%CZQYJ{4n~x8jzHSv z%w>Q3fF39BGB0CpZa#T+FvE~3w{gB9AJ~Gb{zuf!e}XvR@m+s^2MVglxBc)y36VG4 zq>-9q*S5`75fKsfL>i4p?Ha~V)DVatX7Zk9>|g|XXKFybow3CZO!zgbbU$Foz}_~a zoMQK1g#}`%DKMpOWzN?}ttoCz>(Q3oXrHSGX=+i+PB~m7G^D?{!V`cd`T;l0t>gqTb5FA+)u;@KN7LEc&p4zi3z>xkXa|_8U1aWvJsRj;Lb^f$}mRaLW%xqu@-OpFEY*V z!fYQi7(?x}>FXG%Rc1_UYhJzel&P=%mw9_UaqGDtkNecBY^-Ph*JJ8BMl`PH$o%P# zVCjHhu>gC3t>V07U8r!Yk^KXP`LJk}g(J;n$Xl=Q{ij<$-rDqHk7CF*0@JOHTfpr* zNiY-%tq%VYjln;p?PJNt!st5>kH*Ya1^}nV-k=!M0O&4s=#PQF3`tNW?FnQ5Y{V|x+gldrlafZ!M?Mo~0{4ZR~YE<{*Edt~>EUoI`jE1E7hQ_a>S z_AB`gMWy{sLmyz$_M5q1v;*I&15OnwxG}lDDrX3& zP7>UQwt=`XZuzk}{AsE1AU47=X+GOS8{9s()m>E-Q>hBg!!`2*(*>jXr^ZOSw>XO6 z^}YRt8U%oJLm!-lU~+Ws+%+GtWqkADSc|S4gwh+B$RJCyR`kyK<+f|8&w$&YwId+e z4|UlRl7frWuOWn{34I#T!LAz_k?$#|nF`XxHVgRL{q{D9rc=aI(ddYJd65!|B7?&uLHRDu}{@_b|d_0aaHae){ z>dK9n%MurZ$i+{5!KG#au+>uarv1Dlr;-H04@?kyplBV2c~X*{?O**9c#N1uLa)UH z;{0&yzNKg#3!DpL=2*gxXa?+Z%d@FGnJBeYLze`ST-n|62l01pr>`gqPu_vo*;tsE zhM2R~B?oTGw zMEcYpKh`krBd1u2fZG-_!=cPgM4TU&3!T2mRP!?c0PtpJ&N}eRD3CSM{R0fCsll!- zO1LOcm?%-|dxXFgH3|v}+}69g84hF~7nnRPZm#_(PsLq%+!w^-LO)#}Hnf5c7HViv zU_yITwfBD4v-4KGnV;!|KQHV$bW0z6U;5e2CqQ6>y zpJ&0FLUpt}qyQTajE|4!0dU1X$cmy` zJ}Kkt*E5f#$R7u$&X^y|Eu8EcjofDq{#F`P`m&Dvv@B22ci8Ss0bA){*Y z5^#S76f+iHjpnURU=NcS3Np zh9&YCPQirZn=vG{fi^roK5I$!%x?T^Zf+`?Y`H;qP%P7(&u0su$PlW;2AMgGr#9T* z)B;46e6PTkzia>eF)1p8_W?c}I+cGh3pkFDiKPU}sbWU84j>p;cE95LAl!N{^b)qs zVeN|d70yr%9i43R_lZE&a|$SDy&<~$>;}G-R{*mwOLsO$MMZu4p8qd2rJ}t(9cmC_ zOmF}~)PVyg@MLwcl=Ln)`Vj||gs!(;S?jnJ$jmZ?r=cd&U1d zrECq>1xL%sm{Q%P;-RiHA-imw8%$x_* z{`ccp7C;&h$8op?MO2Qbi|y^BC{Y$LblUszBhJqDb|2I3?VEF9fQfgyS6oryp8ghx zI}|ADnenx#l>($Glclfy;h#RW07&N%YSuT&ny^dyET6eQ-2X7CLFDx)yLkZcnE5)l zpM@Or4-iir@119VHmdWq6j9mM&?MD+<*> zMJbW~n71r`xP`^xwbj=r5|faunD^IXP{*29lM-CQ!Ar)h!*?r(14vx%)fM+(OOFj^ zTFq8)im^Bi92YhZ?da&JD=G5rf&9AyihzR=XC%c*PLL477nF>@1Q-6t%S~C;P#6j^ zKq6e%xlxZ=TJ^HUtf`xN@KXXuyL;(43J#uX3!wo8wR_Bz*;yeotqXF18em#w&1r)7 z8vo9IrPaVla8vR$M=BD320-<=4KCn*MYq|SnVEU*+zUC)@Lb)~7yUN5B`*ytE-Rz4d$M~|PEfZ6R7`Nj z%9A-rc1Cx$fr70h=4oMzDQ)OAjgrzJU`%5H3`TM4_IB&tOHx}Rpq~t5kAxdj{&=ys zyPH}Xp^NlL3IIB^;H2czv5*4b`X!04c8RvAdgX82kLFahw7z9Z_dxKXb^$xvBdf~V z3t5ncgXu0VE`}zA_uNIp#WN|_Igof)p;Ut|h@FvdO;Ue+y2Kan(;AFEDFLR~QxkSa zqUqsxU8PFyQO?+8lkRc{XG<>vkfe@dvG8Pw)MPrnz*PF5t)jCaR)>GXw8X5b^7 zgSm$ENFygFei^f!rA!i&f?9j>N8(V9mpuU=Lb;{~uy2*uVv;eo3|DH*!gy#ZZB+$S zL~sf@%0)rbvyhx%IosY)rC)_gJXGB)^G0lw>ILBZFTc^VsNk|zzTo7q#Q+?Jsd-lo zEiIROSk|=}i?fuR+?Tojnuzl^BGi)w3RXRVk_`AFBNLp+2=G+FaO2}0hBM)2uR0}{eKrB3IZmh_5aE8-_#Hg=vjkOOf+-( zW#%aV31F(tOHA{N|3+h9h#R^?Tt?DeS&-^qQC&8`$)|?~V*SV5HwKRZGxwpt*Z0Ox}u|IS75zxU4xfx{z5_<0OG0lfaP`Ip)FzB0_1{debL zF9JbHHa>3tpFsR?(Aw$1dGxB=0Z_R|x#8USPKlFRRDUNO|?&siOG9F~@@U%^j%! zdvu^QmJDd_{%*thKXJY#1s4DIOcX!s|Gp2n`4FK?3vd)=mjxkw2ykxypRf9FXTUl@ zm7=)PnNt5f{@1l|@d>&1_P=Ef0eTY7vYo<419bv7f9ie_n)8Qby`lf^gZahEB5K`9 zJ^)A^K->R=Xo7-G4&R9tHdT$ z!V)hARzv@`Wr|8Y32?De-}*8E-4k@BZh#NWXY0I;001$v26Q81aJn?yE9Nl)>ZyK8 zdgd}b01}*<%A@*VXBVXrHE{Re*hVTxreldswEY zHrz^x@+W}+0MDEiiL^B@H}`%-eo4u&tTSsK6mX&dOK0;-d}^xv+WlO?(jI3Z5vAeX z`881Cu^zExcx})s>X_fzX~^qHQ~`K1KpG`kpF>*! zN@Q@MVv3~w@-9*3O#AxwZ~~+g8g-MJwPz;XB?kt4X-bMsYCg31yYoo7dm=G$bV^}2 zUb~Ec#{R0ALxkCP){KMGHpik-HVVgsZgj5Ev9avJ!mavGm*37ApDn?pGH|Ne$pJca zEWwjj^CcyWq&K!Gl8($5=zV(a7_Or~e-_$Sb)>R38*`&jq0dKZp6ji(MgicpBmneA zYerRZfWATfT}d~#zcDoxgK=~kcV%q&b|^NkX-+ zO6sC)ME!yDo%}gGoP)=#wMqY(5MBmmJj#^*qLn^$COU(z z6NP)~4DN6ni+)b!vFCI@UZ8T&Ekg{&AQ8{{{7eVL8skh~DCf5tbtU1rkobCEYsKg) zLBv#)4~lyHV#v(?$trdUwGWxJlLwN0)f5x!EaWTPM}yBxa{lvpy5hb6{m0{1p3<#) zY~{_=p?YJ7KkFW=|Kknx{?sA!Ba;Kzj8)yQMn0py!EX?C7hg#mXn04f@H<*X4P`yuFT;T0X- z)IyD!8~rCBz`(tuS4x!~{r)*m#9s|;To@oK8lJGxWXLNG5p!Cg*+i2EkM!9RB~!oz zr-VDv?yndN9X~%f2)Clr@Ww1=S$?nNf5maMSZ%U(;Of%_NtS}!*hq#YSL|tgq5=nq z;0|AGDfN{tW{A%bl4S-E_6~cL+?*^=B{I&x^e@#ajWU9Uem`8#qZI=ok~(clG&i{2 zDk_B=iF(!b?RPUk$-A*;CY_?zDNLkXSfw4(0WBpd=E?hlY`59Rd=M>YsaB*MGF~|( z(uW2R={(XmCH=H-)dGR2J@t%LmvJ#ic6w&!szE*dWd5lV_^<*Y8kIEw0o)HL^Yh#5 zZ<=NucLh9^qKP;V1G*+w>h%H4>;o&22fQ$;RzxSbgGQT#ir>dH#AC7qSan)vTNl<+ zx9$JyylR%6b#ZmQB0{z#kE<;6ssxg5*4BOTRNgZ*O)2vhTyaVRtS*&NH#{`*U_vV^ zD;!Je}O?`IMk6iJXG#fiF-h;a~^~+%R)|qN>XPA2G2;fC}Hd)V`IORG}(1GEF)BCRf?*I z4xj%1le^sYl{;2M*O(VrB5YT=5UV$|v<%H;?NddHfGNyA3hPJ&D*k{xS^OJnA?riU zCwe6(7YJCxs8iZONd97hDEVeUS0?34emOh)X0<7f{~jCu7P9UZiY=z`4cd+N3dJ)D zs`EF#@=iwWx&kX(v1k4^jUhyg?~5o<+iV4jAV5RZ)G!YGzc!0eEw7V?MIi58^#{T)}>(EiZ-j{5*PBX$Q&N9{kxGpM zlw^FDq-FY)0d%s2S1m^0@9v|oMJbInlOp(47yvvZzkR;t3MA7rQPt(9pq`v`Qf#Xt zzIM_%#$^aTH(`#7jQT56x=Vu+a)|Oucx)(Y9#eTZSRG))0G^XjDbwdQ)t!k`E2o!2 z?ABpL)2YKdKC)aWy#AnRbFKr#5w^<+w>DD!0T`dr%phj=~|nDiTaf+EeZIVXO`T_K!i<=B*@cZa0LBO6N0og2xW;7mS{8yBh>`J1sWnvkD>3YLQo_w!QxmV_=|&I$o3VR} zp?kNzkdI$Q&9a0<3H@E`~l%Gim;c?}yORf#e~-S!K< z8;WZi-o3U@O<_eadiRM3C@mFb{mjF9dn-%v^l2nLg#)At^|wLxU0T*d5^Oacc$NjA1F^p4(gv-Qk7Z>vZh^yY{%w+WkLsLJ~s;kr5 zw0;Jo{>pm&<+b}dt}I}wgHO!kaM?X(f}HV6=8Zl-DT(77ROz`r-vu4~8D*OldEvV3 zWqpqG0GPcEgkuw6P>0ubz6|*%6)ak@hN{l{)aqp1K|>$ox$Z)X>ubi~4ynM*1NajO zd@}|p!({fI3@G8JFf(&xWy>y8PbR)tQ^Tg%pv3J@!Lu1{qw(+9k@J z^td>&FXv;X_(-ngxG2#beT%ORbMy1JgZ274veVMjB?%1NsFcz_7VzZS>>w(X2%X12 zZ$?(_uXu`N1I!ScT7BQ^B)6jqUYTtpb#(>6c)ap`yeLZ7W2P2g%}`WUE(GXGGs1s= z%K;4yGUkul2|x0_8+yIje8Z-UN(BMju_R>UW!}_O<$Yz3a*8;naD*}63Q>9a`wzRN z!x}0o>u|V-2|7Rg@}5msfBeuWt+rpP&slrE`Rkq>V55YTm9QzT*V`Nt_Rd1xzCwg7dwR8Mt$GV(WyZRG;~hNXd)or{3Z1y zLI=7KvKgbBY=Cw?&V{UAoIG90rVLlAkuN)=+LLH(?UDrr7OL{+HuSLl=>jg{t4V}b z{&|L#rnO9kAGiJgh+m(6;0JCDn*mpwh*6yMISwefs3}f)P@N}%h9~U`v<=<_48%}) zej}S_g_O==g@|80KTu4!e=?G-Q*G))isYd1y&5dEpR2C+EFvqVGFEHzPO2x~AK|r@zqnp!Yi+rv38wr=AqG?^lw%#KYA$s!M1k&+$-j z`O}Y`8rwj{y^=}Vln_D5dzj)VnL}IrHo()8hKx$NMSTF7u5|TciL8g~$X5M{`P|Mx z_qY&;#2{{dz8-M(bS5IH98&Rb9a-cTK_1g|`;2K(GZFe(T>g^U?2CW6;AO{S7Pe)nm0QOHt6PYpx;H=hj z<=Q~&r$qFW5?K81?(V7!;V(|D9NNb3AyRl^-Zh`J+7$F^I1VnZnR=Ajs=r`MYM{K9 zcpbw~Bzm5EKi9-s;OKkAIpd)(vPz4AF}M#@E~g|6Nq&#-+Mtm$Tpr96E#|^1IG2Py zPrbQ4PuqgGtaomOV2_{|$~T~DmQM>9iqE%$KPFu#o_aB+qbG62Re;u*RX?h9^~`9< z9tehBzfKYm10H0pu2xiIMCA0jRY?{4gbmO$-aEu*F_|`A?54S*)L|v8m?Xyh1 zZE1mQ)5{iEZB$O<99vGOriKU68lWD(-=CsE$jIUP%{4na>t#M0h#2XE69DvO>v_jL ze&2fvDiNS=fYyWzRj`MCx%wJj`f&E+`zz)4Y1cH7^B-rO$Uv)YLuUZ#t|J5Xn4%9& zy_DFL2uA9iAg(~^oy;~JPF$`iyBeX$vuW#}5tLLiu3qZk=aRXFkLdv1sBbg_Lk;nv zX@&;+{Ym(j1x2A(ur4S1bUDr+{Dv0j$Exi+Ph`WN2CT-l+g=72imjlK#cI@It2@bl zruXUJabx6MG^%<}`Bn!9JZjZP8Y5A zD$u*Ku{q5gAuYHyw;4A)$rrCi52S?avQL4*DL`sPihyM`}{hr=-+jI z1LFLG$QVgiAo-7X<8Q}bFDc5Ls$&Dv3$O8e7QcnqlbdD7g0+9oF;*FWN3nj33`T1n zy?Pxiiu^$F7$lZABf1CH&(cyt<}&0GyH^38siAz6*6 z_S1Wy&BJ{r1l7gwyj!FMXc$6N6-t6ni8AuLdy~rV8d~H-!_lkg_A}kn`fSxVj`d-a zbWVkvo7=iBF2Ur7ICx%!I(YI)RL6~I+K0xvO)q0R0wnex@fbCH1%3rvpRN@mD5b;d zfvh3NT2}kpWmIYDm&oh~_rXI=E%KbE)l{=I;5LB%j!-<1wvlf}(ubm>#}mg1oErn1 z`O1?6S58dm%2mgi@Au~|k!J-Y@4=6z+=kkoiR=OsV`D0tW3M>&$V%CJkL;1XXCxva zd&`zh_D(25Hj%w0LiWnu+xcGS{rmj!`ycl?*L~gh^?E&DkLMGAsi5{7V9Kz+IIzf& zc#+NrVbbcjiu`bwpyMl#fee&&HMWa61NPe~GCKP5F{Oz{U_`0w=BP}Q1hjsvxxX6? zVIMvZ)6HUV+)1IE6fS3X#9G~~b3*i<(pf}f5bf4#Ro5+^Kcxq8?FaN3wiEEQOEun} zy~C&(U_4uD$KL0L#6S^QLCQ+PJPt+0#rAyF-eNms;I0P!(E=w=XQkb5lehORQiYp3 zOHFA5xD9JV{`y_h0NF~*#CYP!#AC)&3$e}X@>AK}C(~KBogFQ>=i$5ecL(7mVrGLg zaODbYX_s!QSIxhU607`wsG}hj<>i@|m^frzNFrfCjn6v4M9fj_)=hY&kSLC1i=9*( zJMma61WdpA_5FPUx-+!Fjiy^A=v#}{!@BR2`#xM2yg`9J<$G7I#TD`xD`c0^5anzE0E=6AWpr9)AG z?+3Oo_#E+*lR9Eln;|%LMur^(=;$#1jKX)k4=Y17Ef72uRn%8t zFe1>sY`a(VB)Jz`E$TqH&_2b_QdsAxcQ_S!gmYl%?TI7Z1)zvmu zphu#@KbgXb)RzQ-#tkE|x+tr=E(J7;mi9+}N^e!@RNmxB^Q`AE^*jDOgp<2(TM?Q@)O^|FO` zTVn+xCO(JV30z)&1Y^#+=*GYH`Qw2ATD*~c-8AcjKb9kS$S#ecD-()o2(`^FFMlz= z6+NQ_%b>swUC!9FWQPR=+=3jSzriwQexPv}O*I=X0dbS|il* zg<^4(jJCr1ZXzeUfF;}W&+p7d!TbEA(nD#k1ryesV=}lmBpj_@bW%A!N}-Jf1G|D1 z?OW?QF$NP$T0}n)=I@LQ!=a-wYZ(4zHzg${{(~KSHrNv!s_W8+F9QyQD>g22ke5Qf zz|0Xblw%7u2BAKafJ(NtTcuv^@Lmcvc%6nF&v8!~R6yfKDLFan^>g_@8|k;qpAez# z5B>Yc?)yf-mSu>G?Je|j@tU7K%>qkH(=|=}YE!$wU5vZl^APSUhJCgr8Scduu#BH4 zSoz&HAFf4TQ;}1zpo`IED@_M6OeWsePs_+z_>%7K1BIw%(fK|g5d6bC+ATyPk*DE1 zSUsQem`abXGy)q5FgbYn_tjoPn^i5<_{>+Wfz?5Jb;h82TwNYe z^EfU%L=KqU$tNct?fX}Z`Yi@t7cJ!quM`(E18>>H4a2XnAz9OJIA1$1UxnqcVPVWp z8@(EODzotIs|Kll%S{{dT2Lyo;U_Cv2%#ko$i+~Vs{Hcjk0FUHP7=Pxp#Rl`S(5$4 zTB?~c&Np(Z*!M0#app=f~Y;MqvCyI4Ts~$u-$pQ`laRr@?S=RqqqFHlFe{$R- zahIMA@)Ck=dLMl#fd#?pI6`j7RYJ1-uC_$eT_73fv#&;&AkDqbg|Hx0IURCfI`g%3 zm^S!z+BfNYQ^pN5q|MK%@U0hKvi&f?EnMriZ{vNRbhsR5b;BZYDKwOR%$5G}g`A_x z=tvwOW-XR-ad*3-HIv6ua6JV%e*l&G1kCA$RHxuAz{*$PmIdLlJ5Fy*!!liioWEH=tz2p-9%Xzgg~9Ari+7 zAiE84x%N74JqXe@eyHdgq{HHh_ZpoB9lz52uiO=@Ec-teu?x&1o8%lOtRQ|1QrNiY znV`pZ@WmG3u4DWTqmXN2UpWJ!ts@mP?DNVCbYUa{j#C4%W7N^%Y07M7R47r$7P8FjhAd>K*8AaQr7 zzBRzz#!sTR-oPWy6!B#Dxv7v8&ej4bsii&am_n4$5J1aS=WaPEhjVu0H@IyKEB7u7 zAYgk&y1Jjkk;`)XVK<1O^YKad&c_Y|xDe{YLua~7;2qekcp;oYHUiYwP7)`hZ*8KMjP5k3BVwhKXl#$v z_#v35@v0n&oIn$t+L?JJGR_>Wkzh$vHl?C6FgU(?Gz23DeFQju3TG(1!coNoe-LgT z5uKFKO40EkpTAE2DT+>%kEPBFdE`fefez={S_vj=BiapE`O8IPgbNu2ppoiyEOC#X zxIH9kRNemyuaj9_&)(%DACwWqnGB}$4QIuBhQyCowPtW@26frqCprdHRWjOAg2F?_ zxlCo~iWPzfFVFyQiegZ$f*;HM;ESPz@kkx82c>0ZWDGLl$*d$m3H%6lj(3vuLPaBQ zI_N8hKSmYG1l-9@bF~)XeaOW?y9U+V2heY?z98X)RC*%l}y`K`F*(d=5D9GUHBb7P!nw(JKZea##5{rx&BcjLH zVnjQAW=D5*4ijOh`p^pllEjyUo&=qW@2Y_;HEP#9Xx~c1kWwRKC4{}a4E*_SAznS1UQvcSb z`{lJ0WKmFE&7)Ri#Mb=acOWJ<>mSKZIvlQb3=AH!{e`v#tp0UHW^mtu@M2#HPvwtB zBUWG~9w$)>wk>~QO2|iYp_Y+T^KNI83VVV&{IO|Mpv^1j?yP>J?CV!}$;ApB z186Ko=$Kbcvh&n4pqC8A#$Bg7E_`CjtS)x?PTjNH>ak@PPvgaM)H2EOs<%e^q6z*d z*fS#wB=m+!tzMwpAqcwF9n%N~AqpkRY6BF+-uk7Xa>4Ai*in*SzNF%Qt;XM=4+w1= zNUh4vlUb`G>|E{yK1{7(TMwb}1w4Xa}i?#eC zyJazGY_dfC6%%9l3iaWdGW3TuxjdTMFH~9K;w6Ab|Lz2I5l#PJutt=Vx3}=T&+&cd z1OYj+cav4d-}`lFba88_W${QKjtZF@&+W8Hhc!G<0dhl+737!E4^z^uyX zMDpG$oi^H>_d1>p^SCY!%@(n#a-FoJ34r6^$Fs0$M8>6}%%PZ;QVtbWEMrKFG^ zW~8!wDlfMOYuIAl*K91i2v$#oM*NY)JZ!M$fw*T|6sOI&8j8|!kTuCiv!P4nh90)9A6g%#B9$%utUG_wB{!`e8aJ2!l}9&_{AgG4CX+leG966gWewu22ewsVFW+M0$XW&`I)%S%Qy} z$86_m3`4*(Ob~_h6czmhCT0O}K3B5LO{4J&N#Y%0Yv$d_GHsPUQKav37tU3WgejxX zyWuPfWjQq8JFwpDW9Lwd9B_8%h^Bd21B^-br`(^JogJqP;ZtFUn@qmDqk$?^^5l^E zp(_TW+Ijw-_kN2%``9vA@nE2GC4t){7z}O`XfR!$_+IJs_xC4qsjw2~qa0+YTpVLa zw(nV7q4b}Oot>$Z-B$~o5AfHi2?2#fXp!IsM?`@cM_i z)7OPD<=KD$)$iA@8XbgftgRJOfId|CK)&2%dmKQUz$*x__bB*~%0o`AQlA*GRBzpOxlRS$mcb`kmySgd zk-V%igq^6=AOXEUEm{%9C{28i*SsGmupNvng4x;G3+tb9a>i6kn>5nlFau2Qfe7{Y z%J}1cnG{WfmZSb{cVJd6{e6kSU=9fc4U{*KDyi81c~h+RQt~@RZ2P2jP=F7Z)v>(8 z5blroz}o3S!|WJIEzOfK+pA?$*#)hYT%3QqP!dBW@J*0oV}l{iC+?u4Zz|8^-$i= zX@^lKF@b(=;|9g_v3#mstBlt${qL`zg5ji{8gISa#_U3CCP3<6jxF~81Z<-vK8sON zvD(LquKO{*G`2(Dzx0e69y7r12QJ+1833`rz~pSl$Jv?yU|-OME1LK6iW;A*gfx$FZtd-1j|A{!i;p6z|HgG%9dpQWhVD?eHg| zaz4+N7epe%F~GwijM!}gd7pZne384aXc#F(wMY%SaJw+<$I7E0iY0=<7xy0<^${!3 z`b8flvGG|!4C!2eY0djznVn%)@-e7Du_tU&V^V*J=7N1IIQeBd&K!(etO?s8W3n$!q;Jo<6mH&V8D)ZZd>u#)R=>nHP^`bdmo-2PDe0F1m^r)-Akj4 zCl2|TNjo3f=_^6t;2)MQVsdnBLP^$3RNtvMCR~=zXQu%UiwdH}jQ<@b+t|}_2B8kF zU~t}Y_%m~gs`DuYIvL@`aSl>hAy(&mZwL8SbTmGg|LzOurKxnwN|Io~wH1@O&$cEq z0l!lVr*8$d97vAQ1&2uxp?xH9Gd;cCQulx9W!S%uL&Q}8Iuykv8ph%ZNvD%ySdeqm zt{z-^I(PY*ZiuqqQ6weRmEZ(@FNw@q9%;aXaYm^B)tUmKkm;*D#RjbWA0K*enmK^T zo~cL|RZA?(V`lvtTh7}J|2u(OFa~nG3#ZJS9DLp*{TZ}GGd^+vZda5=i^8L#jP>G@ z0uapYxzxJWw0DGv5>kM)BXY+vbp+e3w_-H4axNMw_R<7bdf3R`&Q*(FiIesdrX0GAMnS zgDCpI&Y~%#PS>%qVQMK7Vq!2`tBDTy12vzD{hTtN0=F#(C9P4Wm#9=)V8al1!e$MI zYhL~N&Wwr#^0MlLs;;795Q~6C3GB#iV%$)*yTvxZnZtlDqyP-^)awdkbty)cfL8Wk zb158|ym%a;n^I*U1HRDHIs9LSbxuOJImlz=7-*oCr!#+OFa?JmNcvo^J-?^o#w#zW z3PDXZ4cq*J3p#%RbJf1z`6HlhiX8GSv(|3Ftgv1aFb-!+%FluKUy=XqZ=?zU$fTzC zCb+OiFRmBNTtZSz3>w54%(2nu2I9odk{He(+qWDKzjI%SssE45fbx7{p!yvH;{W0= z$c41>zaBwv599pv0Np@40Wx=9j%7*sBVPV(?k2t8@)&6WA(k`;kcam{B#oxtXG0l~ zn?{S0(ouo)B83f=IN+#CLmP<9=MlTT=!qMjP)Gh9k1;hftIF)kiVt<*!6>IY0D4UI z>IetOf}*`U@ZSU^M*su zPbwM!=gS3F;L#E031}7`KjONl<$pP_uvwgG`>%#fRC~3`KQJBy^L9CR$poaivnFEU zk#;AqE_MWi*XMo@XAc%Rx&%EB(9U!W4Joxxh*%=3ZP1B(a*#J!MFuL*?)i)n1J?gp z$C}y_&@Q)T{q9y-;>JOBSnxRg={AXWO>$|-1qMSd9R|6E*zHM;Cev(#E0HglR88DQ z6cz1-_9&19aA%<^U^lvix0b-ha$<%&l@VKeGvG@!RkfgqN5+-Hl4Y4?kY!FE5Iqip zIYmFYl8}UNZAc)$?J*+PGj;7uR%l;?Qk9+z>DD0d^keRb_;uFZn%SL+z;gtCLs?m5 z{LAyKPM;t`C>;hcP$p#?P+Bz9JgJ$wFEA$!)~X-}&)m&-zL3~Vh1PuO%K=OYE^%r7 z5WE7oiyb)Hd0ZyoF!Ye`3`-l}HVx=xpZ(vm)_d^-~a zj9F)y`kzfHK@zhVf7brbr2xkUw<~hu_ng*Km^mAHU^~i-!DG^Q|38C7yAjw5o>2mB u|IY!z1HDiSgxvFThW=+k5LZ}4qSNvgiO`SC4ugN>fTkp;CR-_O9`t``mD`{I literal 16580 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 gzzf|x-r-!r>AE2PjOK4gdfE literal 6703 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 Hcm00=YKvXV From e4083cb8e2d71d8ee17bd48321140ca60bfff198 Mon Sep 17 00:00:00 2001 From: Olivier FAURE Date: Thu, 4 Apr 2024 16:07:11 +0200 Subject: [PATCH 04/21] Remove unused imports --- src/contexts.rs | 12 ++++-------- src/lib.rs | 2 -- src/paint_scene_helpers.rs | 2 ++ src/text_helpers.rs | 3 +++ src/widget/flex.rs | 2 -- src/widget/image.rs | 2 ++ src/widget/label.rs | 7 +++---- src/widget/scroll_bar.rs | 9 +++++---- src/widget/spinner.rs | 1 - src/widget/widget_state.rs | 14 +------------- 10 files changed, 20 insertions(+), 34 deletions(-) diff --git a/src/contexts.rs b/src/contexts.rs index 11e2c7be..1136c1ed 100644 --- a/src/contexts.rs +++ b/src/contexts.rs @@ -6,14 +6,12 @@ use std::any::Any; use std::collections::{HashMap, VecDeque}; -use std::ops::{Deref, DerefMut}; -use std::rc::Rc; use std::time::Duration; -use druid_shell::piet::{Piet, PietText}; +use druid_shell::piet::PietText; use druid_shell::text::Event as ImeInvalidation; -use druid_shell::{Cursor, Region, TimerToken, WindowHandle}; -use tracing::{error, trace, warn}; +use druid_shell::{Cursor, TimerToken, WindowHandle}; +use tracing::{trace, warn}; use crate::action::{Action, ActionQueue}; use crate::command::{Command, CommandQueue, Notification, SingleUse}; @@ -24,9 +22,7 @@ use crate::promise::PromiseToken; use crate::testing::MockTimerQueue; use crate::text_helpers::TextFieldRegistration; use crate::widget::{CursorChange, FocusChange, StoreInWidgetMut, WidgetMut, WidgetState}; -use crate::{ - Affine, Insets, Point, Rect, Size, Target, Vec2, Widget, WidgetId, WidgetPod, WindowId, -}; +use crate::{Insets, Point, Rect, Size, Target, Vec2, Widget, WidgetId, WidgetPod, WindowId}; /// A macro for implementing methods on multiple contexts. /// diff --git a/src/lib.rs b/src/lib.rs index b5b3934d..fd6dd169 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -88,8 +88,6 @@ #![allow(clippy::bool_assert_comparison)] #![cfg_attr(docsrs, feature(doc_cfg))] #![cfg_attr(not(debug_assertions), allow(unused))] -#![allow(unused)] -#![allow(missing_docs)] // TODO - Add logo diff --git a/src/paint_scene_helpers.rs b/src/paint_scene_helpers.rs index 9596957d..9021561a 100644 --- a/src/paint_scene_helpers.rs +++ b/src/paint_scene_helpers.rs @@ -1,3 +1,5 @@ +#![allow(missing_docs)] + use vello::{ kurbo::{self, Affine, Rect, Shape, Stroke}, peniko::{BrushRef, Color, ColorStopsSource, Fill, Gradient}, diff --git a/src/text_helpers.rs b/src/text_helpers.rs index f153321d..79706a1c 100644 --- a/src/text_helpers.rs +++ b/src/text_helpers.rs @@ -1,3 +1,5 @@ +//! Helper functions for working with text in Masonry. + use parley::Layout; use vello::{ kurbo::Affine, @@ -20,6 +22,7 @@ pub(crate) struct TextFieldRegistration { pub widget_id: WidgetId, } +/// A function that renders laid out glyphs to a [Scene]. pub fn render_text(scene: &mut Scene, transform: Affine, layout: &Layout) { for line in layout.lines() { for glyph_run in line.glyph_runs() { diff --git a/src/widget/flex.rs b/src/widget/flex.rs index 39eeb27b..8b486571 100644 --- a/src/widget/flex.rs +++ b/src/widget/flex.rs @@ -7,12 +7,10 @@ use kurbo::{Affine, Stroke}; use smallvec::SmallVec; use tracing::{trace, trace_span, Span}; -use vello::peniko::Brush; use vello::Scene; use crate::kurbo::common::FloatExt; use crate::kurbo::Vec2; -use crate::paint_scene_helpers::stroke; use crate::theme::get_debug_color; use crate::widget::{WidgetMut, WidgetRef}; use crate::{ diff --git a/src/widget/image.rs b/src/widget/image.rs index 8d7edd4d..eb5814d9 100644 --- a/src/widget/image.rs +++ b/src/widget/image.rs @@ -5,6 +5,8 @@ //! An Image widget. //! Please consider using SVG and the SVG widget as it scales much better. +#![allow(unused)] + use smallvec::SmallVec; use tracing::{trace, trace_span, Span}; use vello::Scene; diff --git a/src/widget/label.rs b/src/widget/label.rs index 340e087e..d061a426 100644 --- a/src/widget/label.rs +++ b/src/widget/label.rs @@ -8,7 +8,6 @@ use kurbo::Affine; use parley::style::{FontFamily, FontStack, GenericFamily, StyleProperty}; use parley::{FontContext, Layout}; use smallvec::SmallVec; -use swash::Weight; use tracing::{trace, trace_span, Span}; use vello::peniko::{BlendMode, Brush}; use vello::Scene; @@ -192,13 +191,13 @@ impl LabelMut<'_, '_> { // --- TRAIT IMPLS --- impl Widget for Label { - fn on_event(&mut self, ctx: &mut EventCtx, event: &Event) {} + fn on_event(&mut self, _ctx: &mut EventCtx, _event: &Event) {} fn on_status_change(&mut self, _ctx: &mut LifeCycleCtx, _event: &StatusChange) {} fn lifecycle(&mut self, ctx: &mut LifeCycleCtx, event: &LifeCycle) { match event { - LifeCycle::DisabledChanged(disabled) => { + LifeCycle::DisabledChanged(_) => { // TODO - only request paint ctx.request_layout(); } @@ -206,7 +205,7 @@ impl Widget for Label { } } - fn layout(&mut self, ctx: &mut LayoutCtx, bc: &BoxConstraints) -> Size { + fn layout(&mut self, _ctx: &mut LayoutCtx, bc: &BoxConstraints) -> Size { // Compute max_advance from box constraints let max_advance = if self.line_break_mode != LineBreaking::WordWrap { None diff --git a/src/widget/scroll_bar.rs b/src/widget/scroll_bar.rs index 8ff67e29..27263bec 100644 --- a/src/widget/scroll_bar.rs +++ b/src/widget/scroll_bar.rs @@ -3,6 +3,7 @@ // details. #![allow(missing_docs)] +#![allow(unused)] use smallvec::SmallVec; use tracing::{trace_span, Span}; @@ -167,7 +168,7 @@ impl Widget for ScrollBar { } ctx.request_paint(); } - Event::MouseUp(event) => { + Event::MouseUp(_event) => { self.grab_anchor = None; ctx.set_active(false); ctx.request_paint(); @@ -176,11 +177,11 @@ impl Widget for ScrollBar { } } - fn on_status_change(&mut self, ctx: &mut LifeCycleCtx, event: &StatusChange) {} + fn on_status_change(&mut self, _ctx: &mut LifeCycleCtx, _event: &StatusChange) {} - fn lifecycle(&mut self, ctx: &mut LifeCycleCtx, event: &LifeCycle) {} + fn lifecycle(&mut self, _ctx: &mut LifeCycleCtx, _event: &LifeCycle) {} - fn layout(&mut self, ctx: &mut LayoutCtx, bc: &BoxConstraints) -> Size { + fn layout(&mut self, _ctx: &mut LayoutCtx, bc: &BoxConstraints) -> Size { // TODO - handle resize let scrollbar_width = theme::SCROLLBAR_WIDTH; diff --git a/src/widget/spinner.rs b/src/widget/spinner.rs index eab231d5..a92f98bb 100644 --- a/src/widget/spinner.rs +++ b/src/widget/spinner.rs @@ -12,7 +12,6 @@ use tracing::trace; use vello::Scene; use crate::kurbo::Line; -use crate::paint_scene_helpers::stroke; use crate::widget::WidgetRef; use crate::{ theme, BoxConstraints, Color, Event, EventCtx, LayoutCtx, LifeCycle, LifeCycleCtx, PaintCtx, diff --git a/src/widget/widget_state.rs b/src/widget/widget_state.rs index 22f6dc91..ab76ae39 100644 --- a/src/widget/widget_state.rs +++ b/src/widget/widget_state.rs @@ -6,7 +6,7 @@ use std::sync::atomic::{AtomicBool, Ordering}; -use druid_shell::{Cursor, Region}; +use druid_shell::Cursor; use crate::bloom::Bloom; use crate::kurbo::{Insets, Point, Rect, Size}; @@ -68,8 +68,6 @@ pub struct WidgetState { // --- PASSES --- // TODO: consider using bitflags for the booleans. - // The region that needs to be repainted, relative to the widget's bounds. - pub(crate) invalid: Region, /// A flag used to track and debug missing calls to place_child. pub(crate) is_expecting_place_child_call: bool, @@ -154,7 +152,6 @@ impl WidgetState { is_expecting_place_child_call: false, paint_insets: Insets::ZERO, local_paint_rect: Rect::ZERO, - invalid: Region::EMPTY, is_portal: false, is_new: true, children_disabled_changed: false, @@ -213,15 +210,6 @@ impl WidgetState { /// /// This method is idempotent and can be called multiple times. pub(crate) fn merge_up(&mut self, child_state: &mut WidgetState) { - // TODO - Ideally, we'd want to do this in global coordinates. The problem - // is that a parent could change this widget's coordinates through place_child - // later in the same pass - let clip = self - .layout_rect() - .with_origin(Point::ORIGIN) - .inset(self.paint_insets); - let offset = child_state.layout_rect().origin().to_vec2(); - self.needs_layout |= child_state.needs_layout; self.needs_window_origin |= child_state.needs_window_origin; self.request_anim |= child_state.request_anim; From d2040513540fb56e7572e3b8ea75428eaef354ee Mon Sep 17 00:00:00 2001 From: Olivier FAURE Date: Thu, 4 Apr 2024 16:09:50 +0200 Subject: [PATCH 05/21] Remove garbage file --- ...ts__lifecycle_basic__adding_child.snap.new | 21 ------------------- 1 file changed, 21 deletions(-) delete mode 100644 src/widget/tests/snapshots/masonry__widget__tests__lifecycle_basic__adding_child.snap.new diff --git a/src/widget/tests/snapshots/masonry__widget__tests__lifecycle_basic__adding_child.snap.new b/src/widget/tests/snapshots/masonry__widget__tests__lifecycle_basic__adding_child.snap.new deleted file mode 100644 index e5fdf70d..00000000 --- a/src/widget/tests/snapshots/masonry__widget__tests__lifecycle_basic__adding_child.snap.new +++ /dev/null @@ -1,21 +0,0 @@ ---- -source: src/widget/tests/lifecycle_basic.rs -assertion_line: 53 -expression: record_new_child ---- -[ - L( - WidgetAdded, - ), - L( - BuildFocusChain, - ), - Layout( - 0.0W×20.0H, - ), - L( - Internal( - ParentWindowOrigin, - ), - ), -] From 96e8cb8c586e46b36e255372c059e8555624d3fa Mon Sep 17 00:00:00 2001 From: Olivier FAURE Date: Fri, 5 Apr 2024 18:26:30 +0200 Subject: [PATCH 06/21] Re-implement Image widget --- src/widget/image.rs | 189 ++++++++------------------------------------ src/widget/mod.rs | 16 ++-- 2 files changed, 39 insertions(+), 166 deletions(-) diff --git a/src/widget/image.rs b/src/widget/image.rs index eb5814d9..cf511275 100644 --- a/src/widget/image.rs +++ b/src/widget/image.rs @@ -5,48 +5,38 @@ //! An Image widget. //! Please consider using SVG and the SVG widget as it scales much better. -#![allow(unused)] - +use kurbo::Affine; use smallvec::SmallVec; use tracing::{trace, trace_span, Span}; +use vello::peniko::{BlendMode, Image as ImageBuf}; use vello::Scene; -use crate::kurbo::Rect; -//use crate::piet::{Image as _, ImageBuf, InterpolationMode, PietImage}; use crate::widget::{FillStrat, WidgetRef}; use crate::{ BoxConstraints, Event, EventCtx, LayoutCtx, LifeCycle, LifeCycleCtx, PaintCtx, Size, StatusChange, Widget, }; -#[cfg(FALSE)] /// A widget that renders a bitmap Image. +/// +/// The underlying image uses `Arc` for buffer data, making it cheap to clone. pub struct Image { image_data: ImageBuf, - paint_data: Option, fill: FillStrat, - interpolation: InterpolationMode, - clip_area: Option, } -//crate::declare_widget!(ImageMut, Image); +crate::declare_widget!(ImageMut, Image); -#[cfg(FALSE)] impl Image { /// Create an image drawing widget from an image buffer. /// - /// By default, the Image will scale to fit its box constraints ([`FillStrat::Fill`]) - /// and will be scaled bilinearly ([`InterpolationMode::Bilinear`]) - /// - /// The underlying `ImageBuf` uses `Arc` for buffer data, making it cheap to clone. + /// By default, the Image will scale to fit its box constraints ([`FillStrat::Fill`]). + #[inline] pub fn new(image_data: ImageBuf) -> Self { Image { image_data, - paint_data: None, fill: FillStrat::default(), - interpolation: InterpolationMode::Bilinear, - clip_area: None, } } @@ -56,25 +46,8 @@ impl Image { self.fill = mode; self } - - /// Builder-style method for specifying the interpolation strategy. - #[inline] - pub fn interpolation_mode(mut self, interpolation: InterpolationMode) -> Self { - self.interpolation = interpolation; - self - } - - /// Builder-style method for setting the area of the image that will be displayed. - /// - /// If `None`, then the whole image will be displayed. - #[inline] - pub fn clip_area(mut self, clip_area: Option) -> Self { - self.clip_area = clip_area; - self - } } -#[cfg(FALSE)] impl<'a, 'b> ImageMut<'a, 'b> { /// Modify the widget's fill strategy. #[inline] @@ -83,32 +56,14 @@ impl<'a, 'b> ImageMut<'a, 'b> { self.ctx.request_paint(); } - /// Modify the widget's interpolation mode. - #[inline] - pub fn set_interpolation_mode(&mut self, interpolation: InterpolationMode) { - self.widget.interpolation = interpolation; - self.ctx.request_paint(); - } - - /// Set the area of the image that will be displayed. - /// - /// If `None`, then the whole image will be displayed. - #[inline] - pub fn set_clip_area(&mut self, clip_area: Option) { - self.widget.clip_area = clip_area; - self.ctx.request_paint(); - } - /// Set new `ImageBuf`. #[inline] pub fn set_image_data(&mut self, image_data: ImageBuf) { self.widget.image_data = image_data; - self.widget.paint_data = None; self.ctx.request_layout(); } } -#[cfg(FALSE)] impl Widget for Image { fn on_event(&mut self, _ctx: &mut EventCtx, _event: &Event) {} @@ -121,7 +76,7 @@ impl Widget for Image { // in the size exactly. If it is unconstrained by both width and height take the size of // the image. let max = bc.max(); - let image_size = self.image_data.size(); + let image_size = Size::new(self.image_data.width as f64, self.image_data.height as f64); let size = if bc.is_width_bounded() && !bc.is_height_bounded() { let ratio = max.width / image_size.width; Size::new(max.width, ratio * image_size.height) @@ -129,54 +84,20 @@ impl Widget for Image { let ratio = max.height / image_size.height; Size::new(ratio * image_size.width, max.height) } else { - bc.constrain(self.image_data.size()) + bc.constrain(image_size) }; trace!("Computed size: {}", size); size } fn paint(&mut self, ctx: &mut PaintCtx, scene: &mut Scene) { - let offset_matrix = self.fill.affine_to_fill(ctx.size(), self.image_data.size()); + let image_size = Size::new(self.image_data.width as f64, self.image_data.height as f64); + let transform = self.fill.affine_to_fill(ctx.size(), image_size); - // The ImageData's to_piet function does not clip to the image's size - // CairoRenderContext is very like Masonry's but with some extra goodies like clip - if self.fill != FillStrat::Contain { - let clip_rect = ctx.size().to_rect(); - ctx.clip(clip_rect); - } - - let piet_image = { - let image_data = &self.image_data; - self.paint_data - .get_or_insert_with(|| image_data.to_image(ctx.render_ctx)) - }; - if piet_image.size().is_empty() { - // zero-sized image = nothing to draw - return; - } - ctx.with_save(|ctx| { - // we have to re-do this because the whole struct is moved into the closure. - let piet_image = { - let image_data = &self.image_data; - self.paint_data - .get_or_insert_with(|| image_data.to_image(ctx.render_ctx)) - }; - ctx.transform(offset_matrix); - if let Some(area) = self.clip_area { - ctx.draw_image_area( - piet_image, - area, - self.image_data.size().to_rect(), - self.interpolation, - ); - } else { - ctx.draw_image( - piet_image, - self.image_data.size().to_rect(), - self.interpolation, - ); - } - }); + let clip_rect = ctx.size().to_rect(); + scene.push_layer(BlendMode::default(), 1., Affine::IDENTITY, &clip_rect); + scene.draw_image(&self.image_data, transform); + scene.pop_layer(); } fn children(&self) -> SmallVec<[WidgetRef<'_, dyn Widget>; 16]> { @@ -188,96 +109,50 @@ impl Widget for Image { } } -#[cfg(FALSE)] -#[allow(unused)] // FIXME - remove cfg? #[cfg(not(target_arch = "wasm32"))] #[cfg(test)] mod tests { - use insta::assert_debug_snapshot; + use vello::peniko::Format; use super::*; use crate::assert_render_snapshot; - use crate::piet::ImageFormat; - use crate::testing::{widget_ids, TestHarness, TestWidgetExt}; - use crate::theme::PRIMARY_LIGHT; + use crate::testing::TestHarness; /// Painting an empty image shouldn't crash. #[test] fn empty_paint() { - let image_data = ImageBuf::empty(); - - let image_widget = - Image::new(image_data).interpolation_mode(InterpolationMode::NearestNeighbor); + // TODO - Blob::empty() function? + let image_data = ImageBuf::new(Vec::new().into(), vello::peniko::Format::Rgba8, 0, 0); + let image_widget = Image::new(image_data); let mut harness = TestHarness::create(image_widget); let _ = harness.render(); } #[test] fn tall_paint() { - let image_data = ImageBuf::from_raw( - vec![255, 255, 255, 0, 0, 0, 0, 0, 0, 255, 255, 255], - ImageFormat::Rgb, + #[rustfmt::skip] + let image_data = ImageBuf::new( + vec![ + 255, 255, 255, 255, + 0, 0, 0, 255, + 0, 0, 0, 255, + 255, 255, 255, 255, + ].into(), + Format::Rgba8, 2, 2, ); - - let image_widget = - Image::new(image_data).interpolation_mode(InterpolationMode::NearestNeighbor); + let image_widget = Image::new(image_data); let mut harness = TestHarness::create_with_size(image_widget, Size::new(40., 60.)); assert_render_snapshot!(harness, "tall_paint"); } - #[test] - fn edit_image_attributes() { - let image_data = ImageBuf::from_raw( - vec![ - 255, 255, 255, 244, 244, 244, 255, 255, 255, // row 0 - 0, 0, 0, 1, 1, 1, 0, 0, 0, // row 1 - 255, 255, 255, 244, 244, 244, 255, 255, 255, // row 2 - ], - ImageFormat::Rgb, - 3, - 3, - ); - - let render_1 = { - let image_widget = Image::new(image_data.clone()) - .fill_mode(FillStrat::Cover) - .interpolation_mode(InterpolationMode::NearestNeighbor) - .clip_area(Some(Rect::new(0.0, 0.0, 1.0, 1.0))); - - let mut harness = TestHarness::create_with_size(image_widget, Size::new(40.0, 60.0)); - - harness.render() - }; - - let render_2 = { - let image_widget = Image::new(image_data); - - let mut harness = TestHarness::create_with_size(image_widget, Size::new(40.0, 60.0)); - - harness.edit_root_widget(|mut image| { - let mut image = image.downcast::().unwrap(); - image.set_fill_mode(FillStrat::Cover); - image.set_interpolation_mode(InterpolationMode::NearestNeighbor); - image.set_clip_area(Some(Rect::new(0.0, 0.0, 1.0, 1.0))); - }); - - harness.render() - }; - - // TODO - write comparison function that creates rich diff - // and saves it in /tmp folder - See issue #18 - // We don't use assert_eq because we don't want rich assert - assert!(render_1 == render_2); - } - #[test] fn edit_image() { - let image_data = ImageBuf::from_raw(vec![255; 3 * 8 * 8], ImageFormat::Rgb, 8, 8); + let image_data = ImageBuf::new(vec![255; 4 * 8 * 8].into(), Format::Rgba8, 8, 8); let render_1 = { let image_widget = Image::new(image_data.clone()); @@ -288,7 +163,7 @@ mod tests { }; let render_2 = { - let other_image_data = ImageBuf::from_raw(vec![10; 3 * 8 * 8], ImageFormat::Rgb, 8, 8); + let other_image_data = ImageBuf::new(vec![10; 4 * 8 * 8].into(), Format::Rgba8, 8, 8); let image_widget = Image::new(other_image_data); let mut harness = TestHarness::create_with_size(image_widget, Size::new(40.0, 60.0)); diff --git a/src/widget/mod.rs b/src/widget/mod.rs index 16e64cb6..4b9d4857 100644 --- a/src/widget/mod.rs +++ b/src/widget/mod.rs @@ -27,6 +27,7 @@ mod spinner; mod split; mod textbox; +pub use self::image::Image; pub use align::Align; pub use button::Button; pub use checkbox::Checkbox; @@ -37,6 +38,12 @@ pub use scroll_bar::ScrollBar; pub use sized_box::SizedBox; pub use spinner::Spinner; pub use split::Split; +pub use widget_mut::WidgetMut; +pub use widget_pod::WidgetPod; +pub use widget_ref::WidgetRef; +pub use widget_state::WidgetState; + +pub use sized_box::BackgroundBrush; //pub use textbox::TextBox; pub use widget::StoreInWidgetMut; #[doc(hidden)] @@ -44,15 +51,6 @@ pub use widget::{Widget, WidgetId}; //#[doc(hidden)] //pub use widget_ext::WidgetExt; //pub use widget_wrapper::WidgetWrapper; -pub use widget_mut::WidgetMut; -pub use widget_pod::WidgetPod; -pub use widget_ref::WidgetRef; -pub use widget_state::WidgetState; - -#[cfg(FALSE)] -pub use self::image::Image; - -pub use sized_box::BackgroundBrush; /// Methods by which a widget can attempt to change focus state. #[derive(Debug, Clone, Copy)] From c58426cff30625d8f73eb7c853f52bcf4abd9f1d Mon Sep 17 00:00:00 2001 From: Olivier FAURE Date: Tue, 9 Apr 2024 16:54:14 +0200 Subject: [PATCH 07/21] Remove dead code Remove TextBox Remove `text` module Remove references to Piet --- examples/textbox.rs | 60 --- examples/to_do_list.rs | 89 ---- src/contexts.rs | 8 - src/paint_scene_helpers.rs | 1 - src/testing/harness.rs | 2 - src/text/attribute.rs | 381 -------------- src/text/backspace.rs | 196 -------- src/text/editable_text.rs | 522 -------------------- src/text/font_descriptor.rs | 70 --- src/text/input_component.rs | 954 ------------------------------------ src/text/input_methods.rs | 65 --- src/text/layout.rs | 424 ---------------- src/text/mod.rs | 38 -- src/text/movement.rs | 195 -------- src/text/rich_text.rs | 231 --------- src/text/storage.rs | 63 --- src/widget/mod.rs | 5 - src/widget/textbox.rs | 807 ------------------------------ src/widget/widget.rs | 4 - 19 files changed, 4115 deletions(-) delete mode 100644 examples/textbox.rs delete mode 100644 examples/to_do_list.rs delete mode 100644 src/text/attribute.rs delete mode 100644 src/text/backspace.rs delete mode 100644 src/text/editable_text.rs delete mode 100644 src/text/font_descriptor.rs delete mode 100644 src/text/input_component.rs delete mode 100644 src/text/input_methods.rs delete mode 100644 src/text/layout.rs delete mode 100644 src/text/mod.rs delete mode 100644 src/text/movement.rs delete mode 100644 src/text/rich_text.rs delete mode 100644 src/text/storage.rs delete mode 100644 src/widget/textbox.rs diff --git a/examples/textbox.rs b/examples/textbox.rs deleted file mode 100644 index df4ba1f7..00000000 --- a/examples/textbox.rs +++ /dev/null @@ -1,60 +0,0 @@ -// This software is licensed under Apache License 2.0 and distributed on an -// "as-is" basis without warranties of any kind. See the LICENSE file for -// details. - -// On Windows platform, don't show a console when opening the app. -#![windows_subsystem = "windows"] - -// TODO - rework imports - See #14 -use masonry::widget::prelude::*; -use masonry::widget::{Button, Flex, TextBox}; -use masonry::{Action, AppDelegate, AppLauncher, DelegateCtx, WindowDescription, WindowId}; - -const VERTICAL_WIDGET_SPACING: f64 = 20.0; - -struct Delegate; - -impl AppDelegate for Delegate { - fn on_action( - &mut self, - _ctx: &mut DelegateCtx, - _window_id: WindowId, - _widget_id: WidgetId, - action: Action, - ) { - match action { - Action::ButtonPressed => { - // TODO - Print textbox contents - println!("Hello"); - } - _ => {} - } - } -} - -pub fn main() { - // describe the main window - let main_window = WindowDescription::new(build_root_widget()) - .title("Hello World!") - .window_size((400.0, 400.0)); - - // start the application. Here we pass in the application state. - AppLauncher::with_window(main_window) - .with_delegate(Delegate) - .log_to_console() - .launch() - .expect("Failed to launch application"); -} - -fn build_root_widget() -> impl Widget { - let label = TextBox::new("").with_placeholder("Some text"); - - // a button that says "hello" - let button = Button::new("Say hello"); - - // arrange the two widgets vertically, with some padding - Flex::column() - .with_child(label) - .with_spacer(VERTICAL_WIDGET_SPACING) - .with_child(button) -} diff --git a/examples/to_do_list.rs b/examples/to_do_list.rs deleted file mode 100644 index 95b85683..00000000 --- a/examples/to_do_list.rs +++ /dev/null @@ -1,89 +0,0 @@ -// This software is licensed under Apache License 2.0 and distributed on an -// "as-is" basis without warranties of any kind. See the LICENSE file for -// details. - -#![windows_subsystem = "windows"] - -use masonry::widget::{ - Button, CrossAxisAlignment, Flex, Label, Portal, SizedBox, TextBox, WidgetMut, -}; -use masonry::{ - Action, AppDelegate, AppLauncher, Color, DelegateCtx, WidgetId, WindowDescription, WindowId, -}; - -struct Delegate { - next_task: String, -} - -impl AppDelegate for Delegate { - fn on_action( - &mut self, - ctx: &mut DelegateCtx, - _window_id: WindowId, - _widget_id: WidgetId, - action: Action, - ) { - match action { - Action::ButtonPressed | Action::TextEntered(_) => { - let mut root: WidgetMut> = ctx.get_root(); - if !self.next_task.is_empty() { - let mut flex = root.child_mut(); - flex.child_mut(2) - .unwrap() - .downcast::() - .unwrap() - .child_mut() - .unwrap() - .downcast::() - .unwrap() - .add_child(Label::new(self.next_task.clone())); - } - } - Action::TextChanged(new_text) => { - self.next_task = new_text; - } - _ => {} - } - } -} - -fn main() { - const GAP_SIZE: f64 = 4.0; - const LIGHT_GRAY: Color = Color::rgb8(0x71, 0x71, 0x71); - // The main button with some space below, all inside a scrollable area. - let root_widget = Portal::new( - Flex::column() - .with_child( - SizedBox::new( - Flex::row() - .with_child(Button::new("Add task")) - .with_spacer(5.0) - .with_flex_child(TextBox::new(""), 1.0), - ) - .border(LIGHT_GRAY, GAP_SIZE), - ) - .with_spacer(GAP_SIZE) - .with_child( - SizedBox::new( - Flex::column() - .cross_axis_alignment(CrossAxisAlignment::Start) - .with_child(Label::new("List items:")), - ) - .expand_width() - .border(LIGHT_GRAY, GAP_SIZE), - ), - ) - .constrain_horizontal(true); - - let main_window = WindowDescription::new(root_widget) - .title("To-do list") - .window_size((400.0, 400.0)); - - AppLauncher::with_window(main_window) - .with_delegate(Delegate { - next_task: String::new(), - }) - .log_to_console() - .launch() - .expect("Failed to launch application"); -} diff --git a/src/contexts.rs b/src/contexts.rs index 1136c1ed..7a37cfe2 100644 --- a/src/contexts.rs +++ b/src/contexts.rs @@ -8,7 +8,6 @@ use std::any::Any; use std::collections::{HashMap, VecDeque}; use std::time::Duration; -use druid_shell::piet::PietText; use druid_shell::text::Event as ImeInvalidation; use druid_shell::{Cursor, TimerToken, WindowHandle}; use tracing::{trace, warn}; @@ -53,7 +52,6 @@ pub(crate) struct GlobalPassCtx<'a> { pub(crate) mock_timer_queue: Option<&'a mut MockTimerQueue>, pub(crate) window_id: WindowId, pub(crate) window: &'a WindowHandle, - pub(crate) text: PietText, /// The id of the widget that currently has focus. pub(crate) focus_widget: Option, } @@ -135,11 +133,6 @@ impl_context_method!( self.global_state.window_id } - /// Get an object which can create text layouts. - pub fn text(&mut self) -> &mut PietText { - &mut self.global_state.text - } - /// Skip iterating over the given child. /// /// Normally, container widgets are supposed to iterate over each of their @@ -834,7 +827,6 @@ impl<'a> GlobalPassCtx<'a> { window, window_id, focus_widget, - text: window.text(), } } diff --git a/src/paint_scene_helpers.rs b/src/paint_scene_helpers.rs index 9021561a..ad4e9f88 100644 --- a/src/paint_scene_helpers.rs +++ b/src/paint_scene_helpers.rs @@ -29,7 +29,6 @@ pub fn stroke<'b>( ); } -// Note: copied from piet #[allow(unused)] impl UnitPoint { /// `(0.0, 0.0)` diff --git a/src/testing/harness.rs b/src/testing/harness.rs index 5642a6df..7cc540da 100644 --- a/src/testing/harness.rs +++ b/src/testing/harness.rs @@ -154,8 +154,6 @@ macro_rules! assert_render_snapshot { } // TODO - merge -/// All of the state except for the `Piet` (render context). We need to pass -/// that in to get around some lifetime issues. struct MockAppRoot { window: WindowRoot, command_queue: CommandQueue, diff --git a/src/text/attribute.rs b/src/text/attribute.rs deleted file mode 100644 index 9dfef727..00000000 --- a/src/text/attribute.rs +++ /dev/null @@ -1,381 +0,0 @@ -// This software is licensed under Apache License 2.0 and distributed on an -// "as-is" basis without warranties of any kind. See the LICENSE file for -// details. - -//! Text attributes and spans. - -use std::ops::Range; - -use super::FontDescriptor; -use crate::piet::{Color, FontFamily, FontStyle, FontWeight, TextAttribute as PietAttr}; - -// TODO - Should also hold an associated Command, maybe. -/// A clickable range of text -#[derive(Debug, Clone)] -pub struct Link { - /// The range of text for the link. - pub range: Range, -} - -/// A collection of spans of attributes of various kinds. -#[derive(Debug, Clone, Default)] -pub struct AttributeSpans { - family: SpanSet, - size: SpanSet, - weight: SpanSet, - fg_color: SpanSet, - style: SpanSet, - underline: SpanSet, - font_descriptor: SpanSet, -} - -/// A set of spans for a given attribute. -/// -/// Invariant: the spans are sorted and non-overlapping. -#[derive(Debug, Clone)] -struct SpanSet { - spans: Vec>, -} - -/// An attribute and a range. -/// -/// This is used to represent text attributes of various kinds, -/// with the range representing a region of some text buffer. -#[derive(Debug, Clone, PartialEq)] -struct Span { - range: Range, - attr: T, -} - -/// Attributes that can be applied to text. -/// -/// Where possible, attributes are [`KeyOrValue`] types; this means you -/// can use items defined in the [`theme`] *or* concrete types, where appropriate. -/// -/// The easiest way to construct these attributes is via the various constructor -/// methods, such as [`Attribute::size`] or [`Attribute::text_color`]. -/// -/// # Examples -/// -/// ```no_run -/// use masonry::text::Attribute; -/// use masonry::{theme, Color}; -/// -/// let font = Attribute::font_descriptor(theme::UI_FONT); -/// let font_size = Attribute::size(32.0); -/// let explicit_color = Attribute::text_color(Color::BLACK); -/// let theme_color = Attribute::text_color(theme::SELECTION_TEXT_COLOR); -/// ``` -/// -/// [`KeyOrValue`]: ../enum.KeyOrValue.html -/// [`theme`]: ../theme -/// [`Attribute::size`]: #method.size -/// [`Attribute::text_color`]: #method.text_color -#[derive(Debug, Clone)] -pub enum Attribute { - /// The font family. - FontFamily(FontFamily), - /// The font size, in points. - FontSize(f64), - /// The [`FontWeight`](struct.FontWeight.html). - Weight(FontWeight), - /// The foreground color of the text. - TextColor(Color), - /// The [`FontStyle`]; either regular or italic. - /// - /// [`FontStyle`]: enum.FontStyle.html - Style(FontStyle), - /// Underline. - Underline(bool), - /// A [`FontDescriptor`](struct.FontDescriptor.html). - Descriptor(FontDescriptor), -} - -impl Link { - /// Create a new `Link`. - pub fn new(range: Range) -> Self { - Self { range } - } - - /// Get this `Link`'s range. - pub fn range(&self) -> Range { - self.range.clone() - } -} - -impl AttributeSpans { - /// Create a new, empty `AttributeSpans`. - pub fn new() -> Self { - Default::default() - } - - /// Add a new [`Attribute`] over the provided [`Range`]. - pub fn add(&mut self, range: Range, attr: Attribute) { - match attr { - Attribute::FontFamily(attr) => self.family.add(Span::new(range, attr)), - Attribute::FontSize(attr) => self.size.add(Span::new(range, attr)), - Attribute::Weight(attr) => self.weight.add(Span::new(range, attr)), - Attribute::TextColor(attr) => self.fg_color.add(Span::new(range, attr)), - Attribute::Style(attr) => self.style.add(Span::new(range, attr)), - Attribute::Underline(attr) => self.underline.add(Span::new(range, attr)), - Attribute::Descriptor(attr) => self.font_descriptor.add(Span::new(range, attr)), - } - } - - pub(crate) fn to_piet_attrs(&self) -> Vec<(Range, PietAttr)> { - let mut items = Vec::new(); - for Span { range, attr } in self.font_descriptor.iter() { - items.push((range.clone(), PietAttr::FontFamily(attr.family.clone()))); - items.push((range.clone(), PietAttr::FontSize(attr.size))); - items.push((range.clone(), PietAttr::Weight(attr.weight))); - items.push((range.clone(), PietAttr::Style(attr.style))); - } - - items.extend( - self.family - .iter() - .map(|s| (s.range.clone(), PietAttr::FontFamily(s.attr.clone()))), - ); - items.extend( - self.size - .iter() - .map(|s| (s.range.clone(), PietAttr::FontSize(s.attr))), - ); - items.extend( - self.weight - .iter() - .map(|s| (s.range.clone(), PietAttr::Weight(s.attr))), - ); - items.extend( - self.fg_color - .iter() - .map(|s| (s.range.clone(), PietAttr::TextColor(s.attr))), - ); - items.extend( - self.style - .iter() - .map(|s| (s.range.clone(), PietAttr::Style(s.attr))), - ); - items.extend( - self.underline - .iter() - .map(|s| (s.range.clone(), PietAttr::Underline(s.attr))), - ); - - // sort by ascending start order; this is a stable sort - // so items that come from FontDescriptor will stay at the front - items.sort_by(|a, b| a.0.start.cmp(&b.0.start)); - items - } -} - -impl SpanSet { - fn iter(&self) -> impl Iterator> { - self.spans.iter() - } - - /// Add a `Span` to this `SpanSet`. - /// - /// Spans can be added in any order. existing spans will be updated - /// as required. - fn add(&mut self, span: Span) { - let span_start = span.range.start; - let span_end = span.range.end; - let insert_idx = self - .spans - .iter() - .position(|x| x.range.start >= span.range.start) - .unwrap_or_else(|| self.spans.len()); - - // if we are inserting into the middle of an existing span we need - // to add the trailing portion back afterwards. - let mut prev_remainder = None; - - if insert_idx > 0 { - // truncate the preceding item, if necessary - let before = self.spans.get_mut(insert_idx - 1).unwrap(); - if before.range.end > span_end { - let mut remainder = before.clone(); - remainder.range.start = span_end; - prev_remainder = Some(remainder); - } - before.range.end = before.range.end.min(span_start); - } - - self.spans.insert(insert_idx, span); - if let Some(remainder) = prev_remainder.take() { - self.spans.insert(insert_idx + 1, remainder); - } - - // clip any existing spans as needed - for after in self.spans.iter_mut().skip(insert_idx + 1) { - after.range.start = after.range.start.max(span_end); - after.range.end = after.range.end.max(span_end); - } - - // remove any spans that have been overwritten - self.spans.retain(|span| !span.is_empty()); - } - - /// Edit the spans, inserting empty space into the changed region if needed. - /// - /// This is used to keep the spans up to date as edits occur in the buffer. - /// - /// `changed` is the range of the string that has been replaced; this can - /// be an empty range (eg, 10..10) for the insertion case. - /// - /// `new_len` is the length of the inserted text. - //TODO: we could be smarter here about just extending the existing spans - //as requred for insertions in the interior of a span. - //TODO: this isn't currently used; it should be used if we use spans with - //some editable type. - // the branches are much more readable without sharing code - #[allow(dead_code, clippy::branches_sharing_code)] - fn edit(&mut self, changed: Range, new_len: usize) { - let old_len = changed.len(); - let mut to_insert = None; - - for (idx, Span { range, attr }) in self.spans.iter_mut().enumerate() { - if range.end <= changed.start { - continue; - } else if range.start < changed.start { - // we start before but end inside; truncate end - if range.end <= changed.end { - range.end = changed.start; - // we start before and end after; this is a special case, - // we'll need to add a new span - } else { - let new_start = changed.start + new_len; - let new_end = range.end - old_len + new_len; - let new_span = Span::new(new_start..new_end, attr.clone()); - to_insert = Some((idx + 1, new_span)); - range.end = changed.start; - } - // start inside - } else if range.start < changed.end { - range.start = changed.start + new_len; - // end inside; collapse - if range.end <= changed.end { - range.end = changed.start + new_len; - // end outside: adjust by length delta - } else { - range.end -= old_len; - range.end += new_len; - } - // whole range is after: - } else { - range.start -= old_len; - range.start += new_len; - range.end -= old_len; - range.end += new_len; - } - } - if let Some((idx, span)) = to_insert.take() { - self.spans.insert(idx, span); - } - - self.spans.retain(|span| !span.is_empty()); - } -} - -impl Span { - fn new(range: Range, attr: T) -> Self { - Span { range, attr } - } - - fn is_empty(&self) -> bool { - self.range.end <= self.range.start - } -} - -impl Attribute { - /// Create a new font size attribute. - pub fn size(size: impl Into) -> Self { - Attribute::FontSize(size.into()) - } - - /// Create a new forground color attribute. - pub fn text_color(color: impl Into) -> Self { - Attribute::TextColor(color.into()) - } - - /// Create a new font family attribute. - pub fn font_family(family: FontFamily) -> Self { - Attribute::FontFamily(family) - } - - /// Create a new `FontWeight` attribute. - pub fn weight(weight: FontWeight) -> Self { - Attribute::Weight(weight) - } - - /// Create a new `FontStyle` attribute. - pub fn style(style: FontStyle) -> Self { - Attribute::Style(style) - } - - /// Create a new underline attribute. - pub fn underline(underline: bool) -> Self { - Attribute::Underline(underline) - } - - /// Create a new `FontDescriptor` attribute. - pub fn font_descriptor(font: impl Into) -> Self { - Attribute::Descriptor(font.into()) - } -} - -impl Default for SpanSet { - fn default() -> Self { - SpanSet { spans: Vec::new() } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn smoke_test_spans() { - let mut spans = SpanSet::::default(); - spans.add(Span::new(2..10, 1)); - spans.add(Span::new(3..6, 2)); - assert_eq!( - &spans.spans, - &vec![Span::new(2..3, 1), Span::new(3..6, 2), Span::new(6..10, 1)] - ); - - spans.add(Span::new(0..12, 3)); - assert_eq!(&spans.spans, &vec![Span::new(0..12, 3)]); - spans.add(Span::new(5..20, 4)); - assert_eq!(&spans.spans, &vec![Span::new(0..5, 3), Span::new(5..20, 4)]); - } - - #[test] - fn edit_spans() { - let mut spans = SpanSet::::default(); - spans.add(Span::new(0..2, 1)); - spans.add(Span::new(8..12, 2)); - spans.add(Span::new(13..16, 3)); - spans.add(Span::new(20..22, 4)); - - let mut deletion = spans.clone(); - deletion.edit(6..14, 0); - assert_eq!( - &deletion.spans, - &vec![Span::new(0..2, 1), Span::new(6..8, 3), Span::new(12..14, 4)] - ); - - spans.edit(10..10, 2); - assert_eq!( - &spans.spans, - &vec![ - Span::new(0..2, 1), - Span::new(8..10, 2), - Span::new(12..14, 2), - Span::new(15..18, 3), - Span::new(22..24, 4), - ] - ); - } -} diff --git a/src/text/backspace.rs b/src/text/backspace.rs deleted file mode 100644 index d688a430..00000000 --- a/src/text/backspace.rs +++ /dev/null @@ -1,196 +0,0 @@ -// This software is licensed under Apache License 2.0 and distributed on an -// "as-is" basis without warranties of any kind. See the LICENSE file for -// details. - -//! Calc start of a backspace delete interval - -use xi_unicode::*; - -use crate::text::{EditableText, EditableTextCursor, Selection}; - -#[allow(clippy::cognitive_complexity)] -fn backspace_offset(text: &impl EditableText, start: usize) -> usize { - #[derive(PartialEq)] - enum State { - Start, - Lf, - BeforeKeycap, - BeforeVsAndKeycap, - BeforeEmojiModifier, - BeforeVsAndEmojiModifier, - BeforeVs, - BeforeEmoji, - BeforeZwj, - BeforeVsAndZwj, - OddNumberedRis, - EvenNumberedRis, - InTagSequence, - Finished, - } - let mut state = State::Start; - - let mut delete_code_point_count = 0; - let mut last_seen_vs_code_point_count = 0; - let mut cursor = text - .cursor(start) - .expect("Backspace must begin at a valid codepoint boundary."); - - while state != State::Finished && cursor.pos() > 0 { - let code_point = cursor.prev_codepoint().unwrap_or('0'); - - match state { - State::Start => { - delete_code_point_count = 1; - if code_point == '\n' { - state = State::Lf; - } else if is_variation_selector(code_point) { - state = State::BeforeVs; - } else if code_point.is_regional_indicator_symbol() { - state = State::OddNumberedRis; - } else if code_point.is_emoji_modifier() { - state = State::BeforeEmojiModifier; - } else if code_point.is_emoji_combining_enclosing_keycap() { - state = State::BeforeKeycap; - } else if code_point.is_emoji() { - state = State::BeforeEmoji; - } else if code_point.is_emoji_cancel_tag() { - state = State::InTagSequence; - } else { - state = State::Finished; - } - } - State::Lf => { - if code_point == '\r' { - delete_code_point_count += 1; - } - state = State::Finished; - } - State::OddNumberedRis => { - if code_point.is_regional_indicator_symbol() { - delete_code_point_count += 1; - state = State::EvenNumberedRis - } else { - state = State::Finished - } - } - State::EvenNumberedRis => { - if code_point.is_regional_indicator_symbol() { - delete_code_point_count -= 1; - state = State::OddNumberedRis; - } else { - state = State::Finished; - } - } - State::BeforeKeycap => { - if is_variation_selector(code_point) { - last_seen_vs_code_point_count = 1; - state = State::BeforeVsAndKeycap; - } else { - if is_keycap_base(code_point) { - delete_code_point_count += 1; - } - state = State::Finished; - } - } - State::BeforeVsAndKeycap => { - if is_keycap_base(code_point) { - delete_code_point_count += last_seen_vs_code_point_count + 1; - } - state = State::Finished; - } - State::BeforeEmojiModifier => { - if is_variation_selector(code_point) { - last_seen_vs_code_point_count = 1; - state = State::BeforeVsAndEmojiModifier; - } else { - if code_point.is_emoji_modifier_base() { - delete_code_point_count += 1; - } - state = State::Finished; - } - } - State::BeforeVsAndEmojiModifier => { - if code_point.is_emoji_modifier_base() { - delete_code_point_count += last_seen_vs_code_point_count + 1; - } - state = State::Finished; - } - State::BeforeVs => { - if code_point.is_emoji() { - delete_code_point_count += 1; - state = State::BeforeEmoji; - } else { - if !is_variation_selector(code_point) { - //TODO: UCharacter.getCombiningClass(codePoint) == 0 - delete_code_point_count += 1; - } - state = State::Finished; - } - } - State::BeforeEmoji => { - if code_point.is_zwj() { - state = State::BeforeZwj; - } else { - state = State::Finished; - } - } - State::BeforeZwj => { - if code_point.is_emoji() { - delete_code_point_count += 2; - state = if code_point.is_emoji_modifier() { - State::BeforeEmojiModifier - } else { - State::BeforeEmoji - }; - } else if is_variation_selector(code_point) { - last_seen_vs_code_point_count = 1; - state = State::BeforeVsAndZwj; - } else { - state = State::Finished; - } - } - State::BeforeVsAndZwj => { - if code_point.is_emoji() { - delete_code_point_count += last_seen_vs_code_point_count + 2; - last_seen_vs_code_point_count = 0; - state = State::BeforeEmoji; - } else { - state = State::Finished; - } - } - State::InTagSequence => { - if code_point.is_tag_spec_char() { - delete_code_point_count += 1; - } else if code_point.is_emoji() { - delete_code_point_count += 1; - state = State::Finished; - } else { - delete_code_point_count = 1; - state = State::Finished; - } - } - State::Finished => { - break; - } - } - } - - cursor.set(start); - for _ in 0..delete_code_point_count { - let _ = cursor.prev_codepoint(); - } - cursor.pos() -} - -/// Calculate resulting offset for a backwards delete. -/// -/// This involves complicated logic to handle various special cases that -/// are unique to backspace. -#[allow(clippy::trivially_copy_pass_by_ref)] -pub fn offset_for_delete_backwards(region: &Selection, text: &impl EditableText) -> usize { - if !region.is_caret() { - region.min() - } else { - backspace_offset(text, region.active) - } -} diff --git a/src/text/editable_text.rs b/src/text/editable_text.rs deleted file mode 100644 index 98088615..00000000 --- a/src/text/editable_text.rs +++ /dev/null @@ -1,522 +0,0 @@ -// This software is licensed under Apache License 2.0 and distributed on an -// "as-is" basis without warranties of any kind. See the LICENSE file for -// details. - -//! Traits for text editing and a basic String implementation. - -use std::borrow::Cow; -use std::ops::{Deref, Range}; -use std::sync::Arc; - -use unicode_segmentation::{GraphemeCursor, UnicodeSegmentation}; - -/// An EditableText trait. -pub trait EditableText: Sized { - // TODO: would be nice to have something like - // type Cursor: EditableTextCursor; - - /// Create a cursor with a reference to the text and a offset position. - /// - /// Returns None if the position isn't a codepoint boundary. - fn cursor(&self, position: usize) -> Option; - - /// Replace range with new text. - /// Can panic if supplied an invalid range. - // TODO: make this generic over Self - fn edit(&mut self, range: Range, new: impl Into); - - /// Get slice of text at range. - fn slice(&self, range: Range) -> Option>; - - /// Get length of text (in bytes). - fn len(&self) -> usize; - - /// Get the previous word offset from the given offset, if it exists. - fn prev_word_offset(&self, offset: usize) -> Option; - - /// Get the next word offset from the given offset, if it exists. - fn next_word_offset(&self, offset: usize) -> Option; - - /// Get the next grapheme offset from the given offset, if it exists. - fn prev_grapheme_offset(&self, offset: usize) -> Option; - - /// Get the next grapheme offset from the given offset, if it exists. - fn next_grapheme_offset(&self, offset: usize) -> Option; - - /// Get the previous codepoint offset from the given offset, if it exists. - fn prev_codepoint_offset(&self, offset: usize) -> Option; - - /// Get the next codepoint offset from the given offset, if it exists. - fn next_codepoint_offset(&self, offset: usize) -> Option; - - /// Get the preceding line break offset from the given offset - fn preceding_line_break(&self, offset: usize) -> usize; - - /// Get the next line break offset from the given offset - fn next_line_break(&self, offset: usize) -> usize; - - /// Returns `true` if this text has 0 length. - fn is_empty(&self) -> bool; - - /// Construct an instance of this type from a `&str`. - fn from_str(s: &str) -> Self; -} - -impl EditableText for String { - fn cursor<'a>(&self, position: usize) -> Option { - let new_cursor = StringCursor { - text: self, - position, - }; - - if new_cursor.is_boundary() { - Some(new_cursor) - } else { - None - } - } - - fn edit(&mut self, range: Range, new: impl Into) { - self.replace_range(range, &new.into()); - } - - fn slice(&self, range: Range) -> Option> { - self.get(range).map(Cow::from) - } - - fn len(&self) -> usize { - self.len() - } - - fn prev_grapheme_offset(&self, from: usize) -> Option { - let mut c = GraphemeCursor::new(from, self.len(), true); - c.prev_boundary(self, 0).unwrap() - } - - fn next_grapheme_offset(&self, from: usize) -> Option { - let mut c = GraphemeCursor::new(from, self.len(), true); - c.next_boundary(self, 0).unwrap() - } - - fn prev_codepoint_offset(&self, from: usize) -> Option { - let mut c = self.cursor(from).unwrap(); - c.prev() - } - - fn next_codepoint_offset(&self, from: usize) -> Option { - let mut c = self.cursor(from).unwrap(); - if c.next().is_some() { - Some(c.pos()) - } else { - None - } - } - - fn prev_word_offset(&self, from: usize) -> Option { - let mut offset = from; - let mut passed_alphanumeric = false; - for prev_grapheme in self.get(0..from)?.graphemes(true).rev() { - let is_alphanumeric = prev_grapheme.chars().next()?.is_alphanumeric(); - if is_alphanumeric { - passed_alphanumeric = true; - } else if passed_alphanumeric { - return Some(offset); - } - offset -= prev_grapheme.len(); - } - None - } - - fn next_word_offset(&self, from: usize) -> Option { - let mut offset = from; - let mut passed_alphanumeric = false; - for next_grapheme in self.get(from..)?.graphemes(true) { - let is_alphanumeric = next_grapheme.chars().next()?.is_alphanumeric(); - if is_alphanumeric { - passed_alphanumeric = true; - } else if passed_alphanumeric { - return Some(offset); - } - offset += next_grapheme.len(); - } - Some(self.len()) - } - - fn is_empty(&self) -> bool { - self.is_empty() - } - - fn from_str(s: &str) -> Self { - s.to_string() - } - - fn preceding_line_break(&self, from: usize) -> usize { - let mut offset = from; - - for byte in self.get(0..from).unwrap_or("").bytes().rev() { - if byte == 0x0a { - return offset; - } - offset -= 1; - } - - 0 - } - - fn next_line_break(&self, from: usize) -> usize { - let mut offset = from; - - for char in self.get(from..).unwrap_or("").bytes() { - if char == 0x0a { - return offset; - } - offset += 1; - } - - self.len() - } -} - -impl EditableText for Arc { - fn cursor(&self, position: usize) -> Option { - ::cursor(self, position) - } - fn edit(&mut self, range: Range, new: impl Into) { - let new = new.into(); - if !range.is_empty() || !new.is_empty() { - Arc::make_mut(self).edit(range, new) - } - } - fn slice(&self, range: Range) -> Option> { - Some(Cow::Borrowed(&self[range])) - } - fn len(&self) -> usize { - self.deref().len() - } - fn prev_word_offset(&self, offset: usize) -> Option { - self.deref().prev_word_offset(offset) - } - fn next_word_offset(&self, offset: usize) -> Option { - self.deref().next_word_offset(offset) - } - fn prev_grapheme_offset(&self, offset: usize) -> Option { - self.deref().prev_grapheme_offset(offset) - } - fn next_grapheme_offset(&self, offset: usize) -> Option { - self.deref().next_grapheme_offset(offset) - } - fn prev_codepoint_offset(&self, offset: usize) -> Option { - self.deref().prev_codepoint_offset(offset) - } - fn next_codepoint_offset(&self, offset: usize) -> Option { - self.deref().next_codepoint_offset(offset) - } - fn preceding_line_break(&self, offset: usize) -> usize { - self.deref().preceding_line_break(offset) - } - fn next_line_break(&self, offset: usize) -> usize { - self.deref().next_line_break(offset) - } - fn is_empty(&self) -> bool { - self.deref().is_empty() - } - fn from_str(s: &str) -> Self { - Arc::new(s.to_owned()) - } -} - -/// A cursor with convenience functions for moving through EditableText. -pub trait EditableTextCursor { - /// Set cursor position. - fn set(&mut self, position: usize); - - /// Get cursor position. - fn pos(&self) -> usize; - - /// Check if cursor position is at a codepoint boundary. - fn is_boundary(&self) -> bool; - - /// Move cursor to previous codepoint boundary, if it exists. - /// Returns previous codepoint as usize offset. - fn prev(&mut self) -> Option; - - /// Move cursor to next codepoint boundary, if it exists. - /// Returns current codepoint as usize offset. - fn next(&mut self) -> Option; - - /// Get the next codepoint after the cursor position, without advancing - /// the cursor. - fn peek_next_codepoint(&self) -> Option; - - /// Return codepoint preceding cursor offset and move cursor backward. - fn prev_codepoint(&mut self) -> Option; - - /// Return codepoint at cursor offset and move cursor forward. - fn next_codepoint(&mut self) -> Option; - - /// Return current offset if it's a boundary, else next. - fn at_or_next(&mut self) -> Option; - - /// Return current offset if it's a boundary, else previous. - fn at_or_prev(&mut self) -> Option; -} - -/// A cursor type that implements EditableTextCursor for String -#[derive(Debug)] -pub struct StringCursor<'a> { - text: &'a str, - position: usize, -} - -impl<'a> EditableTextCursor<&'a String> for StringCursor<'a> { - fn set(&mut self, position: usize) { - self.position = position; - } - - fn pos(&self) -> usize { - self.position - } - - fn is_boundary(&self) -> bool { - self.text.is_char_boundary(self.position) - } - - fn prev(&mut self) -> Option { - let current_pos = self.pos(); - - if current_pos == 0 { - None - } else { - let mut len = 1; - while !self.text.is_char_boundary(current_pos - len) { - len += 1; - } - self.set(self.pos() - len); - Some(self.pos()) - } - } - - fn next(&mut self) -> Option { - let current_pos = self.pos(); - - if current_pos == self.text.len() { - None - } else { - let b = self.text.as_bytes()[current_pos]; - self.set(current_pos + len_utf8_from_first_byte(b)); - Some(current_pos) - } - } - - fn peek_next_codepoint(&self) -> Option { - self.text[self.pos()..].chars().next() - } - - fn prev_codepoint(&mut self) -> Option { - if let Some(prev) = self.prev() { - self.text[prev..].chars().next() - } else { - None - } - } - - fn next_codepoint(&mut self) -> Option { - let current_index = self.pos(); - if self.next().is_some() { - self.text[current_index..].chars().next() - } else { - None - } - } - - fn at_or_next(&mut self) -> Option { - if self.is_boundary() { - Some(self.pos()) - } else { - self.next() - } - } - - fn at_or_prev(&mut self) -> Option { - if self.is_boundary() { - Some(self.pos()) - } else { - self.prev() - } - } -} - -pub fn len_utf8_from_first_byte(b: u8) -> usize { - match b { - b if b < 0x80 => 1, - b if b < 0xe0 => 2, - b if b < 0xf0 => 3, - _ => 4, - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn replace() { - let mut a = String::from("hello world"); - a.edit(1..9, "era"); - assert_eq!("herald", a); - } - - #[test] - fn prev_codepoint_offset() { - let a = String::from("a\u{00A1}\u{4E00}\u{1F4A9}"); - assert_eq!(Some(6), a.prev_codepoint_offset(10)); - assert_eq!(Some(3), a.prev_codepoint_offset(6)); - assert_eq!(Some(1), a.prev_codepoint_offset(3)); - assert_eq!(Some(0), a.prev_codepoint_offset(1)); - assert_eq!(None, a.prev_codepoint_offset(0)); - let b = a.slice(1..10).unwrap().to_string(); - assert_eq!(Some(5), b.prev_codepoint_offset(9)); - assert_eq!(Some(2), b.prev_codepoint_offset(5)); - assert_eq!(Some(0), b.prev_codepoint_offset(2)); - assert_eq!(None, b.prev_codepoint_offset(0)); - } - - #[test] - fn next_codepoint_offset() { - let a = String::from("a\u{00A1}\u{4E00}\u{1F4A9}"); - assert_eq!(Some(10), a.next_codepoint_offset(6)); - assert_eq!(Some(6), a.next_codepoint_offset(3)); - assert_eq!(Some(3), a.next_codepoint_offset(1)); - assert_eq!(Some(1), a.next_codepoint_offset(0)); - assert_eq!(None, a.next_codepoint_offset(10)); - let b = a.slice(1..10).unwrap().to_string(); - assert_eq!(Some(9), b.next_codepoint_offset(5)); - assert_eq!(Some(5), b.next_codepoint_offset(2)); - assert_eq!(Some(2), b.next_codepoint_offset(0)); - assert_eq!(None, b.next_codepoint_offset(9)); - } - - #[test] - fn prev_next() { - let input = String::from("abc"); - let mut cursor = input.cursor(0).unwrap(); - assert_eq!(cursor.next(), Some(0)); - assert_eq!(cursor.next(), Some(1)); - assert_eq!(cursor.prev(), Some(1)); - assert_eq!(cursor.next(), Some(1)); - assert_eq!(cursor.next(), Some(2)); - } - - #[test] - fn peek_next_codepoint() { - let inp = String::from("$¢€£💶"); - let mut cursor = inp.cursor(0).unwrap(); - assert_eq!(cursor.peek_next_codepoint(), Some('$')); - assert_eq!(cursor.peek_next_codepoint(), Some('$')); - assert_eq!(cursor.next_codepoint(), Some('$')); - assert_eq!(cursor.peek_next_codepoint(), Some('¢')); - assert_eq!(cursor.prev_codepoint(), Some('$')); - assert_eq!(cursor.peek_next_codepoint(), Some('$')); - assert_eq!(cursor.next_codepoint(), Some('$')); - assert_eq!(cursor.next_codepoint(), Some('¢')); - assert_eq!(cursor.peek_next_codepoint(), Some('€')); - assert_eq!(cursor.next_codepoint(), Some('€')); - assert_eq!(cursor.peek_next_codepoint(), Some('£')); - assert_eq!(cursor.next_codepoint(), Some('£')); - assert_eq!(cursor.peek_next_codepoint(), Some('💶')); - assert_eq!(cursor.next_codepoint(), Some('💶')); - assert_eq!(cursor.peek_next_codepoint(), None); - assert_eq!(cursor.next_codepoint(), None); - assert_eq!(cursor.peek_next_codepoint(), None); - } - - #[test] - fn prev_grapheme_offset() { - // A with ring, hangul, regional indicator "US" - let a = String::from("A\u{030a}\u{110b}\u{1161}\u{1f1fa}\u{1f1f8}"); - assert_eq!(Some(9), a.prev_grapheme_offset(17)); - assert_eq!(Some(3), a.prev_grapheme_offset(9)); - assert_eq!(Some(0), a.prev_grapheme_offset(3)); - assert_eq!(None, a.prev_grapheme_offset(0)); - } - - #[test] - fn next_grapheme_offset() { - // A with ring, hangul, regional indicator "US" - let a = String::from("A\u{030a}\u{110b}\u{1161}\u{1f1fa}\u{1f1f8}"); - assert_eq!(Some(3), a.next_grapheme_offset(0)); - assert_eq!(Some(9), a.next_grapheme_offset(3)); - assert_eq!(Some(17), a.next_grapheme_offset(9)); - assert_eq!(None, a.next_grapheme_offset(17)); - } - - #[test] - fn prev_word_offset() { - let a = String::from("Technically a word: ৬藏A\u{030a}\u{110b}\u{1161}"); - assert_eq!(Some(20), a.prev_word_offset(35)); - assert_eq!(Some(20), a.prev_word_offset(27)); - assert_eq!(Some(20), a.prev_word_offset(23)); - assert_eq!(Some(14), a.prev_word_offset(20)); - assert_eq!(Some(14), a.prev_word_offset(19)); - assert_eq!(Some(12), a.prev_word_offset(13)); - assert_eq!(None, a.prev_word_offset(12)); - assert_eq!(None, a.prev_word_offset(11)); - assert_eq!(None, a.prev_word_offset(0)); - } - - #[test] - fn next_word_offset() { - let a = String::from("Technically a word: ৬藏A\u{030a}\u{110b}\u{1161}"); - assert_eq!(Some(11), a.next_word_offset(0)); - assert_eq!(Some(11), a.next_word_offset(7)); - assert_eq!(Some(13), a.next_word_offset(11)); - assert_eq!(Some(18), a.next_word_offset(14)); - assert_eq!(Some(35), a.next_word_offset(18)); - assert_eq!(Some(35), a.next_word_offset(19)); - assert_eq!(Some(35), a.next_word_offset(20)); - assert_eq!(Some(35), a.next_word_offset(26)); - assert_eq!(Some(35), a.next_word_offset(35)); - } - - #[test] - fn preceding_line_break() { - let a = String::from("Technically\na word:\n ৬藏A\u{030a}\n\u{110b}\u{1161}"); - assert_eq!(0, a.preceding_line_break(0)); - assert_eq!(0, a.preceding_line_break(11)); - assert_eq!(12, a.preceding_line_break(12)); - assert_eq!(12, a.preceding_line_break(13)); - assert_eq!(20, a.preceding_line_break(21)); - assert_eq!(31, a.preceding_line_break(31)); - assert_eq!(31, a.preceding_line_break(34)); - - let b = String::from("Technically a word: ৬藏A\u{030a}\u{110b}\u{1161}"); - assert_eq!(0, b.preceding_line_break(0)); - assert_eq!(0, b.preceding_line_break(11)); - assert_eq!(0, b.preceding_line_break(13)); - assert_eq!(0, b.preceding_line_break(21)); - } - - #[test] - fn next_line_break() { - let a = String::from("Technically\na word:\n ৬藏A\u{030a}\n\u{110b}\u{1161}"); - assert_eq!(11, a.next_line_break(0)); - assert_eq!(11, a.next_line_break(11)); - assert_eq!(19, a.next_line_break(13)); - assert_eq!(30, a.next_line_break(21)); - assert_eq!(a.len(), a.next_line_break(31)); - - let b = String::from("Technically a word: ৬藏A\u{030a}\u{110b}\u{1161}"); - assert_eq!(b.len(), b.next_line_break(0)); - assert_eq!(b.len(), b.next_line_break(11)); - assert_eq!(b.len(), b.next_line_break(13)); - assert_eq!(b.len(), b.next_line_break(19)); - } - - #[test] - fn arcstring_empty_edit() { - let a = Arc::new("hello".to_owned()); - let mut b = a.clone(); - b.edit(5..5, ""); - assert!(Arc::ptr_eq(&a, &b)); - } -} diff --git a/src/text/font_descriptor.rs b/src/text/font_descriptor.rs deleted file mode 100644 index 19dad581..00000000 --- a/src/text/font_descriptor.rs +++ /dev/null @@ -1,70 +0,0 @@ -// This software is licensed under Apache License 2.0 and distributed on an -// "as-is" basis without warranties of any kind. See the LICENSE file for -// details. - -//! Font attributes - -use crate::piet::{FontFamily, FontStyle, FontWeight}; - -/// A collection of attributes that describe a font. -/// -/// This is provided as a convenience; library consumers may wish to have -/// a single type that represents a specific font face at a specific size. -#[derive(Debug, Clone, PartialEq)] -pub struct FontDescriptor { - /// The font's [`FontFamily`](struct.FontFamily.html). - pub family: FontFamily, - /// The font's size. - pub size: f64, - /// The font's [`FontWeight`](struct.FontWeight.html). - pub weight: FontWeight, - /// The font's [`FontStyle`](struct.FontStyle.html). - pub style: FontStyle, -} - -impl FontDescriptor { - /// Create a new descriptor with the provided [`FontFamily`]. - /// - /// [`FontFamily`]: struct.FontFamily.html - pub const fn new(family: FontFamily) -> Self { - FontDescriptor { - family, - size: crate::piet::util::DEFAULT_FONT_SIZE, - weight: FontWeight::REGULAR, - style: FontStyle::Regular, - } - } - - /// Buider-style method to set the descriptor's font size. - pub const fn with_size(mut self, size: f64) -> Self { - self.size = size; - self - } - - /// Buider-style method to set the descriptor's [`FontWeight`]. - /// - /// [`FontWeight`]: struct.FontWeight.html - pub const fn with_weight(mut self, weight: FontWeight) -> Self { - self.weight = weight; - self - } - - /// Buider-style method to set the descriptor's [`FontStyle`]. - /// - /// [`FontStyle`]: enum.FontStyle.html - pub const fn with_style(mut self, style: FontStyle) -> Self { - self.style = style; - self - } -} - -impl Default for FontDescriptor { - fn default() -> Self { - FontDescriptor { - family: Default::default(), - weight: Default::default(), - style: Default::default(), - size: crate::piet::util::DEFAULT_FONT_SIZE, - } - } -} diff --git a/src/text/input_component.rs b/src/text/input_component.rs deleted file mode 100644 index fe5fcaba..00000000 --- a/src/text/input_component.rs +++ /dev/null @@ -1,954 +0,0 @@ -// This software is licensed under Apache License 2.0 and distributed on an -// "as-is" basis without warranties of any kind. See the LICENSE file for -// details. - -//! A widget component that integrates with the platform text system. - -use std::cell::{Cell, Ref, RefCell, RefMut}; -use std::ops::Range; -use std::sync::{Arc, Weak}; - -use druid_shell::{Cursor, Modifiers}; -use smallvec::SmallVec; -use tracing::{trace_span, Span}; - -use super::{ - EditableText, ImeHandlerRef, ImeInvalidation, InputHandler, Movement, Selection, TextAction, - TextAlignment, TextLayout, TextStorage, -}; -use crate::kurbo::{Line, Point, Rect, Vec2}; -use crate::piet::TextLayout as _; -use crate::widget::WidgetRef; -use crate::{ - text, theme, BoxConstraints, Event, EventCtx, LayoutCtx, LifeCycle, LifeCycleCtx, PaintCtx, - RenderContext, Selector, Size, StatusChange, Widget, -}; - -/// A widget that accepts text input. -/// -/// This is intended to be used as a component of other widgets. -/// -/// Text input is more complicated than you think, probably. For a good -/// overview, see [`druid_shell::text`]. -/// -/// This type manages an inner [`EditSession`] that is shared with the platform. -/// Unlike other aspects of Masonry, the platform interacts with this session, not -/// through discrete events. -/// -/// This is managed through a simple 'locking' mechanism; the platform asks for -/// a lock on a particular text session that it wishes to interact with, calls -/// methods on the locked session, and then later releases the lock. -/// -/// Importantly, *other events may be received while the lock is held*. -/// -/// It is the responsibility of the user of this widget to ensure that the -/// session is not locked before it is accessed. This can be done by checking -/// [`TextComponent::can_read`] and [`TextComponent::can_write`]; -/// after checking these methods the inner session can be accessed via -/// [`TextComponent::borrow`] and [`TextComponent::borrow_mut`]. -/// -/// Sementically, this functions like a `RefCell`; attempting to borrow while -/// a lock is held will result in a panic. -#[derive(Debug, Clone)] -pub struct TextComponent { - edit_session: Arc>>, - lock: Arc>, - // HACK: because of the way focus works (it is managed higher up, in - // whatever widget is controlling this) we can't rely on `is_focused` in - // the PaintCtx. - /// A manual flag set by the parent to control drawing behaviour. - /// - /// The parent should update this when handling [`StatusChange::FocusChanged`]. - pub has_focus: bool, -} - -crate::declare_widget!( - TextComponentMut, - TextComponent -); - -/// Editable text state. -/// -/// This is the inner state of a [`TextComponent`]. It should only be accessed -/// through its containing [`TextComponent`], or by the platform through an -/// [`ImeHandlerRef`] created by [`TextComponent::input_handler`]. -#[derive(Debug, Clone)] -pub struct EditSession { - /// The inner [`TextLayout`] object. - /// - /// This is exposed so that users can do things like set text properties; - /// you should avoid doing things like rebuilding this layout manually, or - /// setting the text directly. - pub layout: TextLayout, - /// If the platform modifies the text, this contains the new text; - /// we update the app `Data` with this text on the next update pass. - external_text_change: Option, - external_selection_change: Option, - external_scroll_to: Option, - external_action: Option, - /// A flag set in `update` if the text has changed from a non-IME source. - pending_ime_invalidation: Option, - /// If `true`, the component will send the [`TextComponent::RETURN`] - /// notification when the user enters a newline. - pub send_notification_on_return: bool, - /// If `true`, the component will send the [`TextComponent::CANCEL`] - /// notification when the user cancels editing. - pub send_notification_on_cancel: bool, - selection: Selection, - accepts_newlines: bool, - accepts_tabs: bool, - alignment: TextAlignment, - /// The y-position of the text when it does not fill our width. - alignment_offset: f64, - /// The portion of the text that is currently marked by the IME. - composition_range: Option>, - drag_granularity: DragGranularity, - /// The origin of the textbox, relative to the origin of the window. - pub origin: Point, -} - -/// An object that can be used to acquire an `ImeHandler`. -/// -/// This does not own the session; when the widget that owns the session -/// is dropped, this will become invalid. -#[derive(Debug, Clone)] -struct EditSessionRef { - inner: Weak>>, - lock: Arc>, -} - -/// A locked handle to an [`EditSession`]. -/// -/// This type implements [`InputHandler`]; it is the type that we pass to the -/// platform. -struct EditSessionHandle { - text: T, - inner: Arc>>, -} - -/// When a drag follows a double- or triple-click, the behaviour of -/// drag changes to only select whole words or whole paragraphs. -#[derive(Debug, Clone, Copy, PartialEq)] -enum DragGranularity { - Grapheme, - /// Start and end are the start/end bounds of the initial selection. - Word { - start: usize, - end: usize, - }, - /// Start and end are the start/end bounds of the initial selection. - Paragraph { - start: usize, - end: usize, - }, -} - -/// An informal lock. -#[derive(Debug, Clone, Copy, PartialEq)] -enum ImeLock { - None, - ReadWrite, - Read, -} - -impl ImeHandlerRef for EditSessionRef { - fn is_alive(&self) -> bool { - Weak::strong_count(&self.inner) > 0 - } - - fn acquire(&self, mutable: bool) -> Option> { - let lock = if mutable { - ImeLock::ReadWrite - } else { - ImeLock::Read - }; - assert_eq!( - self.lock.replace(lock), - ImeLock::None, - "Ime session is already locked" - ); - Weak::upgrade(&self.inner) - .map(EditSessionHandle::new) - .map(|doc| Box::new(doc) as Box) - } - - fn release(&self) -> bool { - self.lock.replace(ImeLock::None) == ImeLock::ReadWrite - } -} - -impl TextComponent<()> { - /// A notification sent by the component when the cursor has moved. - /// - /// If the payload is true, this follows an edit, and the view will need - /// layout before scrolling. - pub const SCROLL_TO: Selector = Selector::new("masonry-builtin.textbox-scroll-to"); - - /// A notification sent by the component when the user hits return. - /// - /// This is only sent when `send_notification_on_return` is `true`. - pub const RETURN: Selector = Selector::new("masonry-builtin.textbox-return"); - - /// A notification sent by the component when the user edits contents. - pub const TEXT_CHANGED: Selector = Selector::new("masonry-builtin.textbox-changed"); - - /// A notification sent when the user cancels editing. - /// - /// This is only sent when `send_notification_on_cancel` is `true`. - pub const CANCEL: Selector = Selector::new("masonry-builtin.textbox-cancel"); - - /// A notification sent by the component when the user presses the tab key. - /// - /// This is not sent if `accepts_tabs` is true. - /// - /// An ancestor can handle this event in order to do things like request - /// a focus change. - pub const TAB: Selector = Selector::new("masonry-builtin.textbox-tab"); - - /// A notification sent by the component when the user inserts a backtab. - /// - /// This is not sent if `accepts_tabs` is true. - /// - /// An ancestor can handle this event in order to do things like request - /// a focus change. - pub const BACKTAB: Selector = Selector::new("masonry-builtin.textbox-backtab"); -} - -impl TextComponent { - /// Returns `true` if the inner [`EditSession`] can be read. - pub fn can_read(&self) -> bool { - self.lock.get() != ImeLock::ReadWrite - } - - /// Returns `true` if the inner [`EditSession`] can be mutated. - pub fn can_write(&self) -> bool { - self.lock.get() == ImeLock::None - } - - /// Returns `true` if the IME is actively composing (or the text is locked.) - /// - /// When text is composing, you should avoid doing things like modifying the - /// selection or copy/pasting text. - pub fn is_composing(&self) -> bool { - self.can_read() && self.borrow().composition_range.is_some() - } - - /// Attempt to mutably borrow the inner [`EditSession`]. - /// - /// # Panics - /// - /// This method panics if there is an outstanding lock on the session. - pub fn borrow_mut(&self) -> RefMut<'_, EditSession> { - assert!(self.can_write()); - self.edit_session.borrow_mut() - } - - /// Attempt to borrow the inner [`EditSession`]. - /// - /// # Panics - /// - /// This method panics if there is an outstanding write lock on the session. - pub fn borrow(&self) -> Ref<'_, EditSession> { - assert!(self.can_read()); - self.edit_session.borrow() - } -} - -impl TextComponent { - /// Returns an [`ImeHandlerRef`] that can accept platform text input. - /// - /// The widget managing this component should call [`LifeCycleCtx::register_text_input`] - /// during [`LifeCycle::WidgetAdded`], and pass it this object. - pub fn input_handler(&self) -> impl ImeHandlerRef { - EditSessionRef { - inner: Arc::downgrade(&self.edit_session), - lock: self.lock.clone(), - } - } -} - -impl TextComponentMut<'_, '_, T> { - pub fn set_text(&mut self, new_text: impl Into) { - let new_text = new_text.into(); - // TODO - use '==' instead - let needs_rebuild = self - .widget - .borrow() - .layout - .text() - .map(|old| !old.maybe_eq(&new_text)) - .unwrap_or(true); - if needs_rebuild { - self.widget.borrow_mut().layout.set_text(new_text.clone()); - self.widget - .borrow_mut() - .update_pending_invalidation(ImeInvalidation::Reset); - self.ctx.request_layout(); - } - } - - pub fn set_focused(&mut self, focused: bool) { - self.widget.has_focus = focused; - self.ctx.request_paint(); - } -} - -impl Widget for TextComponent { - fn on_event(&mut self, ctx: &mut EventCtx, event: &Event) { - match event { - Event::MouseDown(mouse) if self.can_write() && !ctx.is_disabled() => { - ctx.set_active(true); - self.borrow_mut() - .do_mouse_down(mouse.pos, mouse.mods, mouse.count); - self.borrow_mut() - .update_pending_invalidation(ImeInvalidation::SelectionChanged); - ctx.request_layout(); - ctx.request_paint(); - } - Event::MouseMove(mouse) if self.can_write() => { - if !ctx.is_disabled() { - ctx.set_cursor(&Cursor::IBeam); - if ctx.is_active() { - let pre_sel = self.borrow().selection(); - self.borrow_mut().do_drag(mouse.pos); - if self.borrow().selection() != pre_sel { - self.borrow_mut() - .update_pending_invalidation(ImeInvalidation::SelectionChanged); - ctx.request_layout(); - ctx.request_paint(); - } - } - } else { - ctx.set_disabled(false); - ctx.clear_cursor(); - } - } - Event::MouseUp(_) if ctx.is_active() => { - ctx.set_active(false); - ctx.request_paint(); - } - Event::ImeStateChange => { - assert!( - self.can_write(), - "lock release should be cause of ImeStateChange event" - ); - - let scroll_to = self.borrow_mut().take_scroll_to(); - if let Some(scroll_to) = scroll_to { - ctx.submit_notification(TextComponent::SCROLL_TO.with(scroll_to)); - } - - let text = self.borrow_mut().take_external_text_change(); - if let Some(text) = text { - self.borrow_mut().layout.set_text(text.clone()); - let new_text = self - .borrow() - .layout - .text() - .map(|txt| txt.as_str()) - .unwrap_or("") - .to_string(); - ctx.submit_notification(TextComponent::TEXT_CHANGED.with(new_text)); - } - - let action = self.borrow_mut().take_external_action(); - if let Some(action) = action { - match action { - TextAction::Cancel => ctx.submit_notification(TextComponent::CANCEL), - TextAction::InsertNewLine { .. } => { - let text = self - .borrow() - .layout - .text() - .map(|txt| txt.as_str()) - .unwrap_or("") - .to_string(); - ctx.submit_notification(TextComponent::RETURN.with(text)); - } - TextAction::InsertTab { .. } => ctx.submit_notification(TextComponent::TAB), - TextAction::InsertBacktab => { - ctx.submit_notification(TextComponent::BACKTAB) - } - _ => tracing::warn!("unexepcted external action '{:?}'", action), - }; - } - - let selection = self.borrow_mut().take_external_selection_change(); - if let Some(selection) = selection { - self.borrow_mut().selection = selection; - ctx.request_paint(); - } - ctx.request_layout(); - } - _ => (), - } - } - - fn on_status_change(&mut self, _ctx: &mut LifeCycleCtx, _event: &StatusChange) {} - - fn lifecycle(&mut self, ctx: &mut LifeCycleCtx, event: &LifeCycle) { - match event { - LifeCycle::WidgetAdded => { - assert!( - self.can_write(), - "ime should never be locked at WidgetAdded" - ); - self.borrow_mut().layout.rebuild_if_needed(ctx.text()); - } - LifeCycle::DisabledChanged(disabled) => { - if self.can_write() { - let color = if *disabled { - theme::DISABLED_TEXT_COLOR - } else { - theme::TEXT_COLOR - }; - self.borrow_mut().layout.set_text_color(color); - } - ctx.request_layout(); - } - //FIXME: this should happen in the parent too? - LifeCycle::Internal(crate::InternalLifeCycle::ParentWindowOrigin) => { - if self.can_write() { - let prev_origin = self.borrow().origin; - let new_origin = ctx.window_origin(); - if prev_origin != new_origin { - self.borrow_mut().origin = ctx.window_origin(); - ctx.invalidate_text_input(ImeInvalidation::LayoutChanged); - } - } - } - _ => (), - } - } - - fn layout(&mut self, ctx: &mut LayoutCtx, bc: &BoxConstraints) -> Size { - if !self.can_write() { - tracing::warn!("Text layout called with IME lock held."); - return Size::ZERO; - } - - self.borrow_mut().layout.set_wrap_width(bc.max().width); - self.borrow_mut().layout.rebuild_if_needed(ctx.text()); - let metrics = self.borrow().layout.layout_metrics(); - let width = if bc.max().width.is_infinite() || bc.max().width < f64::MAX { - metrics.trailing_whitespace_width - } else { - metrics.size.width - }; - let size = bc.constrain((width, metrics.size.height)); - let extra_width = if self.borrow().accepts_newlines { - 0.0 - } else { - (size.width - width).max(0.0) - }; - self.borrow_mut().update_alignment_offset(extra_width); - let baseline_off = metrics.size.height - metrics.first_baseline; - ctx.set_baseline_offset(baseline_off); - size - } - - fn paint(&mut self, ctx: &mut PaintCtx) { - if !self.can_read() { - tracing::warn!("Text paint called with IME lock held."); - } - - let selection_color = if self.has_focus { - theme::SELECTED_TEXT_BACKGROUND_COLOR - } else { - theme::SELECTED_TEXT_INACTIVE_BACKGROUND_COLOR - }; - - let cursor_color = theme::CURSOR_COLOR; - let text_offset = Vec2::new(self.borrow().alignment_offset, 0.0); - - let selection = self.borrow().selection(); - let composition = self.borrow().composition_range(); - let sel_rects = self.borrow().layout.rects_for_range(selection.range()); - if let Some(composition) = composition { - // I believe selection should always be contained in composition range while composing? - assert!(composition.start <= selection.anchor && composition.end >= selection.active); - let comp_rects = self.borrow().layout.rects_for_range(composition); - for region in comp_rects { - let y = region.max_y().floor(); - let line = Line::new((region.min_x(), y), (region.max_x(), y)) + text_offset; - ctx.stroke(line, &cursor_color, 1.0); - } - for region in sel_rects { - let y = region.max_y().floor(); - let line = Line::new((region.min_x(), y), (region.max_x(), y)) + text_offset; - ctx.stroke(line, &cursor_color, 2.0); - } - } else { - for region in sel_rects { - let rounded = (region + text_offset).to_rounded_rect(1.0); - ctx.fill(rounded, &selection_color); - } - } - self.borrow().layout.draw(ctx, text_offset.to_point()); - } - - fn children(&self) -> SmallVec<[WidgetRef<'_, dyn Widget>; 16]> { - SmallVec::new() - } - - fn make_trace_span(&self) -> Span { - trace_span!("TextComponent") - } -} - -impl EditSession { - /// The current [`Selection`]. - pub fn selection(&self) -> Selection { - self.selection - } - - /// Manually set the selection. - /// - /// If the new selection is different from the current selection, this - /// will return an ime event that the controlling widget should use to - /// invalidte the platform's IME state, by passing it to - /// [`EventCtx::invalidate_text_input`]. - #[must_use] - pub fn set_selection(&mut self, selection: Selection) -> Option { - if selection != self.selection { - self.selection = selection; - self.update_pending_invalidation(ImeInvalidation::SelectionChanged); - Some(ImeInvalidation::SelectionChanged) - } else { - None - } - } - - /// The range of text currently being modified by an IME. - pub fn composition_range(&self) -> Option> { - self.composition_range.clone() - } - - /// Sets whether or not this session will allow the insertion of newlines. - pub fn set_accepts_newlines(&mut self, accepts_newlines: bool) { - self.accepts_newlines = accepts_newlines; - } - - /// Set the text alignment. - /// - /// This is only meaningful for single-line text that does not fill - /// the minimum layout size. - pub fn set_text_alignment(&mut self, alignment: TextAlignment) { - self.alignment = alignment; - } - - /// The text alignment. - pub fn text_alignment(&self) -> TextAlignment { - self.alignment - } - - /// Returns any invalidation action that should be passed to the platform. - /// - /// The user of this component *must* check this after calling `update`. - pub fn pending_ime_invalidation(&mut self) -> Option { - self.pending_ime_invalidation.take() - } - - fn take_external_text_change(&mut self) -> Option { - self.external_text_change.take() - } - - fn take_external_selection_change(&mut self) -> Option { - self.external_selection_change.take() - } - - fn take_scroll_to(&mut self) -> Option { - self.external_scroll_to.take() - } - - fn take_external_action(&mut self) -> Option { - self.external_action.take() - } - - // we don't want to replace a more aggressive invalidation with a less aggressive one. - fn update_pending_invalidation(&mut self, new_invalidation: ImeInvalidation) { - self.pending_ime_invalidation = match self.pending_ime_invalidation.take() { - None => Some(new_invalidation), - Some(prev) => match (prev, new_invalidation) { - (ImeInvalidation::SelectionChanged, ImeInvalidation::SelectionChanged) => { - ImeInvalidation::SelectionChanged - } - (ImeInvalidation::LayoutChanged, ImeInvalidation::LayoutChanged) => { - ImeInvalidation::LayoutChanged - } - _ => ImeInvalidation::Reset, - } - .into(), - } - } - - fn update_alignment_offset(&mut self, extra_width: f64) { - self.alignment_offset = match self.alignment { - TextAlignment::Start | TextAlignment::Justified => 0.0, - TextAlignment::End => extra_width, - TextAlignment::Center => extra_width / 2.0, - }; - } -} - -impl EditSession { - /// Insert text *not* from the IME, replacing the current selection. - /// - /// The caller is responsible for notifying the platform of the change in - /// text state, by calling [`EventCtx::invalidate_text_input`]. - #[must_use] - pub fn insert_text(&mut self, data: &mut T, new_text: &str) -> ImeInvalidation { - let new_cursor_pos = self.selection.min() + new_text.len(); - data.edit(self.selection.range(), new_text); - self.selection = Selection::caret(new_cursor_pos); - self.scroll_to_selection_end(true); - ImeInvalidation::Reset - } - - /// Sets the clipboard to the contents of the current selection. - /// - /// Returns `true` if the clipboard was set, and `false` if not (indicating) - /// that the selection was empty.) - pub fn set_clipboard(&self) -> bool { - if let Some(text) = self - .layout - .text() - .and_then(|txt| txt.slice(self.selection.range())) - { - if !text.is_empty() { - druid_shell::Application::global() - .clipboard() - .put_string(text); - return true; - } - } - false - } - - fn scroll_to_selection_end(&mut self, after_edit: bool) { - self.external_scroll_to = Some(after_edit); - } - - fn do_action(&mut self, buffer: &mut T, action: TextAction) { - match action { - TextAction::Move(movement) => { - let sel = text::movement(movement, self.selection, &self.layout, false); - self.external_selection_change = Some(sel); - self.scroll_to_selection_end(false); - } - TextAction::MoveSelecting(movement) => { - let sel = text::movement(movement, self.selection, &self.layout, true); - self.external_selection_change = Some(sel); - self.scroll_to_selection_end(false); - } - TextAction::SelectAll => { - let len = buffer.len(); - self.external_selection_change = Some(Selection::new(0, len)); - } - TextAction::SelectWord => { - if self.selection.is_caret() { - let range = - text::movement::word_range_for_pos(buffer.as_str(), self.selection.active); - self.external_selection_change = Some(Selection::new(range.start, range.end)); - } - - // it is unclear what the behaviour should be if the selection - // is not a caret (and may span multiple words) - } - // This requires us to have access to the layout, which might be stale? - TextAction::SelectLine => (), - // this assumes our internal selection is consistent with the buffer? - TextAction::SelectParagraph => { - if !self.selection.is_caret() || buffer.len() < self.selection.active { - return; - } - let prev = buffer.preceding_line_break(self.selection.active); - let next = buffer.next_line_break(self.selection.active); - self.external_selection_change = Some(Selection::new(prev, next)); - } - TextAction::Delete(movement) if self.selection.is_caret() => { - if movement == Movement::Grapheme(druid_shell::text::Direction::Upstream) { - self.backspace(buffer); - } else { - let to_delete = text::movement(movement, self.selection, &self.layout, true); - self.selection = to_delete; - self.ime_insert_text(buffer, "") - } - } - TextAction::Delete(_) => self.ime_insert_text(buffer, ""), - TextAction::DecomposingBackspace => { - tracing::warn!("Decomposing Backspace is not implemented"); - self.backspace(buffer); - } - //TextAction::UppercaseSelection - //| TextAction::LowercaseSelection - //| TextAction::TitlecaseSelection => { - //tracing::warn!("IME transformations are not implemented"); - //} - TextAction::InsertNewLine { - newline_type, - ignore_hotkey, - } => { - if self.send_notification_on_return && !ignore_hotkey { - self.external_action = Some(action); - } else if self.accepts_newlines { - self.ime_insert_text(buffer, &newline_type.to_string()); - } - } - TextAction::InsertTab { ignore_hotkey } => { - if ignore_hotkey || self.accepts_tabs { - self.ime_insert_text(buffer, "\t"); - } else if !ignore_hotkey { - self.external_action = Some(action); - } - } - TextAction::InsertBacktab => { - if !self.accepts_tabs { - self.external_action = Some(action); - } - } - TextAction::InsertSingleQuoteIgnoringSmartQuotes => self.ime_insert_text(buffer, "'"), - TextAction::InsertDoubleQuoteIgnoringSmartQuotes => self.ime_insert_text(buffer, "\""), - TextAction::Cancel if self.send_notification_on_cancel => { - self.external_action = Some(action) - } - other => tracing::warn!("unhandled IME action {:?}", other), - } - } - - /// Replace the current selection with `text`, and advance the cursor. - /// - /// This should only be called from the IME. - fn ime_insert_text(&mut self, buffer: &mut T, text: &str) { - let new_cursor_pos = self.selection.min() + text.len(); - buffer.edit(self.selection.range(), text); - self.external_selection_change = Some(Selection::caret(new_cursor_pos)); - self.scroll_to_selection_end(true); - } - - fn backspace(&mut self, buffer: &mut T) { - let to_del = if self.selection.is_caret() { - let del_start = text::offset_for_delete_backwards(&self.selection, buffer); - del_start..self.selection.anchor - } else { - self.selection.range() - }; - self.external_selection_change = Some(Selection::caret(to_del.start)); - buffer.edit(to_del, ""); - self.scroll_to_selection_end(true); - } - - fn do_mouse_down(&mut self, point: Point, mods: Modifiers, count: u8) { - let point = point - Vec2::new(self.alignment_offset, 0.0); - let pos = self.layout.text_position_for_point(point); - if mods.shift() { - self.selection.active = pos; - } else { - let Range { start, end } = self.sel_region_for_pos(pos, count); - self.selection = Selection::new(start, end); - self.drag_granularity = match count { - 2 => DragGranularity::Word { start, end }, - 3 => DragGranularity::Paragraph { start, end }, - _ => DragGranularity::Grapheme, - }; - } - } - - fn do_drag(&mut self, point: Point) { - let point = point - Vec2::new(self.alignment_offset, 0.0); - //FIXME: this should behave differently if we were double or triple clicked - let pos = self.layout.text_position_for_point(point); - let text = match self.layout.text() { - Some(text) => text, - None => return, - }; - - let (start, end) = match self.drag_granularity { - DragGranularity::Grapheme => (self.selection.anchor, pos), - DragGranularity::Word { start, end } => { - let word_range = self.word_for_pos(pos); - if pos <= start { - (end, word_range.start) - } else { - (start, word_range.end) - } - } - DragGranularity::Paragraph { start, end } => { - let par_start = text.preceding_line_break(pos); - let par_end = text.next_line_break(pos); - - if pos <= start { - (end, par_start) - } else { - (start, par_end) - } - } - }; - self.selection = Selection::new(start, end); - self.scroll_to_selection_end(false); - } - - /// Returns a line suitable for drawing a standard cursor. - pub fn cursor_line_for_text_position(&self, pos: usize) -> Line { - let line = self.layout.cursor_line_for_text_position(pos); - line + Vec2::new(self.alignment_offset, 0.0) - } - - fn sel_region_for_pos(&mut self, pos: usize, click_count: u8) -> Range { - match click_count { - 1 => pos..pos, - 2 => self.word_for_pos(pos), - _ => { - let text = match self.layout.text() { - Some(text) => text, - None => return pos..pos, - }; - let line_min = text.preceding_line_break(pos); - let line_max = text.next_line_break(pos); - line_min..line_max - } - } - } - - fn word_for_pos(&self, pos: usize) -> Range { - let layout = match self.layout.layout() { - Some(layout) => layout, - None => return pos..pos, - }; - - let line_n = layout.hit_test_text_position(pos).line; - let lm = layout.line_metric(line_n).unwrap(); - let text = layout.line_text(line_n).unwrap(); - let rel_pos = pos - lm.start_offset; - let mut range = text::movement::word_range_for_pos(text, rel_pos); - range.start += lm.start_offset; - range.end += lm.start_offset; - range - } -} - -impl EditSessionHandle { - fn new(inner: Arc>>) -> Self { - let text = inner.borrow().layout.text().cloned().unwrap(); - EditSessionHandle { text, inner } - } -} - -impl InputHandler for EditSessionHandle { - fn selection(&self) -> Selection { - self.inner.borrow().selection - } - - fn set_selection(&mut self, selection: Selection) { - self.inner.borrow_mut().external_selection_change = Some(selection); - self.inner.borrow_mut().external_scroll_to = Some(true); - } - - fn composition_range(&self) -> Option> { - self.inner.borrow().composition_range.clone() - } - - fn set_composition_range(&mut self, range: Option>) { - self.inner.borrow_mut().composition_range = range; - } - - fn is_char_boundary(&self, i: usize) -> bool { - self.text.cursor(i).is_some() - } - - fn len(&self) -> usize { - self.text.len() - } - - fn slice(&self, range: Range) -> std::borrow::Cow { - self.text.slice(range).unwrap() - } - - fn replace_range(&mut self, range: Range, text: &str) { - self.text.edit(range, text); - self.inner.borrow_mut().external_text_change = Some(self.text.clone()); - } - - fn hit_test_point(&self, point: Point) -> crate::piet::HitTestPoint { - self.inner - .borrow() - .layout - .layout() - .map(|layout| layout.hit_test_point(point)) - .unwrap_or_default() - } - - fn line_range(&self, index: usize, _affinity: druid_shell::text::Affinity) -> Range { - let inner = self.inner.borrow(); - let layout = inner.layout.layout().unwrap(); - let hit = layout.hit_test_text_position(index); - let metric = layout.line_metric(hit.line).unwrap(); - metric.range() - } - - fn bounding_box(&self) -> Option { - let size = self.inner.borrow().layout.size(); - Some(Rect::from_origin_size(self.inner.borrow().origin, size)) - } - - fn slice_bounding_box(&self, range: Range) -> Option { - let origin = self.inner.borrow().origin; - let layout = &self.inner.borrow().layout; - if range.is_empty() { - let hit = layout - .layout() - .map(|l| l.hit_test_text_position(range.start))?; - let line = layout.layout().and_then(|l| l.line_metric(hit.line))?; - let x = hit.point.x; - Some(Rect::new(x, line.y_offset, x, line.y_offset + line.height)) - } else { - layout.rects_for_range(range).first().copied() - } - .map(|rect| rect + origin.to_vec2()) - } - - fn handle_action(&mut self, action: TextAction) { - self.inner.borrow_mut().do_action(&mut self.text, action); - let text_changed = self - .inner - .borrow() - .layout - .text() - .map(|old| !old.maybe_eq(&self.text)) - .unwrap_or(true); - if text_changed { - self.inner.borrow_mut().external_text_change = Some(self.text.clone()); - } - } -} - -impl TextComponent { - /// Create new `TextComponent`. - pub fn new(text: T) -> Self { - let mut inner = EditSession { - layout: TextLayout::new(), - external_scroll_to: None, - external_text_change: None, - external_selection_change: None, - external_action: None, - pending_ime_invalidation: None, - selection: Selection::caret(0), - composition_range: None, - send_notification_on_return: false, - send_notification_on_cancel: false, - accepts_newlines: false, - accepts_tabs: false, - alignment: TextAlignment::Start, - alignment_offset: 0.0, - drag_granularity: DragGranularity::Grapheme, - origin: Point::ZERO, - }; - inner.layout.set_text(text); - - TextComponent { - edit_session: Arc::new(RefCell::new(inner)), - lock: Arc::new(Cell::new(ImeLock::None)), - has_focus: false, - } - } -} diff --git a/src/text/input_methods.rs b/src/text/input_methods.rs deleted file mode 100644 index fd0b1484..00000000 --- a/src/text/input_methods.rs +++ /dev/null @@ -1,65 +0,0 @@ -// This software is licensed under Apache License 2.0 and distributed on an -// "as-is" basis without warranties of any kind. See the LICENSE file for -// details. - -//! Types related to input method editing. -//! -//! Most IME-related code is in druid-shell; these are helper types used -//! exclusively in Masonry. - -use std::rc::Rc; - -use druid_shell::text::InputHandler; - -use crate::WidgetId; - -/// A trait for input handlers registered by widgets. -/// -/// A widget registers itself as accepting text input by calling -/// [`LifeCycleCtx::register_text_input`] while handling the -/// [`LifeCycle::WidgetAdded`] event. -/// -/// The widget does not explicitly *deregister* afterwards; rather anytime -/// the widget tree changes, Masonry will call [`is_alive`] on each registered -/// `ImeHandlerRef`, and deregister those that return `false`. -/// -/// [`LifeCycle::WidgetAdded`]: crate::LifeCycle::WidgetAdded -/// [`LifeCycleCtx::register_text_input`]: crate::LifeCycleCtx::register_text_input -/// [`is_alive`]: ImeHandlerRef::is_alive -pub trait ImeHandlerRef { - /// Returns `true` if this handler is still active. - fn is_alive(&self) -> bool; - /// Mark the session as locked, and return a handle. - /// - /// The lock can be read-write or read-only, indicated by the `mutable` flag. - /// - /// if [`is_alive`] is `true`, this should always return `Some(_)`. - /// - /// [`is_alive`]: ImeHandlerRef::is_alive - fn acquire(&self, mutable: bool) -> Option>; - /// Mark the session as released. - fn release(&self) -> bool; -} - -/// A type we use to keep track of which widgets are responsible for which -/// ime sessions. -#[derive(Clone)] -pub(crate) struct TextFieldRegistration { - pub widget_id: WidgetId, - pub document: Rc, -} - -impl TextFieldRegistration { - pub fn is_alive(&self) -> bool { - self.document.is_alive() - } -} - -impl std::fmt::Debug for TextFieldRegistration { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - f.debug_struct("TextFieldRegistration") - .field("widget_id", &self.widget_id) - .field("is_alive", &self.document.is_alive()) - .finish() - } -} diff --git a/src/text/layout.rs b/src/text/layout.rs deleted file mode 100644 index 7f9da02b..00000000 --- a/src/text/layout.rs +++ /dev/null @@ -1,424 +0,0 @@ -// This software is licensed under Apache License 2.0 and distributed on an -// "as-is" basis without warranties of any kind. See the LICENSE file for -// details. - -//! A type for laying out, drawing, and interacting with text. - -use std::ops::Range; -use std::rc::Rc; - -use super::{FontDescriptor, Link, TextStorage}; -use crate::kurbo::{Line, Point, Rect, Size}; -use crate::piet::{ - Color, PietText, PietTextLayout, Text as _, TextAlignment, TextAttribute, TextLayout as _, - TextLayoutBuilder as _, -}; -use crate::{PaintCtx, RenderContext}; - -/// A component for displaying text on screen. -/// -/// This is a type intended to be used by other widgets that display text. -/// It allows for the text itself as well as font and other styling information -/// to be set and modified. It wraps an inner layout object, and handles -/// invalidating and rebuilding it as required. -/// -/// This object is not valid until the [`rebuild_if_needed`] method has been -/// called. You should generally do this in your widget's [`layout`] method. -/// Additionally, you should call [`needs_rebuild_after_update`] -/// as part of your widget's [`update`] method; if this returns `true`, you will need -/// to call [`rebuild_if_needed`] again, generally by scheduling another [`layout`] -/// pass. -/// -/// [`layout`]: trait.Widget.html#tymethod.layout -/// [`update`]: trait.Widget.html#tymethod.update -/// [`needs_rebuild_after_update`]: #method.needs_rebuild_after_update -/// [`rebuild_if_needed`]: #method.rebuild_if_needed -#[derive(Clone)] -pub struct TextLayout { - // TODO - remove Option - text: Option, - font: FontDescriptor, - // when set, this will be used to override the size in he font descriptor. - // This provides an easy way to change only the font size, while still - // using a `FontDescriptor` in the `Env`. - text_size_override: Option, - text_color: Color, - layout: Option, - wrap_width: f64, - alignment: TextAlignment, - links: Rc<[(Rect, usize)]>, - text_is_rtl: bool, -} - -/// Metrics describing the layout text. -#[derive(Debug, Clone, Copy, Default)] -pub struct LayoutMetrics { - /// The nominal size of the layout. - pub size: Size, - /// The distance from the nominal top of the layout to the first baseline. - pub first_baseline: f64, - /// The width of the layout, inclusive of trailing whitespace. - pub trailing_whitespace_width: f64, - //TODO: add inking_rect -} - -impl TextLayout { - /// Create a new `TextLayout` object. - /// - /// You must set the text ([`set_text`]) before using this object. - /// - /// [`set_text`]: #method.set_text - pub fn new() -> Self { - TextLayout { - text: None, - font: crate::theme::UI_FONT, - text_color: crate::theme::TEXT_COLOR, - text_size_override: None, - layout: None, - wrap_width: f64::INFINITY, - alignment: Default::default(), - links: Rc::new([]), - text_is_rtl: false, - } - } - - /// Set the default text color for this layout. - pub fn set_text_color(&mut self, color: Color) { - if color != self.text_color { - self.text_color = color; - self.layout = None; - } - } - - /// Set the default font. - /// - /// The argument is a [`FontDescriptor`]. - /// - /// [`FontDescriptor`]: struct.FontDescriptor.html - pub fn set_font(&mut self, font: FontDescriptor) { - if font != self.font { - self.font = font; - self.layout = None; - self.text_size_override = None; - } - } - - /// Set the font size. - /// - /// This overrides the size in the [`FontDescriptor`] provided to [`set_font`]. - /// - /// [`set_font`]: #method.set_font.html - /// [`FontDescriptor`]: struct.FontDescriptor.html - pub fn set_text_size(&mut self, size: f64) { - if Some(&size) != self.text_size_override.as_ref() { - self.text_size_override = Some(size); - self.layout = None; - } - } - - /// Set the width at which to wrap words. - /// - /// You may pass `f64::INFINITY` to disable word wrapping - /// (the default behaviour). - pub fn set_wrap_width(&mut self, width: f64) { - let width = width.max(0.0); - // 1e-4 is an arbitrary small-enough value that we don't care to rewrap - if (width - self.wrap_width).abs() > 1e-4 { - self.wrap_width = width; - self.layout = None; - } - } - - /// Set the [`TextAlignment`] for this layout. - /// - /// [`TextAlignment`]: enum.TextAlignment.html - pub fn set_text_alignment(&mut self, alignment: TextAlignment) { - if self.alignment != alignment { - self.alignment = alignment; - self.layout = None; - } - } - - /// Returns `true` if this layout's text appears to be right-to-left. - /// - /// See [`piet::util::first_strong_rtl`] for more information. - /// - /// [`piet::util::first_strong_rtl`]: crate::piet::util::first_strong_rtl - pub fn text_is_rtl(&self) -> bool { - self.text_is_rtl - } -} - -impl TextLayout { - /// Create a new `TextLayout` with the provided text. - /// - /// This is useful when the text is not tied to application data. - pub fn from_text(text: impl Into) -> Self { - let mut this = TextLayout::new(); - this.set_text(text.into()); - this - } - - /// Returns `true` if this layout needs to be rebuilt. - /// - /// This happens (for instance) after style attributes are modified. - /// - /// This does not account for things like the text changing, handling that - /// is the responsibility of the user. - pub fn needs_rebuild(&self) -> bool { - self.layout.is_none() - } - - /// Set the text to display. - pub fn set_text(&mut self, text: T) { - if self.text.is_none() || !self.text.as_ref().unwrap().maybe_eq(&text) { - self.text_is_rtl = crate::piet::util::first_strong_rtl(text.as_str()); - self.text = Some(text); - self.layout = None; - } - } - - /// Returns the [`TextStorage`] backing this layout, if it exists. - pub fn text(&self) -> Option<&T> { - self.text.as_ref() - } - - /// Returns the length of the [`TextStorage`] backing this layout, if it exists. - pub fn text_len(&self) -> usize { - if let Some(text) = &self.text { - text.as_str().len() - } else { - 0 - } - } - - /// Returns the inner Piet [`TextLayout`] type. - /// - /// [`TextLayout`]: ./piet/trait.TextLayout.html - pub fn layout(&self) -> Option<&PietTextLayout> { - self.layout.as_ref() - } - - /// The size of the laid-out text. - /// - /// This is not meaningful until [`rebuild_if_needed`] has been called. - /// - /// [`rebuild_if_needed`]: #method.rebuild_if_needed - pub fn size(&self) -> Size { - self.layout - .as_ref() - .map(|layout| layout.size()) - .unwrap_or_default() - } - - /// Return the text's [`LayoutMetrics`]. - /// - /// This is not meaningful until [`rebuild_if_needed`] has been called. - /// - /// [`rebuild_if_needed`]: #method.rebuild_if_needed - /// [`LayoutMetrics`]: struct.LayoutMetrics.html - pub fn layout_metrics(&self) -> LayoutMetrics { - debug_assert!( - self.layout.is_some(), - "TextLayout::layout_metrics called without rebuilding layout object. Text was '{}'", - self.text().as_ref().map(|s| s.as_str()).unwrap_or_default() - ); - - if let Some(layout) = self.layout.as_ref() { - let first_baseline = layout.line_metric(0).unwrap().baseline; - let size = layout.size(); - LayoutMetrics { - size, - first_baseline, - trailing_whitespace_width: layout.trailing_whitespace_width(), - } - } else { - LayoutMetrics::default() - } - } - - /// For a given `Point` (relative to this object's origin), returns index - /// into the underlying text of the nearest grapheme boundary. - pub fn text_position_for_point(&self, point: Point) -> usize { - self.layout - .as_ref() - .map(|layout| layout.hit_test_point(point).idx) - .unwrap_or_default() - } - - /// Given the utf-8 position of a character boundary in the underlying text, - /// return the `Point` (relative to this object's origin) representing the - /// boundary of the containing grapheme. - /// - /// # Panics - /// - /// Panics if `text_pos` is not a character boundary. - pub fn point_for_text_position(&self, text_pos: usize) -> Point { - self.layout - .as_ref() - .map(|layout| layout.hit_test_text_position(text_pos).point) - .unwrap_or_default() - } - - /// Given a utf-8 range in the underlying text, return a `Vec` of `Rect`s - /// representing the nominal bounding boxes of the text in that range. - /// - /// # Panics - /// - /// Panics if the range start or end is not a character boundary. - pub fn rects_for_range(&self, range: Range) -> Vec { - self.layout - .as_ref() - .map(|layout| layout.rects_for_range(range)) - .unwrap_or_default() - } - - /// Return a line suitable for underlining a range of text. - /// - /// This is really only intended to be used to indicate the composition - /// range while IME is active. - /// - /// range is expected to be on a single visual line. - pub fn underline_for_range(&self, range: Range) -> Line { - self.layout - .as_ref() - .map(|layout| { - let p1 = layout.hit_test_text_position(range.start); - let p2 = layout.hit_test_text_position(range.end); - let line_metric = layout.line_metric(p1.line).unwrap(); - // heuristic; 1/5 of height is a rough guess at the descender pos? - let y_pos = line_metric.baseline + (line_metric.height / 5.0); - Line::new((p1.point.x, y_pos), (p2.point.x, y_pos)) - }) - .unwrap_or_else(|| Line::new(Point::ZERO, Point::ZERO)) - } - - /// Given the utf-8 position of a character boundary in the underlying text, - /// return a `Line` suitable for drawing a vertical cursor at that boundary. - pub fn cursor_line_for_text_position(&self, text_pos: usize) -> Line { - self.layout - .as_ref() - .map(|layout| { - let pos = layout.hit_test_text_position(text_pos); - let line_metrics = layout.line_metric(pos.line).unwrap(); - let p1 = (pos.point.x, line_metrics.y_offset); - let p2 = (pos.point.x, (line_metrics.y_offset + line_metrics.height)); - Line::new(p1, p2) - }) - .unwrap_or_else(|| Line::new(Point::ZERO, Point::ZERO)) - } - - /// Returns the [`Link`] at the provided point (relative to the layout's origin) if one exists. - /// - /// This can be used both for hit-testing (deciding whether to change the mouse cursor, - /// or performing some other action when hovering) as well as for retrieving a [`Link`] - /// on click. - /// - /// [`Link`]: super::attribute::Link - pub fn link_for_pos(&self, pos: Point) -> Option<&Link> { - let (_, i) = self - .links - .iter() - .rfind(|(hit_box, _)| hit_box.contains(pos))?; - - let text = self.text()?; - text.links().get(*i) - } - - /// Rebuild the inner layout as needed. - /// - /// This `TextLayout` object manages a lower-level layout object that may - /// need to be rebuilt in response to changes to the text or attributes - /// like the font. - /// - /// This method should be called whenever any of these things may have changed. - /// A simple way to ensure this is correct is to always call this method - /// as part of your widget's [`layout`] method. - /// - /// [`layout`]: trait.Widget.html#method.layout - pub fn rebuild_if_needed(&mut self, factory: &mut PietText) { - if let Some(text) = &self.text { - if self.layout.is_none() { - let font = self.font.clone(); - let color = self.text_color; - let size_override = self.text_size_override; - - let descriptor = if let Some(size) = size_override { - font.with_size(size) - } else { - font - }; - - let builder = factory - .new_text_layout(text.clone()) - .max_width(self.wrap_width) - .alignment(self.alignment) - .font(descriptor.family.clone(), descriptor.size) - .default_attribute(descriptor.weight) - .default_attribute(descriptor.style) - .default_attribute(TextAttribute::TextColor(color)); - let layout = text.add_attributes(builder).build().unwrap(); - - self.links = text - .links() - .iter() - .enumerate() - .flat_map(|(i, link)| { - layout - .rects_for_range(link.range()) - .into_iter() - .map(move |rect| (rect, i)) - }) - .collect(); - - self.layout = Some(layout); - } - } - } - - /// Draw the layout at the provided `Point`. - /// - /// The origin of the layout is the top-left corner. - /// - /// You must call [`rebuild_if_needed`] at some point before you first - /// call this method. - /// - /// [`rebuild_if_needed`]: #method.rebuild_if_needed - pub fn draw(&self, ctx: &mut PaintCtx, point: impl Into) { - debug_assert!( - self.layout.is_some(), - "TextLayout::draw called without rebuilding layout object. Text was '{}'", - self.text - .as_ref() - .map(|t| t.as_str()) - .unwrap_or("layout is missing text") - ); - if let Some(layout) = self.layout.as_ref() { - ctx.draw_text(layout, point); - } - } -} - -impl std::fmt::Debug for TextLayout { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - f.debug_struct("TextLayout") - .field("font", &self.font) - .field("text_size_override", &self.text_size_override) - .field("text_color", &self.text_color) - .field( - "layout", - if self.layout.is_some() { - &"Some" - } else { - &"None" - }, - ) - .finish() - } -} - -impl Default for TextLayout { - fn default() -> Self { - Self::new() - } -} diff --git a/src/text/mod.rs b/src/text/mod.rs deleted file mode 100644 index 1962a276..00000000 --- a/src/text/mod.rs +++ /dev/null @@ -1,38 +0,0 @@ -// This software is licensed under Apache License 2.0 and distributed on an -// "as-is" basis without warranties of any kind. See the LICENSE file for -// details. - -//! Editing and displaying text. - -// TODO -#![allow(clippy::all)] - -mod attribute; -mod backspace; -mod editable_text; -mod font_descriptor; - -mod input_component; -mod input_methods; -mod layout; -mod movement; -mod rich_text; -mod storage; - -pub use druid_shell::text::{ - Action as TextAction, Affinity, Direction, Event as ImeInvalidation, InputHandler, Movement, - Selection, VerticalMovement, WritingDirection, -}; -pub use input_component::{EditSession, TextComponent}; -pub use input_methods::ImeHandlerRef; -pub(crate) use input_methods::TextFieldRegistration; -pub use rich_text::{AttributesAdder, RichText, RichTextBuilder}; -pub use storage::{ArcStr, TextStorage}; - -pub use self::attribute::{Attribute, AttributeSpans, Link}; -pub use self::backspace::offset_for_delete_backwards; -pub use self::editable_text::{EditableText, EditableTextCursor, StringCursor}; -pub use self::font_descriptor::FontDescriptor; -pub use self::layout::{LayoutMetrics, TextLayout}; -pub use self::movement::movement; -pub use crate::piet::{FontFamily, FontStyle, FontWeight, TextAlignment}; diff --git a/src/text/movement.rs b/src/text/movement.rs deleted file mode 100644 index a7a278c1..00000000 --- a/src/text/movement.rs +++ /dev/null @@ -1,195 +0,0 @@ -// This software is licensed under Apache License 2.0 and distributed on an -// "as-is" basis without warranties of any kind. See the LICENSE file for -// details. - -//! Text editing movements. - -use std::ops::Range; - -use unicode_segmentation::UnicodeSegmentation; - -use crate::kurbo::Point; -use crate::piet::TextLayout as _; -use crate::text::{ - EditableText, Movement, Selection, TextLayout, TextStorage, VerticalMovement, WritingDirection, -}; - -/// Compute the result of a [`Movement`] on a [`Selection`]. -/// -/// returns a new selection representing the state after the movement. -/// -/// If `modify` is true, only the 'active' edge (the `end`) of the selection -/// should be changed; this is the case when the user moves with the shift -/// key pressed. -pub fn movement( - m: Movement, - s: Selection, - layout: &TextLayout, - modify: bool, -) -> Selection { - let (text, layout) = match (layout.text(), layout.layout()) { - (Some(text), Some(layout)) => (text, layout), - _ => { - debug_assert!(false, "movement() called before layout rebuild"); - return s; - } - }; - - let writing_direction = if crate::piet::util::first_strong_rtl(text.as_str()) { - WritingDirection::RightToLeft - } else { - WritingDirection::LeftToRight - }; - - let (offset, h_pos) = match m { - Movement::Grapheme(d) if d.is_upstream_for_direction(writing_direction) => { - if s.is_caret() || modify { - text.prev_grapheme_offset(s.active) - .map(|off| (off, None)) - .unwrap_or((0, s.h_pos)) - } else { - (s.min(), None) - } - } - Movement::Grapheme(_) => { - if s.is_caret() || modify { - text.next_grapheme_offset(s.active) - .map(|off| (off, None)) - .unwrap_or((s.active, s.h_pos)) - } else { - (s.max(), None) - } - } - Movement::Vertical(VerticalMovement::LineUp) => { - let cur_pos = layout.hit_test_text_position(s.active); - let h_pos = s.h_pos.unwrap_or(cur_pos.point.x); - if cur_pos.line == 0 { - (0, Some(h_pos)) - } else { - let lm = layout.line_metric(cur_pos.line).unwrap(); - let point_above = Point::new(h_pos, cur_pos.point.y - lm.height); - let up_pos = layout.hit_test_point(point_above); - if up_pos.is_inside { - (up_pos.idx, Some(h_pos)) - } else { - // because we can't specify affinity, moving up when h_pos - // is wider than both the current line and the previous line - // can result in a cursor position at the visual start of the - // current line; so we handle this as a special-case. - let lm_prev = layout.line_metric(cur_pos.line.saturating_sub(1)).unwrap(); - let up_pos = lm_prev.end_offset - lm_prev.trailing_whitespace; - (up_pos, Some(h_pos)) - } - } - } - Movement::Vertical(VerticalMovement::LineDown) => { - let cur_pos = layout.hit_test_text_position(s.active); - let h_pos = s.h_pos.unwrap_or(cur_pos.point.x); - if cur_pos.line == layout.line_count() - 1 { - (text.len(), Some(h_pos)) - } else { - let lm = layout.line_metric(cur_pos.line).unwrap(); - // may not work correctly for point sizes below 1.0 - let y_below = lm.y_offset + lm.height + 1.0; - let point_below = Point::new(h_pos, y_below); - let up_pos = layout.hit_test_point(point_below); - (up_pos.idx, Some(point_below.x)) - } - } - Movement::Vertical(VerticalMovement::DocumentStart) => (0, None), - Movement::Vertical(VerticalMovement::DocumentEnd) => (text.len(), None), - - Movement::ParagraphStart => (text.preceding_line_break(s.active), None), - Movement::ParagraphEnd => (text.next_line_break(s.active), None), - - Movement::Line(d) => { - let hit = layout.hit_test_text_position(s.active); - let lm = layout.line_metric(hit.line).unwrap(); - let offset = if d.is_upstream_for_direction(writing_direction) { - lm.start_offset - } else { - lm.end_offset - lm.trailing_whitespace - }; - (offset, None) - } - Movement::Word(d) if d.is_upstream_for_direction(writing_direction) => { - let offset = if s.is_caret() || modify { - text.prev_word_offset(s.active).unwrap_or(0) - } else { - s.min() - }; - (offset, None) - } - Movement::Word(_) => { - let offset = if s.is_caret() || modify { - text.next_word_offset(s.active).unwrap_or(s.active) - } else { - s.max() - }; - (offset, None) - } - - // These two are not handled; they require knowledge of the size - // of the viewport. - Movement::Vertical(VerticalMovement::PageDown) - | Movement::Vertical(VerticalMovement::PageUp) => (s.active, s.h_pos), - other => { - tracing::warn!("unhandled movement {:?}", other); - (s.anchor, s.h_pos) - } - }; - - let start = if modify { s.anchor } else { offset }; - Selection::new(start, offset).with_h_pos(h_pos) -} - -/// Given a position in some text, return the containing word boundaries. -/// -/// The returned range may not necessary be a 'word'; for instance it could be -/// the sequence of whitespace between two words. -/// -/// If the position is on a word boundary, that will be considered the start -/// of the range. -/// -/// This uses Unicode word boundaries, as defined in [UAX#29]. -/// -/// [UAX#29]: http://www.unicode.org/reports/tr29/ -pub(crate) fn word_range_for_pos(text: &str, pos: usize) -> Range { - text.split_word_bound_indices() - .map(|(ix, word)| ix..(ix + word.len())) - .find(|range| range.contains(&pos)) - .unwrap_or(pos..pos) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn word_range_simple() { - assert_eq!(word_range_for_pos("hello world", 3), 0..5); - assert_eq!(word_range_for_pos("hello world", 8), 6..11); - } - - #[test] - fn word_range_whitespace() { - assert_eq!(word_range_for_pos("hello world", 5), 5..6); - } - - #[test] - fn word_range_rtl() { - let rtl = "مرحبا بالعالم"; - assert_eq!(word_range_for_pos(rtl, 5), 0..10); - assert_eq!(word_range_for_pos(rtl, 16), 11..25); - assert_eq!(word_range_for_pos(rtl, 10), 10..11); - } - - #[test] - fn word_range_mixed() { - let mixed = "hello مرحبا بالعالم world"; - assert_eq!(word_range_for_pos(mixed, 3), 0..5); - assert_eq!(word_range_for_pos(mixed, 8), 6..16); - assert_eq!(word_range_for_pos(mixed, 19), 17..31); - assert_eq!(word_range_for_pos(mixed, 36), 32..37); - } -} diff --git a/src/text/rich_text.rs b/src/text/rich_text.rs deleted file mode 100644 index 3f48915c..00000000 --- a/src/text/rich_text.rs +++ /dev/null @@ -1,231 +0,0 @@ -// This software is licensed under Apache License 2.0 and distributed on an -// "as-is" basis without warranties of any kind. See the LICENSE file for -// details. - -//! Rich text with style spans. - -use std::ops::{Range, RangeBounds}; -use std::sync::Arc; - -use super::attribute::Link; -use super::{Attribute, AttributeSpans, FontDescriptor, TextStorage}; -use crate::piet::{ - util, Color, FontFamily, FontStyle, FontWeight, PietTextLayoutBuilder, TextLayoutBuilder, - TextStorage as PietTextStorage, -}; -use crate::ArcStr; - -/// Text with optional style spans. -#[derive(Clone, Debug)] -pub struct RichText { - buffer: ArcStr, - attrs: Arc, - links: Arc<[Link]>, -} - -impl RichText { - /// Create a new `RichText` object with the provided text. - pub fn new(buffer: ArcStr) -> Self { - RichText::new_with_attributes(buffer, Default::default()) - } - - /// Create a new `RichText`, providing explicit attributes. - pub fn new_with_attributes(buffer: ArcStr, attributes: AttributeSpans) -> Self { - RichText { - buffer, - attrs: Arc::new(attributes), - links: Arc::new([]), - } - } - - /// Builder-style method for adding an [`Attribute`] to a range of text. - /// - /// [`Attribute`]: enum.Attribute.html - pub fn with_attribute(mut self, range: impl RangeBounds, attr: Attribute) -> Self { - self.add_attribute(range, attr); - self - } - - /// The length of the buffer, in utf8 code units. - pub fn len(&self) -> usize { - self.buffer.len() - } - - /// Returns `true` if the underlying buffer is empty. - pub fn is_empty(&self) -> bool { - self.buffer.is_empty() - } - - /// Add an [`Attribute`] to the provided range of text. - /// - /// [`Attribute`]: enum.Attribute.html - pub fn add_attribute(&mut self, range: impl RangeBounds, attr: Attribute) { - let range = util::resolve_range(range, self.buffer.len()); - Arc::make_mut(&mut self.attrs).add(range, attr); - } -} - -impl PietTextStorage for RichText { - fn as_str(&self) -> &str { - self.buffer.as_str() - } -} - -impl TextStorage for RichText { - fn add_attributes(&self, mut builder: PietTextLayoutBuilder) -> PietTextLayoutBuilder { - for (range, attr) in self.attrs.to_piet_attrs() { - builder = builder.range_attribute(range, attr); - } - builder - } - - fn links(&self) -> &[Link] { - &self.links - } - - fn maybe_eq(&self, other: &Self) -> bool { - Arc::ptr_eq(&self.buffer, &other.buffer) - && Arc::ptr_eq(&self.attrs, &other.attrs) - && Arc::ptr_eq(&self.links, &other.links) - } -} - -/// A builder for creating [`RichText`] objects. -/// -/// This builder allows you to construct a [`RichText`] object by building up a sequence -/// of styled sub-strings; first you [`push`](RichTextBuilder::push) a `&str` onto the string, -/// and then you can optionally add styles to that text via the returned [`AttributesAdder`] -/// object. -/// -/// # Example -/// ``` -/// # use masonry::text::{Attribute, RichTextBuilder}; -/// # use masonry::Color; -/// # use masonry::piet::FontWeight; -/// let mut builder = RichTextBuilder::new(); -/// builder.push("Hello "); -/// builder.push("World!").weight(FontWeight::BOLD); -/// -/// // Can also use write! -/// write!(builder, "Here is your number: {}", 1).underline(true).text_color(Color::RED); -/// -/// let rich_text = builder.build(); -/// ``` -/// -/// [`RichText`]: RichText -#[derive(Default)] -pub struct RichTextBuilder { - buffer: String, - attrs: AttributeSpans, - links: Vec, -} - -impl RichTextBuilder { - /// Create a new `RichTextBuilder`. - pub fn new() -> Self { - Self::default() - } - - /// Append a `&str` to the end of the text. - /// - /// This method returns a [`AttributesAdder`] that can be used to style the newly - /// added string slice. - pub fn push(&mut self, string: &str) -> AttributesAdder { - let range = self.buffer.len()..(self.buffer.len() + string.len()); - self.buffer.push_str(string); - self.add_attributes_for_range(range) - } - - /// Glue for usage of the write! macro. - /// - /// This method should generally not be invoked manually, but rather through the write! macro itself. - #[doc(hidden)] - pub fn write_fmt(&mut self, fmt: std::fmt::Arguments<'_>) -> AttributesAdder { - use std::fmt::Write; - let start = self.buffer.len(); - self.buffer - .write_fmt(fmt) - .expect("a formatting trait implementation returned an error"); - self.add_attributes_for_range(start..self.buffer.len()) - } - - /// Get an [`AttributesAdder`] for the given range. - /// - /// This can be used to modify styles for a given range after it has been added. - pub fn add_attributes_for_range(&mut self, range: impl RangeBounds) -> AttributesAdder { - let range = util::resolve_range(range, self.buffer.len()); - AttributesAdder { - rich_text_builder: self, - range, - } - } - - /// Build the `RichText`. - pub fn build(self) -> RichText { - RichText { - buffer: self.buffer.into(), - attrs: self.attrs.into(), - links: self.links.into(), - } - } -} - -/// Adds Attributes to the text. -/// -/// See also: [`RichTextBuilder`](RichTextBuilder) -pub struct AttributesAdder<'a> { - rich_text_builder: &'a mut RichTextBuilder, - range: Range, -} - -impl AttributesAdder<'_> { - /// Add the given attribute. - pub fn add_attr(&mut self, attr: Attribute) -> &mut Self { - self.rich_text_builder.attrs.add(self.range.clone(), attr); - self - } - - /// Add a font size attribute. - pub fn size(&mut self, size: impl Into) -> &mut Self { - self.add_attr(Attribute::size(size)); - self - } - - /// Add a forground color attribute. - pub fn text_color(&mut self, color: impl Into) -> &mut Self { - self.add_attr(Attribute::text_color(color)); - self - } - - /// Add a font family attribute. - pub fn font_family(&mut self, family: FontFamily) -> &mut Self { - self.add_attr(Attribute::font_family(family)); - self - } - - /// Add a `FontWeight` attribute. - pub fn weight(&mut self, weight: FontWeight) -> &mut Self { - self.add_attr(Attribute::weight(weight)); - self - } - - /// Add a `FontStyle` attribute. - pub fn style(&mut self, style: FontStyle) -> &mut Self { - self.add_attr(Attribute::style(style)); - self - } - - /// Add a underline attribute. - pub fn underline(&mut self, underline: bool) -> &mut Self { - self.add_attr(Attribute::underline(underline)); - self - } - - /// Add a `FontDescriptor` attribute. - pub fn font_descriptor(&mut self, font: impl Into) -> &mut Self { - self.add_attr(Attribute::font_descriptor(font)); - self - } - - //pub fn link(&mut self, command: impl Into) -> &mut Self; -} diff --git a/src/text/storage.rs b/src/text/storage.rs deleted file mode 100644 index d63d3812..00000000 --- a/src/text/storage.rs +++ /dev/null @@ -1,63 +0,0 @@ -// This software is licensed under Apache License 2.0 and distributed on an -// "as-is" basis without warranties of any kind. See the LICENSE file for -// details. - -//! Storing text. - -use std::sync::Arc; - -use super::attribute::Link; -use crate::piet::{PietTextLayoutBuilder, TextStorage as PietTextStorage}; - -/// A type that represents text that can be displayed. -pub trait TextStorage: PietTextStorage + Clone { - /// If this TextStorage object manages style spans, it should implement - /// this method and update the provided builder with its spans, as required. - #[allow(unused_variables)] - fn add_attributes(&self, builder: PietTextLayoutBuilder) -> PietTextLayoutBuilder { - builder - } - - /// Any additional [`Link`] attributes on this text. - /// - /// If this `TextStorage` object manages link attributes, it should implement this - /// method and return any attached [`Link`]s. - /// - /// Unlike other attributes, links are managed in Masonry, not in [`piet`]; as such they - /// require a separate API. - /// - /// [`Link`]: super::attribute::Link - /// [`piet`]: https://docs.rs/piet - fn links(&self) -> &[Link] { - &[] - } - - /// Determines quickly whether two text objects have the same content. - /// - /// To allow for faster checks, this method is allowed to return false negatives. - fn maybe_eq(&self, other: &Self) -> bool; -} - -/// A reference counted string slice. -/// -/// This is a data-friendly way to represent strings in Masonry. Unlike `String` -/// it cannot be mutated, but unlike `String` it can be cheaply cloned. -pub type ArcStr = Arc; - -impl TextStorage for ArcStr { - fn maybe_eq(&self, other: &Self) -> bool { - self == other - } -} - -impl TextStorage for String { - fn maybe_eq(&self, other: &Self) -> bool { - self == other - } -} - -impl TextStorage for Arc { - fn maybe_eq(&self, other: &Self) -> bool { - self == other - } -} diff --git a/src/widget/mod.rs b/src/widget/mod.rs index 4b9d4857..cc58205f 100644 --- a/src/widget/mod.rs +++ b/src/widget/mod.rs @@ -25,7 +25,6 @@ mod scroll_bar; mod sized_box; mod spinner; mod split; -mod textbox; pub use self::image::Image; pub use align::Align; @@ -44,13 +43,9 @@ pub use widget_ref::WidgetRef; pub use widget_state::WidgetState; pub use sized_box::BackgroundBrush; -//pub use textbox::TextBox; pub use widget::StoreInWidgetMut; #[doc(hidden)] pub use widget::{Widget, WidgetId}; -//#[doc(hidden)] -//pub use widget_ext::WidgetExt; -//pub use widget_wrapper::WidgetWrapper; /// Methods by which a widget can attempt to change focus state. #[derive(Debug, Clone, Copy)] diff --git a/src/widget/textbox.rs b/src/widget/textbox.rs deleted file mode 100644 index 407eef23..00000000 --- a/src/widget/textbox.rs +++ /dev/null @@ -1,807 +0,0 @@ -// NOPE DON'T COMMIT - -/* -// This software is licensed under Apache License 2.0 and distributed on an -// "as-is" basis without warranties of any kind. See the LICENSE file for -// details. - -//! A textbox widget. - -use std::sync::Arc; -use std::time::Duration; - -use smallvec::{smallvec, SmallVec}; -use tracing::{trace_span, Span}; -use vello::Scene; - -use crate::action::Action; -use crate::kurbo::{Affine, Insets}; -use crate::shell::{HotKey, KeyEvent, SysMods, TimerToken}; -use crate::text::{ImeInvalidation, Selection, TextAlignment, TextComponent, TextLayout}; -use crate::widget::{Portal, WidgetMut, WidgetRef}; -use crate::{ - theme, ArcStr, BoxConstraints, Command, Event, EventCtx, LayoutCtx, LifeCycle, LifeCycleCtx, - PaintCtx, Point, Rect, Size, StatusChange, Vec2, Widget, WidgetPod, -}; -use druid_shell::piet::TextLayout as _; - -const CURSOR_BLINK_DURATION: Duration = Duration::from_millis(500); -const MAC_OR_LINUX: bool = cfg!(any(target_os = "macos", target_os = "linux")); - -// TODO - Implement formatters (TextBox where the text represents a value of some other type). - -// TODO -#[allow(dead_code)] -/// When we scroll after editing or movement, we show a little extra of the document. -const SCROLL_TO_INSETS: Insets = Insets::uniform_xy(40.0, 0.0); - -/// A widget that allows user text input. -pub struct TextBox { - placeholder_text: ArcStr, - placeholder_layout: TextLayout, - // TODO - rename inner - // TODO - Add padding - inner: WidgetPod>>>, - scroll_to_selection_after_layout: bool, - multiline: bool, - /// true if a click event caused us to gain focus. - /// - /// On macOS, if focus happens via click then we set the selection based - /// on the click position; if focus happens automatically (e.g. on tab) - /// then we select our entire contents. - was_focused_from_click: bool, - cursor_on: bool, - cursor_timer: TimerToken, - /// if `true` (the default), this textbox will attempt to change focus on tab. - /// - /// You can override this in a controller if you want to customize tab - /// behaviour. - pub handles_tab_notifications: bool, - // TODO - #[allow(dead_code)] - text_pos: Point, -} -crate::declare_widget!(TextBoxMut, TextBox); - -impl TextBox { - /// Create a new TextBox widget. - pub fn new(initial_text: impl Into) -> Self { - let placeholder_text = ArcStr::from(""); - let mut placeholder_layout = TextLayout::new(); - placeholder_layout.set_text_color(theme::PLACEHOLDER_COLOR); - placeholder_layout.set_text(placeholder_text.clone()); - - let text_component = TextComponent::new(Arc::new(initial_text.into())); - let scroll = Portal::new(text_component).content_must_fill(true); - //TODO - //scroll.set_enabled_scrollbars(crate::scroll_component::ScrollbarsEnabled::None); - Self { - inner: WidgetPod::new(scroll), - scroll_to_selection_after_layout: false, - placeholder_text, - placeholder_layout, - multiline: false, - was_focused_from_click: false, - cursor_on: false, - cursor_timer: TimerToken::INVALID, - handles_tab_notifications: true, - text_pos: Point::ZERO, - } - } - - /// Create a new multi-line `TextBox`. - pub fn multiline(initial_text: impl Into) -> Self { - let mut this = TextBox::new(initial_text); - //TODO - //this.inner.set_enabled_scrollbars(crate::scroll_component::ScrollbarsEnabled::Both); - //this.text_mut().borrow_mut().set_accepts_newlines(true); - //this.inner.set_horizontal_scroll_enabled(false); - this.multiline = true; - this - } - - // TODO - #[cfg(FALSE)] - /// If `true` (and this is a [`multiline`] text box) lines will be wrapped - /// at the maximum layout width. - /// - /// If `false`, lines will not be wrapped, and horizontal scrolling will - /// be enabled. - /// - /// [`multiline`]: TextBox::multiline - pub fn with_line_wrapping(mut self, wrap_lines: bool) -> Self { - self.inner.set_horizontal_scroll_enabled(!wrap_lines); - self - } -} - -// TODO -#[cfg(FALSE)] -impl TextBox { - /// Builder-style method for setting the text size. - /// - /// The argument can be either an `f64` or a [`Key`]. - /// - /// [`Key`]: ../struct.Key.html - pub fn with_text_size(mut self, size: impl Into>) -> Self { - self.set_text_size(size); - self - } - - /// Builder-style method to set the [`TextAlignment`]. - /// - /// This is only relevant when the `TextBox` is *not* [`multiline`], - /// in which case it determines how the text is positioned inside the - /// `TextBox` when it does not fill the available space. - /// - /// # Note: - /// - /// This does not behave exactly like [`TextAlignment`] does when used - /// with label; in particular this does not account for reading direction. - /// This means that `TextAlignment::Start` (the default) always means - /// *left aligned*, and `TextAlignment::End` always means *right aligned*. - /// - /// This should be considered a bug, but it will not be fixed until proper - /// BiDi support is implemented. - /// - /// [`TextAlignment`]: enum.TextAlignment.html - /// [`multiline`]: #method.multiline - pub fn with_text_alignment(mut self, alignment: TextAlignment) -> Self { - self.set_text_alignment(alignment); - self - } - - /// Builder-style method for setting the font. - pub fn with_font(mut self, font: FontDescriptor) -> Self { - self.set_font(font); - self - } - - /// Builder-style method for setting the text color. - /// - /// The argument can be either a `Color` or a [`Key`]. - /// - /// [`Key`]: ../struct.Key.html - pub fn with_text_color(mut self, color: impl Into>) -> Self { - self.set_text_color(color); - self - } - - /// Set the text size. - /// - /// The argument can be either an `f64` or a [`Key`]. - /// - /// [`Key`]: ../struct.Key.html - pub fn set_text_size(&mut self, size: impl Into>) { - if !self.inner.as_ref().child().can_write() { - tracing::warn!("set_text_size called with IME lock held."); - return; - } - - let size = size.into(); - self.text_mut() - .borrow_mut() - .layout - .set_text_size(size.clone()); - self.placeholder_layout.set_text_size(size); - } - - /// Set the font. - pub fn set_font(&mut self, font: FontDescriptor) { - if !self.inner.as_ref().child().can_write() { - tracing::warn!("set_font called with IME lock held."); - return; - } - self.text_mut().borrow_mut().layout.set_font(font.clone()); - self.placeholder_layout.set_font(font); - } - - /// Set the [`TextAlignment`] for this `TextBox``. - /// - /// This is only relevant when the `TextBox` is *not* [`multiline`], - /// in which case it determines how the text is positioned inside the - /// `TextBox` when it does not fill the available space. - /// - /// # Note: - /// - /// This does not behave exactly like [`TextAlignment`] does when used - /// with label; in particular this does not account for reading direction. - /// This means that `TextAlignment::Start` (the default) always means - /// *left aligned*, and `TextAlignment::End` always means *right aligned*. - /// - /// This should be considered a bug, but it will not be fixed until proper - /// BiDi support is implemented. - /// - /// [`TextAlignment`]: enum.TextAlignment.html - /// [`multiline`]: #method.multiline - pub fn set_text_alignment(&mut self, alignment: TextAlignment) { - if !self.inner.as_ref().child().can_write() { - tracing::warn!("set_text_alignment called with IME lock held."); - return; - } - self.text_mut().borrow_mut().set_text_alignment(alignment); - } - - /// Set the text color. - /// - /// The argument can be either a `Color` or a [`Key`]. - /// - /// If you change this property, you are responsible for calling - /// [`request_layout`] to ensure the label is updated. - /// - /// [`request_layout`]: ../struct.EventCtx.html#method.request_layout - /// [`Key`]: ../struct.Key.html - pub fn set_text_color(&mut self, color: impl Into>) { - if !self.inner.as_ref().child().can_write() { - tracing::warn!("set_text_color calld with IME lock held."); - return; - } - self.text_mut().borrow_mut().layout.set_text_color(color); - } - - /// The point, relative to the origin, where this text box draws its - /// [`TextLayout`]. - /// - /// This is exposed in case the user wants to do additional drawing based - /// on properties of the text. - /// - /// This is not valid until `layout` has been called. - pub fn text_position(&self) -> Point { - self.text_pos - } -} - -impl TextBox { - /// Builder-style method to set the `TextBox`'s placeholder text. - pub fn with_placeholder(mut self, placeholder: impl Into) -> Self { - self.set_placeholder(placeholder); - self - } - - // TODO - /// Set the `TextBox`'s placeholder text. - fn set_placeholder(&mut self, placeholder: impl Into) { - self.placeholder_text = placeholder.into(); - self.placeholder_layout - .set_text(self.placeholder_text.clone()); - } -} - -impl TextBox { - // TODO - Return &str - /// Return the box's current contents. - pub fn text(&self) -> String { - self.inner - .as_ref() - .child() - .borrow() - .layout - .text() - .map(|txt| txt.as_str()) - .unwrap_or("") - .to_string() - } - - fn text_len(&self) -> usize { - self.inner.as_ref().child().borrow().layout.text_len() - } - - fn reset_cursor_blink(&mut self, token: TimerToken) { - self.cursor_on = true; - self.cursor_timer = token; - } - - fn should_draw_cursor(&self) -> bool { - if cfg!(target_os = "macos") && self.inner.as_ref().child().can_read() { - self.cursor_on && self.inner.as_ref().child().borrow().selection().is_caret() - } else { - self.cursor_on - } - } -} - -impl<'a, 'b> TextBoxMut<'a, 'b> { - pub fn inner_mut(&mut self) -> WidgetMut<'_, 'b, Portal>>> { - self.ctx.get_mut(&mut self.widget.inner) - } - - pub fn set_text(&mut self, new_text: impl Into) { - self.inner_mut().child_mut().set_text(new_text.into()); - } -} - -impl TextBox { - fn rect_for_selection_end(&self) -> Rect { - // TODO - let child = self.inner.as_ref(); - let child = child.child(); - let text = child.borrow(); - let layout = text.layout.layout().unwrap(); - - let hit = layout.hit_test_text_position(text.selection().active); - let line = layout.line_metric(hit.line).unwrap(); - let y0 = line.y_offset; - let y1 = y0 + line.height; - let x = hit.point.x; - - Rect::new(x, y0, x, y1) - } - - #[cfg(FALSE)] - fn scroll_to_selection_end(&mut self) { - let rect = self.rect_for_selection_end(); - let view_rect = self.inner.viewport_rect(); - let is_visible = - view_rect.contains(rect.origin()) && view_rect.contains(Point::new(rect.x1, rect.y1)); - if !is_visible { - self.inner.scroll_to(rect + SCROLL_TO_INSETS); - } - } - - /// These commands may be supplied by menus; but if they aren't, we - /// inject them again, here. - fn fallback_do_builtin_command( - &mut self, - ctx: &mut EventCtx, - key: &KeyEvent, - ) -> Option { - let our_id = ctx.widget_id(); - match key { - key if HotKey::new(SysMods::Cmd, "c").matches(key) => { - Some(crate::command::COPY.to(our_id)) - } - key if HotKey::new(SysMods::Cmd, "x").matches(key) => { - Some(crate::command::CUT.to(our_id)) - } - // we have to send paste to the window, in order to get it converted into the `Paste` - // event - key if HotKey::new(SysMods::Cmd, "v").matches(key) => { - Some(crate::command::PASTE.to(ctx.window_id())) - } - key if HotKey::new(SysMods::Cmd, "z").matches(key) => { - Some(crate::command::UNDO.to(our_id)) - } - key if HotKey::new(SysMods::CmdShift, "Z").matches(key) && !cfg!(windows) => { - Some(crate::command::REDO.to(our_id)) - } - key if HotKey::new(SysMods::Cmd, "y").matches(key) && cfg!(windows) => { - Some(crate::command::REDO.to(our_id)) - } - key if HotKey::new(SysMods::Cmd, "a").matches(key) => { - Some(crate::command::SELECT_ALL.to(our_id)) - } - _ => None, - } - } -} - -impl Widget for TextBox { - fn on_event(&mut self, ctx: &mut EventCtx, event: &Event) { - match event { - Event::Notification(cmd) => match cmd { - cmd if cmd.is(TextComponent::SCROLL_TO) => { - let after_edit = *cmd.try_get(TextComponent::SCROLL_TO).unwrap(); - if after_edit { - ctx.request_layout(); - self.scroll_to_selection_after_layout = true; - } else { - let selection_end = self.rect_for_selection_end(); - let mut child = ctx.get_mut(&mut self.inner); - child.pan_viewport_to(selection_end); - } - ctx.set_handled(); - ctx.request_paint(); - } - cmd if cmd.is(TextComponent::TAB) && self.handles_tab_notifications => { - ctx.focus_next(); - ctx.request_paint(); - ctx.set_handled(); - } - cmd if cmd.is(TextComponent::BACKTAB) && self.handles_tab_notifications => { - ctx.focus_prev(); - ctx.request_paint(); - ctx.set_handled(); - } - cmd if cmd.is(TextComponent::CANCEL) => { - ctx.resign_focus(); - ctx.request_paint(); - ctx.set_handled(); - } - cmd if cmd.is(TextComponent::TEXT_CHANGED) => { - // TODO - remove clones - let text = cmd.try_get(TextComponent::TEXT_CHANGED).unwrap(); - ctx.submit_action(Action::TextChanged(text.clone())); - ctx.set_handled(); - } - cmd if cmd.is(TextComponent::RETURN) => { - // TODO - remove clones - let text = cmd.try_get(TextComponent::RETURN).unwrap(); - ctx.submit_action(Action::TextEntered(text.clone())); - ctx.set_handled(); - } - _ => (), - }, - Event::KeyDown(key) if !self.inner.as_ref().child().is_composing() => { - if let Some(cmd) = self.fallback_do_builtin_command(ctx, key) { - ctx.submit_command(cmd); - ctx.set_handled(); - } - } - Event::MouseDown(mouse) if self.inner.as_ref().child().can_write() => { - if !ctx.is_disabled() { - if !mouse.focus { - ctx.request_focus(); - self.was_focused_from_click = true; - self.reset_cursor_blink(ctx.request_timer(CURSOR_BLINK_DURATION)); - } else { - ctx.set_handled(); - } - } - } - Event::Timer(id) => { - if !ctx.is_disabled() { - if *id == self.cursor_timer && ctx.has_focus() { - self.cursor_on = !self.cursor_on; - ctx.request_paint(); - self.cursor_timer = ctx.request_timer(CURSOR_BLINK_DURATION); - } - } else if self.cursor_on { - self.cursor_on = false; - ctx.request_paint(); - } - } - Event::ImeStateChange => { - self.reset_cursor_blink(ctx.request_timer(CURSOR_BLINK_DURATION)); - // TODO - external_text_change.is_some() - } - Event::Command(ref cmd) - if !self.inner.as_ref().child().is_composing() - && ctx.is_focused() - && cmd.is(crate::command::COPY) => - { - self.inner.as_ref().child().borrow().set_clipboard(); - ctx.set_handled(); - } - Event::Command(cmd) - if !self.inner.as_ref().child().is_composing() - && ctx.is_focused() - && cmd.is(crate::command::CUT) => - { - // TODO - #[cfg(FALSE)] - if self.text().borrow().set_clipboard() { - let inval = self.text_mut().borrow_mut().insert_text(data, ""); - ctx.invalidate_text_input(inval); - } - ctx.set_handled(); - } - Event::Command(cmd) - if !self.inner.as_ref().child().is_composing() - && ctx.is_focused() - && cmd.is(crate::command::SELECT_ALL) => - { - // TODO - #[cfg(FALSE)] - if let Some(inval) = self - .text_mut() - .borrow_mut() - .set_selection(Selection::new(0, data.as_str().len())) - { - ctx.invalidate_text_input(inval); - } - ctx.set_handled(); - } - Event::Paste(ref item) if self.inner.as_ref().child().can_write() => { - if let Some(string) = item.get_string() { - let _text = if self.multiline { - &string - } else { - string.lines().next().unwrap_or("") - }; - // TODO - #[cfg(FALSE)] - if !text.is_empty() { - let inval = self.text_mut().borrow_mut().insert_text(data, text); - ctx.invalidate_text_input(inval); - } - } - } - _ => (), - } - self.inner.on_event(ctx, event) - } - - fn on_status_change(&mut self, ctx: &mut LifeCycleCtx, event: &StatusChange) { - match event { - StatusChange::FocusChanged(true) => { - // TODO - #[cfg(FALSE)] - if self.text().can_write() && !self.multiline && !self.was_focused_from_click { - let selection = Selection::new(0, data.len()); - let _ = self.text_mut().borrow_mut().set_selection(selection); - ctx.invalidate_text_input(ImeInvalidation::SelectionChanged); - } - - { - let mut child = ctx.get_mut(&mut self.inner); - child.child_mut().set_focused(true); - } - self.reset_cursor_blink(ctx.request_timer(CURSOR_BLINK_DURATION)); - self.was_focused_from_click = false; - ctx.request_paint(); - } - StatusChange::FocusChanged(false) => { - if self.inner.as_ref().child().can_write() && MAC_OR_LINUX && !self.multiline { - let selection = self.inner.as_ref().child().borrow().selection(); - let selection = Selection::new(selection.active, selection.active); - let _ = self - .inner - .as_ref() - .child() - .borrow_mut() - .set_selection(selection); - ctx.invalidate_text_input(ImeInvalidation::SelectionChanged); - } - - { - let mut child = ctx.get_mut(&mut self.inner); - child.child_mut().set_focused(false); - if !self.multiline { - // TODO - remove? - child.pan_viewport_to(Rect::ZERO); - } - } - - self.cursor_timer = TimerToken::INVALID; - self.was_focused_from_click = false; - ctx.request_paint(); - } - _ => (), - } - } - - fn lifecycle(&mut self, ctx: &mut LifeCycleCtx, event: &LifeCycle) { - match event { - LifeCycle::WidgetAdded => { - ctx.register_text_input(self.inner.as_ref().child().input_handler()); - } - LifeCycle::BuildFocusChain => { - //TODO: make this a configurable option? maybe? - ctx.register_for_focus(); - } - _ => (), - } - self.inner.lifecycle(ctx, event); - } - - fn layout(&mut self, ctx: &mut LayoutCtx, bc: &BoxConstraints) -> Size { - if !self.inner.as_ref().child().can_write() { - tracing::warn!("Widget::layout called with outstanding IME lock."); - } - let min_width = theme::WIDE_WIDGET_WIDTH; - let textbox_insets = theme::TEXTBOX_INSETS; - - self.placeholder_layout.rebuild_if_needed(ctx.text()); - let min_size = bc.constrain((min_width, 0.0)); - let child_bc = BoxConstraints::new(min_size, bc.max()); - - let mut size = self.inner.layout(ctx, &child_bc); - ctx.place_child(&mut self.inner, Point::ORIGIN); - - let text_metrics = if !self.inner.as_ref().child().can_read() || self.text_len() == 0 { - self.placeholder_layout.layout_metrics() - } else { - self.inner.as_ref().child().borrow().layout.layout_metrics() - }; - - let _layout_baseline = text_metrics.size.height - text_metrics.first_baseline; - let baseline_off = 0.0; - // = layout_baseline - (self.inner.child_size().height - self.inner.viewport_rect().height()) + textbox_insets.y1; - ctx.set_baseline_offset(baseline_off); - if self.scroll_to_selection_after_layout { - // TODO - //self.scroll_to_selection_end(); - self.scroll_to_selection_after_layout = false; - } - - size.width += textbox_insets.x0 + textbox_insets.x1; - size.height += textbox_insets.y0 + textbox_insets.y1; - size - } - - fn paint(&mut self, ctx: &mut PaintCtx, scene: &mut Scene) { - if !self.inner.as_ref().child().can_read() { - tracing::warn!("Widget::paint called with outstanding IME lock, skipping"); - return; - } - let size = ctx.size(); - let background_color = theme::BACKGROUND_LIGHT; - let cursor_color = theme::CURSOR_COLOR; - let border_width = theme::TEXTBOX_BORDER_WIDTH; - let textbox_insets = theme::TEXTBOX_INSETS; - - let is_focused = ctx.is_focused(); - - let border_color = if is_focused { - theme::PRIMARY_LIGHT - } else { - theme::BORDER_DARK - }; - - // Paint the background - let clip_rect = size - .to_rect() - .inset(-border_width / 2.0) - .to_rounded_rect(theme::TEXTBOX_BORDER_RADIUS); - - ctx.fill(clip_rect, &background_color); - - if self.text_len() != 0 { - let padding_offset = Vec2::new(textbox_insets.x0, textbox_insets.y0); - ctx.with_save(|ctx| { - ctx.transform(Affine::translate(padding_offset)); - self.inner.paint(ctx, scene); - }) - } else { - ctx.skip_child(&mut self.inner); - - let text_width = self.placeholder_layout.layout_metrics().size.width; - let extra_width = (size.width - text_width - textbox_insets.x_value()).max(0.); - let alignment = self.inner.as_ref().child().borrow().text_alignment(); - // alignment is only used for single-line text boxes - let x_offset = if self.multiline { - 0.0 - } else { - x_offset_for_extra_width(alignment, extra_width) - }; - - // clip when we draw the placeholder, since it isn't in a clipbox - ctx.with_save(|ctx| { - ctx.clip(clip_rect); - self.placeholder_layout - .draw(ctx, (textbox_insets.x0 + x_offset, textbox_insets.y0)); - }) - } - - // Paint the cursor if focused and there's no selection - if is_focused && self.should_draw_cursor() { - // if there's no data, we always draw the cursor based on - // our alignment. - let cursor_pos = self.inner.as_ref().child().borrow().selection().active; - let cursor_line = self - .inner - .as_ref() - .child() - .borrow() - .cursor_line_for_text_position(cursor_pos); - - let padding_offset = Vec2::new(textbox_insets.x0, textbox_insets.y0); - - let mut cursor = if self.text_len() == 0 { - cursor_line + padding_offset - } else { - cursor_line + padding_offset - self.inner.as_ref().get_viewport_pos().to_vec2() - }; - - // Snap the cursor to the pixel grid so it stays sharp. - cursor.p0.x = cursor.p0.x.trunc() + 0.5; - cursor.p1.x = cursor.p0.x; - - ctx.with_save(|ctx| { - ctx.clip(clip_rect); - ctx.stroke(cursor, &cursor_color, 1.); - }) - } - - // Paint the border - ctx.stroke(clip_rect, &border_color, border_width); - } - - fn children(&self) -> SmallVec<[WidgetRef<'_, dyn Widget>; 16]> { - smallvec![self.inner.as_dyn()] - } - - fn make_trace_span(&self) -> Span { - trace_span!("TextBox") - } -} - -fn x_offset_for_extra_width(alignment: TextAlignment, extra_width: f64) -> f64 { - match alignment { - TextAlignment::Start | TextAlignment::Justified => 0.0, - TextAlignment::End => extra_width, - TextAlignment::Center => extra_width / 2.0, - } -} - -#[cfg(test)] -mod tests { - use insta::assert_debug_snapshot; - - use super::*; - use crate::action::Action; - use crate::assert_render_snapshot; - use crate::testing::{widget_ids, TestHarness, TestWidgetExt as _}; - - #[test] - fn simple_textbox() { - let [textbox_id] = widget_ids(); - let textbox = TextBox::new("Hello").with_id(textbox_id); - - let mut harness = TestHarness::create(textbox); - - assert_debug_snapshot!(harness.root_widget()); - assert_render_snapshot!(harness, "hello"); - - assert_eq!(harness.pop_action(), None); - - harness.mouse_click_on(textbox_id); - assert_eq!(harness.focused_widget().unwrap().id(), textbox_id); - assert_eq!(harness.pop_action(), None); - - harness.keyboard_type_chars("abc"); - assert_eq!( - harness.pop_action(), - Some((Action::TextChanged("a".to_string()), textbox_id)) - ); - assert_eq!( - harness.pop_action(), - Some((Action::TextChanged("ab".to_string()), textbox_id)) - ); - assert_eq!( - harness.pop_action(), - Some((Action::TextChanged("abc".to_string()), textbox_id)) - ); - - dbg!(harness.get_widget(textbox_id)); - assert_eq!( - harness - .get_widget(textbox_id) - .downcast::() - .unwrap() - .text(), - "abc" - ); - } - - #[test] - fn simple_textbox_placeholder() { - let textbox = TextBox::new("").with_placeholder("placeholder text"); - - let mut harness = TestHarness::create(textbox); - - assert_debug_snapshot!(harness.root_widget()); - assert_render_snapshot!(harness, "placeholder"); - } - - // TODO - styled textbox - - #[test] - fn edit_textbox() { - // TODO - do styles - let image_1 = { - let textbox = TextBox::new("The quick brown fox jumps over the lazy dog"); - - let mut harness = TestHarness::create_with_size(textbox, Size::new(50.0, 50.0)); - - harness.render() - }; - - let image_2 = { - let textbox = TextBox::new("Hello world"); - - let mut harness = TestHarness::create_with_size(textbox, Size::new(50.0, 50.0)); - - harness.edit_root_widget(|mut textbox| { - let mut textbox = textbox.downcast::().unwrap(); - textbox.set_text("The quick brown fox jumps over the lazy dog"); - }); - - harness.render() - }; - - // We don't use assert_eq because we don't want rich assert - assert!(image_1 == image_2); - } -} -*/ diff --git a/src/widget/widget.rs b/src/widget/widget.rs index ec235093..e9675fd4 100644 --- a/src/widget/widget.rs +++ b/src/widget/widget.rs @@ -102,10 +102,6 @@ pub trait Widget: AsAny { /// Paint the widget appearance. /// - /// The [`PaintCtx`] derefs to something that implements the - /// [`piet::RenderContext`](crate::piet::RenderContext) trait, which exposes various methods that the widget - /// can use to paint its appearance. - /// /// Container widgets can paint a background before recursing to their /// children, or annotations (for example, scrollbars) by painting /// afterwards. In addition, they can apply masks and transforms on From 7116218ea0937191d3be5b893dc26b747854b1e6 Mon Sep 17 00:00:00 2001 From: Olivier FAURE Date: Tue, 9 Apr 2024 17:44:30 +0200 Subject: [PATCH 08/21] Fix examples --- examples/custom_widget.rs | 97 +++++++++------------ examples/promise_button.rs | 168 ------------------------------------- examples/simple_image.rs | 10 ++- src/widget/image.rs | 2 + 4 files changed, 49 insertions(+), 228 deletions(-) delete mode 100644 examples/promise_button.rs diff --git a/examples/custom_widget.rs b/examples/custom_widget.rs index 85b13b40..9253e35c 100644 --- a/examples/custom_widget.rs +++ b/examples/custom_widget.rs @@ -8,16 +8,19 @@ // On Windows platform, don't show a console when opening the app. #![windows_subsystem = "windows"] +use kurbo::Stroke; use masonry::kurbo::BezPath; -use masonry::piet::{FontFamily, ImageFormat, InterpolationMode, Text, TextLayoutBuilder}; -use masonry::text::{FontDescriptor, TextLayout}; -use masonry::widget::WidgetRef; +use masonry::widget::{FillStrat, WidgetRef}; use masonry::{ Affine, AppLauncher, BoxConstraints, Color, Event, EventCtx, LayoutCtx, LifeCycle, LifeCycleCtx, PaintCtx, Point, Rect, Size, StatusChange, Widget, WindowDescription, }; +use parley::style::{FontFamily, FontStack, StyleProperty}; +use parley::FontContext; use smallvec::SmallVec; use tracing::{trace_span, Span}; +use vello::peniko::{Brush, Fill, Format, Image}; +use vello::Scene; struct CustomWidget(String); @@ -61,21 +64,7 @@ impl Widget for CustomWidget { // and we only want to clear this widget's area. let size = ctx.size(); let rect = size.to_rect(); - ctx.fill(rect, &Color::WHITE); - - // We can paint with a Z index, this indicates that this code will be run - // after the rest of the painting. Painting with z-index is done in order, - // so first everything with z-index 1 is painted and then with z-index 2 etc. - // As you can see this(red) curve is drawn on top of the green curve - ctx.paint_with_z_index(1, move |ctx| { - let mut path = BezPath::new(); - path.move_to((0.0, size.height)); - path.quad_to((40.0, 50.0), (size.width, 0.0)); - // Create a color - let stroke_color = Color::rgb8(128, 0, 0); - // Stroke the path with thickness 1.0 - ctx.stroke(path, &stroke_color, 5.0); - }); + scene.fill(Fill::NonZero, Affine::IDENTITY, &Color::WHITE, None, &rect); // Create an arbitrary bezier path let mut path = BezPath::new(); @@ -84,52 +73,46 @@ impl Widget for CustomWidget { // Create a color let stroke_color = Color::rgb8(0, 128, 0); // Stroke the path with thickness 5.0 - ctx.stroke(path, &stroke_color, 5.0); + scene.stroke( + &Stroke::new(5.0), + Affine::IDENTITY, + &stroke_color, + None, + &path, + ); // Rectangles: the path for practical people let rect = Rect::from_origin_size((10.0, 10.0), (100.0, 100.0)); // Note the Color:rgba8 which includes an alpha channel (7F in this case) let fill_color = Color::rgba8(0x00, 0x00, 0x00, 0x7F); - ctx.fill(rect, &fill_color); - - // Text is easy; in real use TextLayout should either be stored in the - // widget and reused, or a label child widget to manage it all. - // This is one way of doing it, you can also use a builder-style way. - let mut layout = TextLayout::::from_text(&self.0); - layout.set_font(FontDescriptor::new(FontFamily::SERIF).with_size(24.0)); - layout.set_text_color(fill_color); - layout.rebuild_if_needed(ctx.text()); - - // Let's rotate our text slightly. First we save our current (default) context: - ctx.with_save(|ctx| { - // Now we can rotate the context (or set a clip path, for instance): - // This makes it so that anything drawn after this (in the closure) is - // transformed. - // The transformation is in radians, but be aware it transforms the canvas, - // not just the part you are drawing. So we draw at (80.0, 40.0) on the rotated - // canvas, this is NOT the same position as (80.0, 40.0) on the original canvas. - ctx.transform(Affine::rotate(std::f64::consts::FRAC_PI_4)); - layout.draw(ctx, (80.0, 40.0)); - }); - // When we exit with_save, the original context's rotation is restored - - // This is the builder-style way of drawing text. - let text = ctx.text(); - let layout = text - .new_text_layout(self.0.clone()) - .font(FontFamily::SERIF, 24.0) - .text_color(Color::rgb8(128, 0, 0)) - .build() - .unwrap(); - ctx.draw_text(&layout, (100.0, 25.0)); + scene.fill(Fill::NonZero, Affine::IDENTITY, &fill_color, None, &rect); + + // To render text, we first create a LayoutBuilder and set the text properties. + // FIXME + let mut font_cx = &mut FontContext::default(); + let mut lcx = parley::LayoutContext::new(); + let mut text_layout_builder = lcx.ranged_builder(&mut font_cx, &self.0, 1.0); + + text_layout_builder.push_default(&StyleProperty::FontStack(FontStack::Single( + FontFamily::Generic(parley::style::GenericFamily::Serif), + ))); + text_layout_builder.push_default(&StyleProperty::FontSize(24.0)); + text_layout_builder.push_default(&StyleProperty::Brush(Brush::Solid(fill_color))); + + let text_layout = text_layout_builder.build(); + + // We can pass a transform matrix to rotate the text we render + masonry::text_helpers::render_text( + scene, + Affine::rotate(std::f64::consts::FRAC_PI_4).then_translate((80.0, 40.0).into()), + &text_layout, + ); // Let's burn some CPU to make a (partially transparent) image buffer let image_data = make_image_data(256, 256); - let image = ctx - .make_image(256, 256, &image_data, ImageFormat::RgbaSeparate) - .unwrap(); - // The image is automatically scaled to fit the rect you pass to draw_image - ctx.draw_image(&image, size.to_rect(), InterpolationMode::Bilinear); + let image_data = Image::new(image_data.into(), Format::Rgba8, 256, 256); + let transform = FillStrat::Fill.affine_to_fill(ctx.size(), size); + scene.draw_image(&image_data, transform); } fn children(&self) -> SmallVec<[WidgetRef<'_, dyn Widget>; 16]> { @@ -142,7 +125,7 @@ impl Widget for CustomWidget { } pub fn main() { - let my_string = "Masonry + Piet".to_string(); + let my_string = "Masonry + Vello".to_string(); let window = WindowDescription::new(CustomWidget(my_string)).title("Fancy Colors"); AppLauncher::with_window(window) .log_to_console() diff --git a/examples/promise_button.rs b/examples/promise_button.rs deleted file mode 100644 index 1826481e..00000000 --- a/examples/promise_button.rs +++ /dev/null @@ -1,168 +0,0 @@ -// This software is licensed under Apache License 2.0 and distributed on an -// "as-is" basis without warranties of any kind. See the LICENSE file for -// details. - -//! A label widget. - -#![allow(clippy::single_match)] - -use std::{thread, time}; - -use druid_shell::Cursor; -use masonry::kurbo::Vec2; -use masonry::promise::PromiseToken; -use masonry::widget::prelude::*; -use masonry::widget::WidgetRef; -use masonry::{AppLauncher, WindowDescription}; -use masonry::{ArcStr, Color, Point}; -use parley::Layout; -use smallvec::SmallVec; -use tracing::{trace, trace_span, Span}; -use vello::peniko::Brush; -use vello::Scene; - -// added padding between the edges of the widget and the text. -const LABEL_X_PADDING: f64 = 2.0; - -pub struct PromiseButton { - value: u32, - text_layout: TextLayout, - text_layout2: Option>, - line_break_mode: LineBreaking, - promise_token: PromiseToken, - - default_text_color: Color, -} - -/// Options for handling lines that are too wide for the label. -#[derive(Debug, Clone, Copy, PartialEq)] -pub enum LineBreaking { - /// Lines are broken at word boundaries. - WordWrap, - /// Lines are truncated to the width of the label. - Clip, - /// Lines overflow the label. - Overflow, -} - -// --- METHODS --- - -impl PromiseButton { - /// Create a new `PromiseButton`. - pub fn new(text: impl Into) -> Self { - let mut text_layout = TextLayout::new(); - text_layout.set_text(text.into()); - - Self { - value: 0, - text_layout, - text_layout2: None, - line_break_mode: LineBreaking::Overflow, - promise_token: PromiseToken::empty(), - default_text_color: masonry::theme::TEXT_COLOR, - } - } -} - -// --- TRAIT IMPLS --- - -impl Widget for PromiseButton { - fn on_event(&mut self, ctx: &mut EventCtx, event: &Event) { - match event { - Event::MouseUp(_event) => { - let value = self.value; - self.promise_token = ctx.compute_in_background(move |_| { - // "sleep" stands in for a long computation, a download, etc. - thread::sleep(time::Duration::from_millis(2000)); - value + 1 - }); - self.text_layout.set_text("Loading ...".into()); - ctx.request_layout(); - } - Event::MouseMove(event) => { - // Account for the padding - let pos = event.pos - Vec2::new(LABEL_X_PADDING, 0.0); - - if self.text_layout.link_for_pos(pos).is_some() { - ctx.set_cursor(&Cursor::Pointer); - } else { - ctx.clear_cursor(); - } - } - Event::PromiseResult(result) => { - if let Some(new_value) = result.try_get(self.promise_token) { - self.text_layout - .set_text(format!("New value: {new_value}").into()); - self.value = new_value; - ctx.request_layout(); - } - } - _ => {} - } - } - - fn on_status_change(&mut self, _ctx: &mut LifeCycleCtx, _event: &StatusChange) {} - - fn lifecycle(&mut self, ctx: &mut LifeCycleCtx, event: &LifeCycle) { - match event { - LifeCycle::DisabledChanged(disabled) => { - let color = if *disabled { - masonry::theme::DISABLED_TEXT_COLOR - } else { - self.default_text_color - }; - self.text_layout.set_text_color(color); - ctx.request_layout(); - } - _ => {} - } - } - - fn layout(&mut self, ctx: &mut LayoutCtx, bc: &BoxConstraints) -> Size { - let width = match self.line_break_mode { - LineBreaking::WordWrap => bc.max().width - LABEL_X_PADDING * 2.0, - _ => f64::INFINITY, - }; - - self.text_layout.set_wrap_width(width); - self.text_layout.rebuild_if_needed(ctx.text()); - - let text_metrics = self.text_layout.layout_metrics(); - ctx.set_baseline_offset(text_metrics.size.height - text_metrics.first_baseline); - let size = bc.constrain(Size::new( - text_metrics.size.width + 2. * LABEL_X_PADDING, - text_metrics.size.height, - )); - trace!("Computed size: {}", size); - size - } - - fn paint(&mut self, ctx: &mut PaintCtx, scene: &mut Scene) { - let origin = Point::new(LABEL_X_PADDING, 0.0); - let label_size = ctx.size(); - - if self.line_break_mode == LineBreaking::Clip { - ctx.clip(label_size.to_rect()); - } - self.text_layout.draw(ctx, origin) - } - - fn children(&self) -> SmallVec<[WidgetRef<'_, dyn Widget>; 16]> { - SmallVec::new() - } - - fn make_trace_span(&self) -> Span { - trace_span!("PromiseButton") - } -} - -// --- - -fn main() { - let main_window = - WindowDescription::new(PromiseButton::new("Hello")).title("Blocking functions"); - AppLauncher::with_window(main_window) - .log_to_console() - .launch() - .expect("launch failed"); -} diff --git a/examples/simple_image.rs b/examples/simple_image.rs index f50ded9d..fa3c86ad 100644 --- a/examples/simple_image.rs +++ b/examples/simple_image.rs @@ -10,15 +10,19 @@ #![windows_subsystem = "windows"] use masonry::widget::{FillStrat, Image}; -use masonry::{AppLauncher, ImageBuf, WindowDescription}; +use masonry::{AppLauncher, WindowDescription}; +use vello::peniko::{Format, Image as ImageBuf}; pub fn main() { - let png_data = ImageBuf::from_data(include_bytes!("./assets/PicWithAlpha.png")).unwrap(); + let image_bytes = include_bytes!("./assets/PicWithAlpha.png"); + let image_data = image::load_from_memory(image_bytes).unwrap().to_rgba8(); + let (width, height) = image_data.dimensions(); + let png_data = ImageBuf::new(image_data.to_vec().into(), Format::Rgba8, width, height); let image = Image::new(png_data).fill_mode(FillStrat::Contain); let main_window = WindowDescription::new(image) .window_size((650., 450.)) - .title("Flex Container Options"); + .title("Simple image example"); AppLauncher::with_window(main_window) .log_to_console() diff --git a/src/widget/image.rs b/src/widget/image.rs index cf511275..e2ac6efe 100644 --- a/src/widget/image.rs +++ b/src/widget/image.rs @@ -17,6 +17,8 @@ use crate::{ StatusChange, Widget, }; +// TODO - Resolve name collision between masonry::Image and peniko::Image + /// A widget that renders a bitmap Image. /// /// The underlying image uses `Arc` for buffer data, making it cheap to clone. From ac123620c0ef303219c3a41119eb53ed610394e5 Mon Sep 17 00:00:00 2001 From: Olivier FAURE Date: Wed, 10 Apr 2024 13:52:31 +0200 Subject: [PATCH 09/21] Fix label properties Update snapshot tests. Update doc tests. --- src/lib.rs | 3 +- src/testing/harness.rs | 1 + src/widget/button.rs | 2 +- src/widget/label.rs | 50 ++++++++---------- src/widget/portal.rs | 2 + ...onry__widget__image__tests__tall_paint.png | Bin 173 -> 1608 bytes ...ry__widget__label__tests__styled_label.png | Bin 6871 -> 10535 bytes 7 files changed, 27 insertions(+), 31 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index fd6dd169..fcc7a156 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,9 +12,10 @@ //! //! ## Example //! +//! **(TODO: FIX THIS EXAMPLE)** //! The todo-list example looks like this: //! -//! ```no_run +//! ```ignore //! use masonry::widget::{prelude::*, TextBox}; //! use masonry::widget::{Button, Flex, Label, Portal, WidgetMut}; //! use masonry::Action; diff --git a/src/testing/harness.rs b/src/testing/harness.rs index 7cc540da..e1d3f861 100644 --- a/src/testing/harness.rs +++ b/src/testing/harness.rs @@ -34,6 +34,7 @@ use crate::widget::{StoreInWidgetMut, WidgetMut, WidgetRef}; use crate::*; // TODO - Get shorter names +// TODO - Make them associated consts /// Default canvas size for tests. pub const HARNESS_DEFAULT_SIZE: Size = Size::new(400., 400.); diff --git a/src/widget/button.rs b/src/widget/button.rs index 8a0fc0b9..877b5241 100644 --- a/src/widget/button.rs +++ b/src/widget/button.rs @@ -54,7 +54,7 @@ impl Button { /// use masonry::Color; /// use masonry::widget::{Button, Label}; /// - /// let label = Label::new("Increment").with_text_color(Color::grey(0.5)); + /// let label = Label::new("Increment").with_text_color(Color::rgb(0.5, 0.5, 0.5)); /// let button = Button::from_label(label); /// ``` pub fn from_label(label: Label) -> Button { diff --git a/src/widget/label.rs b/src/widget/label.rs index d061a426..4ce1e841 100644 --- a/src/widget/label.rs +++ b/src/widget/label.rs @@ -5,6 +5,7 @@ //! A label widget. use kurbo::Affine; +use parley::layout::Alignment; use parley::style::{FontFamily, FontStack, GenericFamily, StyleProperty}; use parley::{FontContext, Layout}; use smallvec::SmallVec; @@ -30,6 +31,7 @@ pub struct Label { line_break_mode: LineBreaking, disabled: bool, text_color: Color, + alignment: Alignment, } crate::declare_widget!(LabelMut, Label); @@ -59,22 +61,16 @@ impl Label { font_family: FontFamily::Generic(GenericFamily::SystemUi), line_break_mode: LineBreaking::Overflow, disabled: false, + alignment: Alignment::Start, } } /// Create a label with empty text. pub fn empty() -> Self { - Self { - current_text: "".into(), - text_layout: None, - text_color: crate::theme::TEXT_COLOR, - text_size: crate::theme::TEXT_SIZE_NORMAL as f32, - font_family: FontFamily::Generic(GenericFamily::SystemUi), - line_break_mode: LineBreaking::Overflow, - disabled: false, - } + Self::new("") } + // TODO - Rename methods /// Builder-style method for setting the text string. pub fn with_text(mut self, new_text: impl Into) -> Self { self.current_text = new_text.into(); @@ -107,10 +103,9 @@ impl Label { self } - #[cfg(FALSE)] - /// Builder-style method to set the [`TextAlignment`]. - pub fn with_text_alignment(mut self, alignment: TextAlignment) -> Self { - self.text_layout.set_text_alignment(alignment); + /// Builder-style method to set the [`Alignment`]. + pub fn with_text_alignment(mut self, alignment: Alignment) -> Self { + self.alignment = alignment; self } @@ -136,9 +131,9 @@ impl Label { let mut layout_builder = lcx.ranged_builder(font_cx, &self.current_text, 1.0); layout_builder.push_default(&StyleProperty::FontStack(FontStack::Single( - FontFamily::Generic(parley::style::GenericFamily::SystemUi), + self.font_family, ))); - layout_builder.push_default(&StyleProperty::FontSize(15.0)); + layout_builder.push_default(&StyleProperty::FontSize(self.text_size)); layout_builder.push_default(&StyleProperty::Brush(Brush::Solid(color))); // TODO - Refactor. This code is mostly copy-pasted from Xilem's text widget @@ -180,10 +175,9 @@ impl LabelMut<'_, '_> { self.ctx.request_layout(); } - #[cfg(FALSE)] - /// Set the [`TextAlignment`] for this layout. - pub fn set_text_alignment(&mut self, alignment: TextAlignment) { - self.widget.text_layout.set_text_alignment(alignment); + /// Set the [`Alignment`] for this layout. + pub fn set_text_alignment(&mut self, alignment: Alignment) { + self.widget.alignment = alignment; self.ctx.request_layout(); } } @@ -223,8 +217,9 @@ impl Widget for Label { // TODO - Handle baseline // Lay text out + let alignment = self.alignment; let layout = self.get_layout_mut(font_cx); - layout.break_all_lines(max_advance, parley::layout::Alignment::Start); + layout.break_all_lines(max_advance, alignment); let size = Size { width: layout.width() as f64 + 2. * LABEL_X_PADDING, height: layout.height() as f64, @@ -279,7 +274,6 @@ mod tests { use super::*; use crate::assert_render_snapshot; use crate::testing::TestHarness; - #[cfg(FALSE)] use crate::theme::{PRIMARY_DARK, PRIMARY_LIGHT}; use crate::widget::{Flex, SizedBox}; @@ -293,15 +287,14 @@ mod tests { assert_render_snapshot!(harness, "hello"); } - #[cfg(FALSE)] #[test] fn styled_label() { let label = Label::new("The quick brown fox jumps over the lazy dog") .with_text_color(PRIMARY_LIGHT) - .with_font(FontDescriptor::new(FontFamily::MONOSPACE)) + .with_font_family(FontFamily::Generic(GenericFamily::Monospace)) .with_text_size(20.0) .with_line_break_mode(LineBreaking::WordWrap) - .with_text_alignment(TextAlignment::Center); + .with_text_alignment(Alignment::Middle); let mut harness = TestHarness::create_with_size(label, Size::new(200.0, 200.0)); @@ -342,16 +335,15 @@ mod tests { assert_render_snapshot!(harness, "line_break_modes"); } - #[cfg(FALSE)] #[test] fn edit_label() { let image_1 = { let label = Label::new("The quick brown fox jumps over the lazy dog") .with_text_color(PRIMARY_LIGHT) - .with_font(FontDescriptor::new(FontFamily::MONOSPACE)) + .with_font_family(FontFamily::Generic(GenericFamily::Monospace)) .with_text_size(20.0) .with_line_break_mode(LineBreaking::WordWrap) - .with_text_alignment(TextAlignment::Center); + .with_text_alignment(Alignment::Middle); let mut harness = TestHarness::create_with_size(label, Size::new(50.0, 50.0)); @@ -369,10 +361,10 @@ mod tests { let mut label = label.downcast::