diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 8aaa18faa36..44cabf9a8cd 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -108,7 +108,7 @@ jobs: - name: wasm-bindgen uses: jetli/wasm-bindgen-action@v0.1.0 with: - version: "0.2.92" + version: "0.2.90" - run: ./scripts/wasm_bindgen_check.sh --skip-setup diff --git a/Cargo.lock b/Cargo.lock index b3722fdddec..c536538b39f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -144,7 +144,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "052ad56e336bcc615a214bffbeca6c181ee9550acec193f0327e0b103b033a4d" dependencies = [ "android-properties", - "bitflags 2.5.0", + "bitflags 2.4.0", "cc", "cesu8", "jni", @@ -510,9 +510,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.5.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" dependencies = [ "serde", ] @@ -649,7 +649,7 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b50b5a44d59a98c55a9eeb518f39bf7499ba19fd98ee7d22618687f3f10adbf" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.4.0", "log", "polling 3.3.0", "rustix 0.38.21", @@ -879,9 +879,9 @@ dependencies = [ [[package]] name = "core-foundation" -version = "0.9.4" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" dependencies = [ "core-foundation-sys", "libc", @@ -889,9 +889,9 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] name = "core-graphics" @@ -908,9 +908,9 @@ dependencies = [ [[package]] name = "core-graphics-types" -version = "0.1.3" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" +checksum = "2bb142d41022986c1d8ff29103a1411c8a3dfad3552f87a4f8dc50d61d4f4e33" dependencies = [ "bitflags 1.3.2", "core-foundation", @@ -1172,6 +1172,7 @@ dependencies = [ name = "eframe" version = "0.27.2" dependencies = [ + "ahash", "bytemuck", "directories-next", "document-features", @@ -1227,6 +1228,7 @@ dependencies = [ name = "egui-wgpu" version = "0.27.2" dependencies = [ + "ahash", "bytemuck", "document-features", "egui", @@ -1245,6 +1247,7 @@ name = "egui-winit" version = "0.27.2" dependencies = [ "accesskit_winit", + "ahash", "arboard", "document-features", "egui", @@ -1302,6 +1305,7 @@ dependencies = [ name = "egui_extras" version = "0.27.2" dependencies = [ + "ahash", "chrono", "document-features", "egui", @@ -1320,6 +1324,7 @@ dependencies = [ name = "egui_glow" version = "0.27.2" dependencies = [ + "ahash", "bytemuck", "document-features", "egui", @@ -1340,6 +1345,7 @@ dependencies = [ name = "egui_plot" version = "0.27.2" dependencies = [ + "ahash", "document-features", "egui", "serde", @@ -1785,7 +1791,7 @@ version = "0.31.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "005459a22af86adc706522d78d360101118e2638ec21df3852fcc626e0dbb212" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.4.0", "cfg_aliases", "cgl", "core-foundation", @@ -1861,7 +1867,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.4.0", "gpu-alloc-types", ] @@ -1871,7 +1877,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.4.0", ] [[package]] @@ -1889,22 +1895,22 @@ dependencies = [ [[package]] name = "gpu-descriptor" -version = "0.3.0" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c08c1f623a8d0b722b8b99f821eb0ba672a1618f0d3b16ddbee1cedd2dd8557" +checksum = "cc11df1ace8e7e564511f53af41f3e42ddc95b56fd07b3f4445d2a6048bc682c" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.4.0", "gpu-descriptor-types", "hashbrown", ] [[package]] name = "gpu-descriptor-types" -version = "0.2.0" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdf242682df893b86f33a73828fb09ca4b2d3bb6cc95249707fc684d27484b91" +checksum = "6bf0b36e6f090b7e1d8a4b49c0cb81c1f8376f72198c65dd3ad9ff3556b8b78c" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.4.0", ] [[package]] @@ -1947,7 +1953,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af2a7e73e1f34c48da31fb668a907f250794837e08faa144fd24f0b8b741e890" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.4.0", "com", "libc", "libloading 0.8.0", @@ -2183,9 +2189,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1" dependencies = [ "wasm-bindgen", ] @@ -2346,11 +2352,11 @@ dependencies = [ [[package]] name = "metal" -version = "0.28.0" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5637e166ea14be6063a3f8ba5ccb9a4159df7d8f6d61c02fc3d480b1f90dcfcb" +checksum = "c43f73953f8cbe511f021b58f18c3ce1c3d1ae13fe953293e13345bf83217f25" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.4.0", "block", "core-graphics-types", "foreign-types", @@ -2407,13 +2413,12 @@ dependencies = [ [[package]] name = "naga" -version = "0.20.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e536ae46fcab0876853bd4a632ede5df4b1c2527a58f6c5a4150fe86be858231" +checksum = "8878eb410fc90853da3908aebfe61d73d26d4437ef850b70050461f939509899" dependencies = [ - "arrayvec", "bit-set", - "bitflags 2.5.0", + "bitflags 2.4.0", "codespan-reporting", "hexf-parse", "indexmap", @@ -2432,7 +2437,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.4.0", "jni-sys", "log", "ndk-sys", @@ -2522,6 +2527,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" dependencies = [ "malloc_buf", + "objc_exception", ] [[package]] @@ -2632,6 +2638,15 @@ dependencies = [ "objc2 0.5.1", ] +[[package]] +name = "objc_exception" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4" +dependencies = [ + "cc", +] + [[package]] name = "objc_id" version = "0.1.1" @@ -3088,9 +3103,9 @@ checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" [[package]] name = "renderdoc-sys" -version = "1.1.0" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" +checksum = "216080ab382b992234dda86873c18d4c48358f5cfcb70fd693d7f6f2131b628b" [[package]] name = "resvg" @@ -3160,7 +3175,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" dependencies = [ "base64", - "bitflags 2.5.0", + "bitflags 2.4.0", "serde", "serde_derive", ] @@ -3203,7 +3218,7 @@ version = "0.38.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.4.0", "errno", "libc", "linux-raw-sys 0.4.11", @@ -3432,7 +3447,7 @@ version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60e3d9941fa3bacf7c2bf4b065304faa14164151254cd16ce1b1bc8fc381600f" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.4.0", "calloop", "calloop-wayland-source", "cursor-icon", @@ -3493,7 +3508,7 @@ 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", + "bitflags 2.4.0", ] [[package]] @@ -3613,6 +3628,14 @@ dependencies = [ "env_logger", ] +[[package]] +name = "test_size_pass" +version = "0.1.0" +dependencies = [ + "eframe", + "env_logger", +] + [[package]] name = "test_viewports" version = "0.1.0" @@ -3623,18 +3646,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.59" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa" +checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.59" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66" +checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" dependencies = [ "proc-macro2", "quote", @@ -3993,9 +4016,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -4003,9 +4026,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.92" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd" dependencies = [ "bumpalo", "log", @@ -4018,9 +4041,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.42" +version = "0.4.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +checksum = "bde2032aeb86bdfaecc8b261eef3cba735cc426c1f3a3416d1e0791be95fc461" dependencies = [ "cfg-if", "js-sys", @@ -4030,9 +4053,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4040,9 +4063,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7" dependencies = [ "proc-macro2", "quote", @@ -4053,9 +4076,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" [[package]] name = "wayland-backend" @@ -4077,7 +4100,7 @@ version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ca7d52347346f5473bf2f56705f360e8440873052e575e55890c4fa57843ed3" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.4.0", "nix", "wayland-backend", "wayland-scanner", @@ -4089,7 +4112,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.4.0", "cursor-icon", "wayland-backend", ] @@ -4111,7 +4134,7 @@ version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e253d7107ba913923dc253967f35e8561a3c65f914543e46843c88ddd729e21c" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.4.0", "wayland-backend", "wayland-client", "wayland-scanner", @@ -4123,7 +4146,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23803551115ff9ea9bce586860c5c5a971e360825a0309264102a9495a5ff479" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.4.0", "wayland-backend", "wayland-client", "wayland-protocols", @@ -4136,7 +4159,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad1f61b76b6c2d8742e10f9ba5c3737f6530b4c243132c2a2ccc8aa96fe25cd6" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.4.0", "wayland-backend", "wayland-client", "wayland-protocols", @@ -4168,9 +4191,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.69" +version = "0.3.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +checksum = "58cd2333b6e0be7a39605f0e255892fd7418a682d8da8fe042fe25128794d2ed" dependencies = [ "js-sys", "wasm-bindgen", @@ -4212,14 +4235,13 @@ checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc" [[package]] name = "wgpu" -version = "0.20.0" +version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32ff1bfee408e1028e2e3acbf6d32d98b08a5a059ccbf5f33305534453ba5d3e" +checksum = "0bfe9a310dcf2e6b85f00c46059aaeaf4184caa8e29a1ecd4b7a704c3482332d" dependencies = [ "arrayvec", "cfg-if", "cfg_aliases", - "document-features", "js-sys", "log", "naga", @@ -4238,16 +4260,15 @@ dependencies = [ [[package]] name = "wgpu-core" -version = "0.20.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac6a86eaa5e763e59c73cf9e97d55fffd4dfda69fd8bda19589fcf851ddfef1f" +checksum = "6b15e451d4060ada0d99a64df44e4d590213496da7c4f245572d51071e8e30ed" dependencies = [ "arrayvec", "bit-vec", - "bitflags 2.5.0", + "bitflags 2.4.0", "cfg_aliases", "codespan-reporting", - "document-features", "indexmap", "log", "naga", @@ -4265,14 +4286,14 @@ dependencies = [ [[package]] name = "wgpu-hal" -version = "0.20.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d71c8ae05170583049b65ee562fd839fdc0b3e9ddb84f4e40c9d5f8ea0d4c8c" +checksum = "11f259ceb56727fb097da108d92f8a5cbdb5b74a77f9e396bd43626f67299d61" dependencies = [ "android_system_properties", "arrayvec", "ash", - "bitflags 2.5.0", + "bitflags 2.4.0", "block", "cfg_aliases", "core-graphics-types", @@ -4289,7 +4310,6 @@ dependencies = [ "log", "metal", "naga", - "ndk-sys", "objc", "once_cell", "parking_lot", @@ -4307,11 +4327,11 @@ dependencies = [ [[package]] name = "wgpu-types" -version = "0.20.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1353d9a46bff7f955a680577f34c69122628cc2076e1d6f3a9be6ef00ae793ef" +checksum = "895fcbeb772bfb049eb80b2d6e47f6c9af235284e9703c96fc0218a42ffd5af2" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.4.0", "js-sys", "web-sys", ] @@ -4619,7 +4639,7 @@ dependencies = [ "ahash", "android-activity", "atomic-waker", - "bitflags 2.5.0", + "bitflags 2.4.0", "bytemuck", "calloop", "cfg_aliases", @@ -4725,7 +4745,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6924668544c48c0133152e7eec86d644a056ca3d09275eb8d5cdb9855f9d8699" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.4.0", "dlib", "log", "once_cell", diff --git a/Cargo.toml b/Cargo.toml index a42033c0efb..07e83a4e9c6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ members = [ "crates/epaint", "examples/*", + "tests/*", "xtask", ] @@ -87,7 +88,7 @@ web-time = "0.2" # Timekeeping for native and web wasm-bindgen = "0.2" wasm-bindgen-futures = "0.4" web-sys = "0.3.58" -wgpu = { version = "0.20.0", default-features = false, features = [ +wgpu = { version = "0.19.1", default-features = false, features = [ # Make the renderer `Sync` even on wasm32, because it makes the code simpler: "fragile-send-sync-non-atomic-wasm", ] } diff --git a/crates/eframe/Cargo.toml b/crates/eframe/Cargo.toml index f992c5c66a2..acd7600f6e6 100644 --- a/crates/eframe/Cargo.toml +++ b/crates/eframe/Cargo.toml @@ -129,6 +129,7 @@ egui = { workspace = true, default-features = false, features = [ "log", ] } +ahash.workspace = true document-features.workspace = true log.workspace = true parking_lot.workspace = true @@ -236,7 +237,14 @@ web-sys = { workspace = true, features = [ "MediaQueryListEvent", "MouseEvent", "Navigator", + "Node", + "NodeList", "Performance", + "ResizeObserver", + "ResizeObserverEntry", + "ResizeObserverBoxOptions", + "ResizeObserverOptions", + "ResizeObserverSize", "Storage", "Touch", "TouchEvent", diff --git a/crates/eframe/src/epi.rs b/crates/eframe/src/epi.rs index db39a08b15b..ac6585c3d18 100644 --- a/crates/eframe/src/epi.rs +++ b/crates/eframe/src/epi.rs @@ -41,10 +41,12 @@ pub type EventLoopBuilderHook = Box) #[cfg(any(feature = "glow", feature = "wgpu"))] pub type WindowBuilderHook = Box egui::ViewportBuilder>; +type DynError = Box; + /// This is how your app is created. /// /// You can use the [`CreationContext`] to setup egui, restore state, setup OpenGL things, etc. -pub type AppCreator = Box) -> Box>; +pub type AppCreator = Box) -> Result, DynError>>; /// Data that is passed to [`AppCreator`] that can be used to setup and initialize your app. pub struct CreationContext<'s> { @@ -150,6 +152,7 @@ pub trait App { /// On web the state is stored to "Local Storage". /// /// On native the path is picked using [`crate::storage_dir`]. + /// The path can be customized via [`NativeOptions::persistence_path`]. fn save(&mut self, _storage: &mut dyn Storage) {} /// Called once on shutdown, after [`Self::save`]. @@ -362,6 +365,10 @@ pub struct NativeOptions { /// Controls whether or not the native window position and size will be /// persisted (only if the "persistence" feature is enabled). pub persist_window: bool, + + /// The folder where `eframe` will store the app state. If not set, eframe will get the paths + /// from [directories_next]. + pub persistence_path: Option, } #[cfg(not(target_arch = "wasm32"))] @@ -379,6 +386,8 @@ impl Clone for NativeOptions { #[cfg(feature = "wgpu")] wgpu_options: self.wgpu_options.clone(), + persistence_path: self.persistence_path.clone(), + ..*self } } @@ -418,6 +427,8 @@ impl Default for NativeOptions { wgpu_options: egui_wgpu::WgpuConfiguration::default(), persist_window: true, + + persistence_path: None, } } } @@ -455,11 +466,6 @@ pub struct WebOptions { /// Configures wgpu instance/device/adapter/surface creation and renderloop. #[cfg(feature = "wgpu")] pub wgpu_options: egui_wgpu::WgpuConfiguration, - - /// The size limit of the web app canvas. - /// - /// By default the max size is [`egui::Vec2::INFINITY`], i.e. unlimited. - pub max_size_points: egui::Vec2, } #[cfg(target_arch = "wasm32")] @@ -475,8 +481,6 @@ impl Default for WebOptions { #[cfg(feature = "wgpu")] wgpu_options: egui_wgpu::WgpuConfiguration::default(), - - max_size_points: egui::Vec2::INFINITY, } } } diff --git a/crates/eframe/src/lib.rs b/crates/eframe/src/lib.rs index e1df19a8b0b..9f9f3a4c807 100644 --- a/crates/eframe/src/lib.rs +++ b/crates/eframe/src/lib.rs @@ -30,7 +30,7 @@ //! //! fn main() { //! let native_options = eframe::NativeOptions::default(); -//! eframe::run_native("My egui App", native_options, Box::new(|cc| Box::new(MyEguiApp::new(cc)))); +//! eframe::run_native("My egui App", native_options, Box::new(|cc| Ok(Box::new(MyEguiApp::new(cc))))); //! } //! //! #[derive(Default)] @@ -90,7 +90,7 @@ //! .start( //! canvas_id, //! eframe::WebOptions::default(), -//! Box::new(|cc| Box::new(MyEguiApp::new(cc))), +//! Box::new(|cc| Ok(Box::new(MyEguiApp::new(cc))),) //! ) //! .await //! } @@ -199,7 +199,7 @@ pub mod icon_data; /// /// fn main() -> eframe::Result<()> { /// let native_options = eframe::NativeOptions::default(); -/// eframe::run_native("MyApp", native_options, Box::new(|cc| Box::new(MyEguiApp::new(cc)))) +/// eframe::run_native("MyApp", native_options, Box::new(|cc| Ok(Box::new(MyEguiApp::new(cc))))) /// } /// /// #[derive(Default)] @@ -324,7 +324,7 @@ pub fn run_simple_native( run_native( app_name, native_options, - Box::new(|_cc| Box::new(SimpleApp { update_fun })), + Box::new(|_cc| Ok(Box::new(SimpleApp { update_fun }))), ) } @@ -333,6 +333,9 @@ pub fn run_simple_native( /// The different problems that can occur when trying to run `eframe`. #[derive(Debug)] pub enum Error { + /// Something went wrong in user code when creating the app. + AppCreation(Box), + /// An error from [`winit`]. #[cfg(not(target_arch = "wasm32"))] Winit(winit::error::OsError), @@ -403,6 +406,8 @@ impl From for Error { impl std::fmt::Display for Error { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { + Self::AppCreation(err) => write!(f, "app creation error: {err}"), + #[cfg(not(target_arch = "wasm32"))] Self::Winit(err) => { write!(f, "winit error: {err}") diff --git a/crates/eframe/src/native/epi_integration.rs b/crates/eframe/src/native/epi_integration.rs index 827b9ec249c..46ad66817ae 100644 --- a/crates/eframe/src/native/epi_integration.rs +++ b/crates/eframe/src/native/epi_integration.rs @@ -1,6 +1,8 @@ //! Common tools used by [`super::glow_integration`] and [`super::wgpu_integration`]. use web_time::Instant; + +use std::path::PathBuf; use winit::event_loop::EventLoopWindowTarget; use raw_window_handle::{HasDisplayHandle as _, HasWindowHandle as _}; @@ -132,6 +134,16 @@ pub fn create_storage(_app_name: &str) -> Option> { None } +#[allow(clippy::unnecessary_wraps)] +pub fn create_storage_with_file(_file: impl Into) -> Option> { + #[cfg(feature = "persistence")] + return Some(Box::new( + super::file_storage::FileStorage::from_ron_filepath(_file), + )); + #[cfg(not(feature = "persistence"))] + None +} + // ---------------------------------------------------------------------------- /// Everything needed to make a winit-based integration for [`epi`]. diff --git a/crates/eframe/src/native/file_storage.rs b/crates/eframe/src/native/file_storage.rs index 51c668abdeb..970c35a4f41 100644 --- a/crates/eframe/src/native/file_storage.rs +++ b/crates/eframe/src/native/file_storage.rs @@ -41,7 +41,7 @@ impl Drop for FileStorage { impl FileStorage { /// Store the state in this .ron file. - fn from_ron_filepath(ron_filepath: impl Into) -> Self { + pub(crate) fn from_ron_filepath(ron_filepath: impl Into) -> Self { crate::profile_function!(); let ron_filepath: PathBuf = ron_filepath.into(); log::debug!("Loading app state from {:?}…", ron_filepath); diff --git a/crates/eframe/src/native/glow_integration.rs b/crates/eframe/src/native/glow_integration.rs index 0fbb48a09c7..bfdee21d8d9 100644 --- a/crates/eframe/src/native/glow_integration.rs +++ b/crates/eframe/src/native/glow_integration.rs @@ -26,10 +26,10 @@ use winit::{ window::{Window, WindowId}, }; +use ahash::{HashMap, HashSet}; use egui::{ - ahash::HashSet, epaint::ahash::HashMap, DeferredViewportUiCallback, ImmediateViewport, - ViewportBuilder, ViewportClass, ViewportId, ViewportIdMap, ViewportIdPair, ViewportInfo, - ViewportOutput, + DeferredViewportUiCallback, ImmediateViewport, ViewportBuilder, ViewportClass, ViewportId, + ViewportIdMap, ViewportIdPair, ViewportInfo, ViewportOutput, }; #[cfg(feature = "accesskit")] use egui_winit::accesskit_winit; @@ -195,13 +195,17 @@ impl GlowWinitApp { ) -> Result<&mut GlowWinitRunning> { crate::profile_function!(); - let storage = epi_integration::create_storage( - self.native_options - .viewport - .app_id - .as_ref() - .unwrap_or(&self.app_name), - ); + let storage = if let Some(file) = &self.native_options.persistence_path { + epi_integration::create_storage_with_file(file) + } else { + epi_integration::create_storage( + self.native_options + .viewport + .app_id + .as_ref() + .unwrap_or(&self.app_name), + ) + }; let egui_ctx = create_egui_context(storage.as_deref()); @@ -309,7 +313,7 @@ impl GlowWinitApp { raw_window_handle: window.window_handle().map(|h| h.as_raw()), }; crate::profile_scope!("app_creator"); - app_creator(&cc) + app_creator(&cc).map_err(crate::Error::AppCreation)? }; let glutin = Rc::new(RefCell::new(glutin)); diff --git a/crates/eframe/src/native/run.rs b/crates/eframe/src/native/run.rs index 3ee249edf76..7087ed6ae71 100644 --- a/crates/eframe/src/native/run.rs +++ b/crates/eframe/src/native/run.rs @@ -2,7 +2,7 @@ use std::{cell::RefCell, time::Instant}; use winit::event_loop::{EventLoop, EventLoopBuilder}; -use egui::epaint::ahash::HashMap; +use ahash::HashMap; use crate::{ epi, diff --git a/crates/eframe/src/native/wgpu_integration.rs b/crates/eframe/src/native/wgpu_integration.rs index f365d74ad93..28f149f0b3f 100644 --- a/crates/eframe/src/native/wgpu_integration.rs +++ b/crates/eframe/src/native/wgpu_integration.rs @@ -15,8 +15,8 @@ use winit::{ window::{Window, WindowId}, }; +use ahash::{HashMap, HashSet, HashSetExt}; use egui::{ - ahash::{HashMap, HashSet, HashSetExt}, DeferredViewportUiCallback, FullOutput, ImmediateViewport, ViewportBuilder, ViewportClass, ViewportId, ViewportIdMap, ViewportIdPair, ViewportIdSet, ViewportInfo, ViewportOutput, }; @@ -182,7 +182,7 @@ impl WgpuWinitApp { storage: Option>, window: Window, builder: ViewportBuilder, - ) -> Result<&mut WgpuWinitRunning, egui_wgpu::WgpuError> { + ) -> crate::Result<&mut WgpuWinitRunning> { crate::profile_function!(); #[allow(unsafe_code, unused_mut, unused_unsafe)] @@ -272,7 +272,7 @@ impl WgpuWinitApp { }; let app = { crate::profile_scope!("user_app_creator"); - app_creator(&cc) + app_creator(&cc).map_err(crate::Error::AppCreation)? }; let mut viewport_from_window = HashMap::default(); @@ -406,13 +406,17 @@ impl WinitApp for WgpuWinitApp { self.recreate_window(event_loop, running); running } else { - let storage = epi_integration::create_storage( - self.native_options - .viewport - .app_id - .as_ref() - .unwrap_or(&self.app_name), - ); + let storage = if let Some(file) = &self.native_options.persistence_path { + epi_integration::create_storage_with_file(file) + } else { + epi_integration::create_storage( + self.native_options + .viewport + .app_id + .as_ref() + .unwrap_or(&self.app_name), + ) + }; let egui_ctx = winit_integration::create_egui_context(storage.as_deref()); let (window, builder) = create_window( &egui_ctx, diff --git a/crates/eframe/src/web/app_runner.rs b/crates/eframe/src/web/app_runner.rs index 620fe86fd62..f8b7f14a9da 100644 --- a/crates/eframe/src/web/app_runner.rs +++ b/crates/eframe/src/web/app_runner.rs @@ -2,9 +2,10 @@ use egui::TexturesDelta; use crate::{epi, App}; -use super::{now_sec, web_painter::WebPainter, NeedRepaint}; +use super::{now_sec, text_agent::TextAgent, web_painter::WebPainter, NeedRepaint}; pub struct AppRunner { + #[allow(dead_code)] web_options: crate::WebOptions, pub(crate) frame: epi::Frame, egui_ctx: egui::Context, @@ -13,7 +14,7 @@ pub struct AppRunner { app: Box, pub(crate) needs_repaint: std::sync::Arc, last_save_time: f64, - pub(crate) ime: Option, + pub(crate) text_agent: TextAgent, pub(crate) mutable_text_under_cursor: bool, // Output for the last run: @@ -29,11 +30,12 @@ impl Drop for AppRunner { impl AppRunner { /// # Errors - /// Failure to initialize WebGL renderer. + /// Failure to initialize WebGL renderer, or failure to create app. pub async fn new( canvas_id: &str, web_options: crate::WebOptions, app_creator: epi::AppCreator, + text_agent: TextAgent, ) -> Result { let painter = super::ActiveWebPainter::new(canvas_id, &web_options).await?; @@ -70,7 +72,7 @@ impl AppRunner { let theme = system_theme.unwrap_or(web_options.default_theme); egui_ctx.set_visuals(theme.egui_visuals()); - let app = app_creator(&epi::CreationContext { + let cc = epi::CreationContext { egui_ctx: egui_ctx.clone(), integration_info: info.clone(), storage: Some(&storage), @@ -85,7 +87,8 @@ impl AppRunner { wgpu_render_state: painter.render_state(), #[cfg(all(feature = "wgpu", feature = "glow"))] wgpu_render_state: None, - }); + }; + let app = app_creator(&cc).map_err(|err| err.to_string())?; let frame = epi::Frame { info, @@ -117,7 +120,7 @@ impl AppRunner { app, needs_repaint, last_save_time: now_sec(), - ime: None, + text_agent, mutable_text_under_cursor: false, textures_delta: Default::default(), clipped_primitives: None, @@ -184,7 +187,6 @@ impl AppRunner { /// /// The result can be painted later with a call to [`Self::run_and_paint`] or [`Self::paint`]. pub fn logic(&mut self) { - super::resize_canvas_to_screen_size(self.canvas(), self.web_options.max_size_points); let canvas_size = super::canvas_size_in_points(self.canvas(), self.egui_ctx()); let raw_input = self.input.new_frame(canvas_size); @@ -269,9 +271,11 @@ impl AppRunner { self.mutable_text_under_cursor = mutable_text_under_cursor; - if self.ime != ime { - super::text_agent::move_text_cursor(ime, self.canvas()); - self.ime = ime; + if let Err(err) = self.text_agent.move_to(ime, self.canvas()) { + log::error!( + "failed to update text agent position: {}", + super::string_from_js_value(&err) + ); } } } diff --git a/crates/eframe/src/web/events.rs b/crates/eframe/src/web/events.rs index 56d3fdf071a..b2f371bde3e 100644 --- a/crates/eframe/src/web/events.rs +++ b/crates/eframe/src/web/events.rs @@ -94,8 +94,8 @@ pub(crate) fn install_document_events(runner_ref: &WebRunner) -> Result<(), JsVa if !modifiers.ctrl && !modifiers.command && !should_ignore_key(&key) - // When text agent is shown, it sends text event instead. - && text_agent::text_agent().hidden() + // When text agent is focused, it is responsible for handling input events + && !runner.text_agent.has_focus() { runner.input.raw.events.push(egui::Event::Text(key)); } @@ -247,7 +247,8 @@ pub(crate) fn install_window_events(runner_ref: &WebRunner) -> Result<(), JsValu runner.save(); })?; - for event_name in &["load", "pagehide", "pageshow", "resize"] { + // NOTE: resize is handled by `ResizeObserver` below + for event_name in &["load", "pagehide", "pageshow"] { runner_ref.add_event_listener(&window, event_name, move |_: web_sys::Event, runner| { // log::debug!("{event_name:?}"); runner.needs_repaint.repaint_asap(); @@ -374,10 +375,12 @@ pub(crate) fn install_canvas_events(runner_ref: &WebRunner) -> Result<(), JsValu // event callback, which is why we run the app logic here and now: runner.logic(); + runner + .text_agent + .set_focus(runner.mutable_text_under_cursor); + // Make sure we paint the output of the above logic call asap: runner.needs_repaint.repaint_asap(); - - text_agent::update_text_agent(runner); } event.stop_propagation(); event.prevent_default(); @@ -466,13 +469,15 @@ pub(crate) fn install_canvas_events(runner_ref: &WebRunner) -> Result<(), JsValu runner.input.raw.events.push(egui::Event::PointerGone); push_touches(runner, egui::TouchPhase::End, &event); + + runner + .text_agent + .set_focus(runner.mutable_text_under_cursor); + runner.needs_repaint.repaint_asap(); event.stop_propagation(); event.prevent_default(); } - - // Finally, focus or blur text agent to toggle mobile keyboard: - text_agent::update_text_agent(runner); }, )?; @@ -590,3 +595,79 @@ pub(crate) fn install_canvas_events(runner_ref: &WebRunner) -> Result<(), JsValu Ok(()) } + +pub(crate) fn install_resize_observer(runner_ref: &WebRunner) -> Result<(), JsValue> { + let closure = Closure::wrap(Box::new({ + let runner_ref = runner_ref.clone(); + move |entries: js_sys::Array| { + // Only call the wrapped closure if the egui code has not panicked + if let Some(mut runner_lock) = runner_ref.try_lock() { + let canvas = runner_lock.canvas(); + let (width, height) = match get_display_size(&entries) { + Ok(v) => v, + Err(err) => { + log::error!("{}", super::string_from_js_value(&err)); + return; + } + }; + canvas.set_width(width); + canvas.set_height(height); + + // force an immediate repaint + runner_lock.needs_repaint.repaint_asap(); + paint_if_needed(&mut runner_lock); + } + } + }) as Box); + + let observer = web_sys::ResizeObserver::new(closure.as_ref().unchecked_ref())?; + let mut options = web_sys::ResizeObserverOptions::new(); + options.box_(web_sys::ResizeObserverBoxOptions::ContentBox); + if let Some(runner_lock) = runner_ref.try_lock() { + observer.observe_with_options(runner_lock.canvas(), &options); + drop(runner_lock); + runner_ref.set_resize_observer(observer, closure); + } + + Ok(()) +} + +// Code ported to Rust from: +// https://webglfundamentals.org/webgl/lessons/webgl-resizing-the-canvas.html +fn get_display_size(resize_observer_entries: &js_sys::Array) -> Result<(u32, u32), JsValue> { + let width; + let height; + let mut dpr = web_sys::window().unwrap().device_pixel_ratio(); + + let entry: web_sys::ResizeObserverEntry = resize_observer_entries.at(0).dyn_into()?; + if JsValue::from_str("devicePixelContentBoxSize").js_in(entry.as_ref()) { + // NOTE: Only this path gives the correct answer for most browsers. + // Unfortunately this doesn't work perfectly everywhere. + let size: web_sys::ResizeObserverSize = + entry.device_pixel_content_box_size().at(0).dyn_into()?; + width = size.inline_size(); + height = size.block_size(); + dpr = 1.0; // no need to apply + } else if JsValue::from_str("contentBoxSize").js_in(entry.as_ref()) { + let content_box_size = entry.content_box_size(); + let idx0 = content_box_size.at(0); + if !idx0.is_undefined() { + let size: web_sys::ResizeObserverSize = idx0.dyn_into()?; + width = size.inline_size(); + height = size.block_size(); + } else { + // legacy + let size = JsValue::clone(content_box_size.as_ref()); + let size: web_sys::ResizeObserverSize = size.dyn_into()?; + width = size.inline_size(); + height = size.block_size(); + } + } else { + // legacy + let content_rect = entry.content_rect(); + width = content_rect.width(); + height = content_rect.height(); + } + + Ok(((width.round() * dpr) as u32, (height.round() * dpr) as u32)) +} diff --git a/crates/eframe/src/web/mod.rs b/crates/eframe/src/web/mod.rs index 566c9b03c8d..50e7aeb363e 100644 --- a/crates/eframe/src/web/mod.rs +++ b/crates/eframe/src/web/mod.rs @@ -40,7 +40,6 @@ pub(crate) type ActiveWebPainter = web_painter_wgpu::WebPainterWgpu; pub use backend::*; -use egui::Vec2; use wasm_bindgen::prelude::*; use web_sys::MediaQueryList; @@ -54,6 +53,29 @@ pub(crate) fn string_from_js_value(value: &JsValue) -> String { value.as_string().unwrap_or_else(|| format!("{value:#?}")) } +/// Returns the `Element` with active focus. +/// +/// Elements can only be focused if they are: +/// - ``/`` with an `href` attribute +/// - ``/`