diff --git a/Cargo.lock b/Cargo.lock index 38096db252ef3..c5217994883d7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -20,9 +20,9 @@ checksum = "366ffbaa4442f4684d91e2cd7c5ea7c4ed8add41959a31447066e279e432b618" [[package]] name = "accesskit" -version = "0.24.1" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3b7f7f85a7e5f68090000ed7622545829afd484d210358702ae4cb97dd0c320" +checksum = "ad442f58ee04714aaa0ba0a2768c1ea1935b29507bb22ddece8cbbc76db02932" dependencies = [ "uuid", ] @@ -209,7 +209,8 @@ dependencies = [ "objc2-foundation 0.3.2", "parking_lot", "percent-encoding", - "windows-sys 0.61.2", + "windows-sys 0.59.0", + "wl-clipboard-rs", "x11rb", ] @@ -1335,9 +1336,9 @@ checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76" [[package]] name = "ecolor" -version = "0.36.2" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0656a7530b9e2841ee7a5f983965bdd9840c32f4012f759cfd44b912cced6b34" +checksum = "31bcbef0d4263a63eb32c4834e5d711613035ce1333468e107d928923e21e6e2" dependencies = [ "bytemuck", "emath", @@ -1345,9 +1346,9 @@ dependencies = [ [[package]] name = "egui" -version = "0.36.2" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc938cc27cd911415e1e4d151bc56ff9df063d8db081374e87aeb805ea74b2ba" +checksum = "bec9144f49b7a28b5f395d3147e325b4fe3e77ba686eac11d1bdf0a7da3f375f" dependencies = [ "accesskit", "ahash", @@ -1360,14 +1361,13 @@ dependencies = [ "profiling", "smallvec", "unicode-segmentation", - "web-sys", ] [[package]] name = "egui-wgpu" -version = "0.36.2" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cef1f6d1bba40b09a4d0d62cb822b81030922cfbf65c5373398c3a3caafc5bd" +checksum = "0309cbe1febed48af5b974e4bcc424b35e9664863a4d402697147b57a488c864" dependencies = [ "ahash", "bytemuck", @@ -1385,15 +1385,17 @@ dependencies = [ [[package]] name = "egui-winit" -version = "0.36.2" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98466000559d66ba4db786a30448b01483946add4188e7f10f522a27b4fb89cc" +checksum = "e4e449f4c4a2a60c7ccb4ba7fa4078417bfe1f9ddc03b5e05ce75748e33a70de" dependencies = [ "arboard", + "block2 0.6.2", "bytemuck", "egui", "log", "objc2 0.6.5", + "objc2-app-kit 0.3.2", "objc2-foundation 0.3.2", "objc2-ui-kit 0.3.2", "profiling", @@ -1401,18 +1403,19 @@ dependencies = [ "smithay-clipboard", "web-time", "webbrowser", + "windows-sys 0.61.2", "winit", ] [[package]] name = "egui_extras" -version = "0.36.2" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05cbdc785020861553f230f23d330ba1fb72613b9d8e0e457f3bdc8ba6db6dcf" +checksum = "def286cf47194f3fe45b8e37c503ada7a20a64b59a903b4bc704baec943b1827" dependencies = [ "ahash", "egui", - "enum-map", + "enum-map 3.1.0", "image", "itertools 0.15.0", "log", @@ -1427,9 +1430,9 @@ checksum = "0e9c71c2167ca323c882b99918929403426e2373ea17242ff5653e0d5e1058be" [[package]] name = "emath" -version = "0.36.2" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52c8d4141cf0f60fb2f7aefaf352d3ffa5171ef0ab09731c64391801e95e48f1" +checksum = "e73ce90f54750be8672c02be0743fe47530e6f251e066f0ee2869b59eb297af5" dependencies = [ "bytemuck", ] @@ -1466,7 +1469,16 @@ version = "2.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6866f3bfdf8207509a033af1a75a7b08abda06bbaaeae6669323fd5a097df2e9" dependencies = [ - "enum-map-derive", + "enum-map-derive 0.17.0", +] + +[[package]] +name = "enum-map" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4532960034c15ba2f55e9eee631040ecc473c32e6c4b200828c759840f13a06" +dependencies = [ + "enum-map-derive 1.0.1", ] [[package]] @@ -1480,6 +1492,17 @@ dependencies = [ "syn 2.0.119", ] +[[package]] +name = "enum-map-derive" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7127272f64b3e098f7d81f350d672081b879bff896d219c42370dc858b1af9ff" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.9", +] + [[package]] name = "enumset" version = "1.1.13" @@ -1526,9 +1549,9 @@ dependencies = [ [[package]] name = "epaint" -version = "0.36.2" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0ec0308dc23130fc1a7d4623a8534c2ed069c6dc84e258ee4f3de99615aa1a3" +checksum = "97bac86ae3dde93fc3951e790951caea739ff39a6c89d909cdaf1d9278dbb1bd" dependencies = [ "ahash", "bytemuck", @@ -1545,15 +1568,16 @@ dependencies = [ "skrifa", "smallvec", "unicode-general-category", + "unicode-properties", "unicode-segmentation", "vello_cpu", ] [[package]] name = "epaint_default_fonts" -version = "0.36.2" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773fa9c96dd0dbef887e39d0ed6177f141cce4d68e6041df77570aa3702dfa13" +checksum = "cfc1cc505827f4c23eedc297975a0fd038268d41293f389dd8ff3b574aefab19" [[package]] name = "equivalent" @@ -1685,6 +1709,12 @@ version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c66915cc5391097de7a2b0b972e8505aa33c0df401fd3a6811dbdb32881ba48" +[[package]] +name = "fixedbitset" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" + [[package]] name = "flash-lso" version = "0.6.0" @@ -1811,6 +1841,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + [[package]] name = "foldhash" version = "0.2.0" @@ -2038,7 +2074,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "160a11f93020eea95cb4c59e2eda2e4c6353f75aa4fbb01f2bf8729b2e4d6dd2" dependencies = [ - "enum-map", + "enum-map 2.7.3", "gc-arena-derive", "hashbrown 0.17.1", "indexmap", @@ -2189,12 +2225,12 @@ dependencies = [ [[package]] name = "glifo" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed4a1bb24121291d27230c1b1b44e07d6a9b28cefdb32fe1581dfb84e14f940a" +checksum = "282a26c1e23de04bdab3e34a21b6f877a479b96737792516b9b8b8f69b6661be" dependencies = [ "bytemuck", - "foldhash", + "foldhash 0.2.0", "hashbrown 0.17.1", "log", "peniko", @@ -2367,6 +2403,15 @@ dependencies = [ "smallvec", ] +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash 0.1.5", +] + [[package]] name = "hashbrown" version = "0.16.1" @@ -2375,7 +2420,7 @@ checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" dependencies = [ "allocator-api2", "equivalent", - "foldhash", + "foldhash 0.2.0", ] [[package]] @@ -2386,7 +2431,7 @@ checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" dependencies = [ "allocator-api2", "equivalent", - "foldhash", + "foldhash 0.2.0", ] [[package]] @@ -3990,6 +4035,16 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "os_pipe" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d8fae84b431384b68627d0f9b3b1245fcf9f46f6c0e3dc902e9dce64edd1967" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + [[package]] name = "owned_ttf_parser" version = "0.25.1" @@ -4137,6 +4192,17 @@ dependencies = [ "stacker", ] +[[package]] +name = "petgraph" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455" +dependencies = [ + "fixedbitset", + "hashbrown 0.15.5", + "indexmap", +] + [[package]] name = "pin-project" version = "1.1.13" @@ -4759,7 +4825,7 @@ dependencies = [ "egui_extras", "either", "encoding_rs", - "enum-map", + "enum-map 2.7.3", "enumset", "flash-lso", "flate2", @@ -4935,7 +5001,7 @@ dependencies = [ "approx", "byteorder", "clap", - "enum-map", + "enum-map 2.7.3", "flate2", "gif", "guillotiere", @@ -4996,7 +5062,7 @@ version = "0.7.1" dependencies = [ "bytemuck", "clap", - "enum-map", + "enum-map 2.7.3", "fnv", "futures", "image", @@ -5477,7 +5543,7 @@ version = "1.0.154" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" dependencies = [ - "foldhash", + "foldhash 0.2.0", "indexmap", "itoa", "memchr", @@ -5749,7 +5815,7 @@ dependencies = [ "bitflags 2.13.2", "bitstream-io", "encoding_rs", - "enum-map", + "enum-map 2.7.3", "flate2", "log", "lzma-rs", @@ -5765,7 +5831,7 @@ dependencies = [ "bitflags 2.13.2", "bitstream-io", "encoding_rs", - "enum-map", + "enum-map 2.7.3", "flate2", "log", "lzma-rs", @@ -5783,7 +5849,7 @@ dependencies = [ "bitflags 2.13.2", "bitstream-io", "encoding_rs", - "enum-map", + "enum-map 2.7.3", "flate2", "log", "lzma-rs", @@ -6427,6 +6493,17 @@ dependencies = [ "strength_reduce", ] +[[package]] +name = "tree_magic_mini" +version = "3.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8765b90061cba6c22b5831f675da109ae5561588290f9fa2317adab2714d5a6" +dependencies = [ + "memchr", + "nom 8.0.0", + "petgraph", +] + [[package]] name = "try-lock" version = "0.2.5" @@ -6547,6 +6624,12 @@ version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563" +[[package]] +name = "unicode-properties" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" + [[package]] name = "unicode-segmentation" version = "1.13.3" @@ -6632,9 +6715,9 @@ checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" [[package]] name = "vello_common" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2e9aed918117e8152c9eddfd8362d73c465c23f26c44786aa331707b8a64fa2" +checksum = "bbb2141a2bca6e6d598e471fd4d1d7eed8e020aad6a28187edda07f091a325dd" dependencies = [ "bytemuck", "fearless_simd", @@ -6647,9 +6730,9 @@ dependencies = [ [[package]] name = "vello_cpu" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac7349e1f55f6b801c7c277958df4ea53e7f20f21e8014910ad888b2ecda93ea" +checksum = "ace506ca414548966fcf3c283be94eb1cad8254de488791ee698bf438b0890a9" dependencies = [ "bytemuck", "glifo", @@ -7601,6 +7684,24 @@ version = "0.57.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" +[[package]] +name = "wl-clipboard-rs" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d7888ccd4896447b2d14d3a9350a85df2aeb6f181e2e7a31349d104ac46cac1" +dependencies = [ + "libc", + "log", + "os_pipe", + "rustix 1.1.6", + "thiserror 2.0.18", + "tree_magic_mini", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-protocols-wlr", +] + [[package]] name = "x11-dl" version = "2.21.0" diff --git a/Cargo.toml b/Cargo.toml index 3dd23bf6105a9..ab5ea83fb6ac1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -61,10 +61,10 @@ tracing-subscriber = { version = "0.3.23", features = ["env-filter"] } naga = { version = "30.0.1", features = ["wgsl-out"] } wgpu = "30.0.1" wgpu-profiler = "0.28.0" -egui = "0.36.1" -egui_extras = { version = "0.36.1", default-features = false } -egui-wgpu = "0.36.1" -egui-winit = "0.36.1" +egui = "0.37.0" +egui_extras = { version = "0.37.0", default-features = false } +egui-wgpu = "0.37.0" +egui-winit = "0.37.0" clap = { version = "4.6.1", features = ["derive"] } clap_complete = "4.6" cpal = "0.16.0" diff --git a/core/src/debug_ui/avm1.rs b/core/src/debug_ui/avm1.rs index 74b99b78c4369..d3f80a4456e31 100644 --- a/core/src/debug_ui/avm1.rs +++ b/core/src/debug_ui/avm1.rs @@ -46,7 +46,7 @@ impl Avm1ObjectWindow { let mut activation = Activation::from_nothing(context, ActivationIdentifier::root("Debug"), base_clip); Window::new(object_name(object)) - .id(Id::new(object.as_ptr())) + .id(Id::unique(object.as_ptr())) .open(&mut keep_open) .scroll([true, true]) .show(egui_ctx, |ui| { @@ -81,7 +81,7 @@ impl Avm1ObjectWindow { activation: &mut Activation<'_, 'gc>, messages: &mut Vec, ) { - Grid::new(ui.id().with("properties")) + Grid::new(ui.scope_id().with("properties")) .num_columns(2) .show(ui, |ui| { let mut keys = object.get_keys(activation, true); @@ -273,7 +273,7 @@ fn show_value_type_combo_box<'gc>( mutation: &Mutation<'gc>, ) -> Option> { let mut new = None; - egui::ComboBox::new(egui::Id::new("value_combo").with(key), "Type") + egui::ComboBox::new(("value_combo", key), "Type") .selected_text(value_label(value)) .show_ui(ui, |ui| { if ui diff --git a/core/src/debug_ui/avm2.rs b/core/src/debug_ui/avm2.rs index 91557eaff7a20..b4a70b6542f31 100644 --- a/core/src/debug_ui/avm2.rs +++ b/core/src/debug_ui/avm2.rs @@ -52,7 +52,7 @@ impl Avm2ObjectWindow { let domain = context.avm2.stage_domain(); let mut activation = Activation::from_domain(context, domain); Window::new(object_name(activation.gc(), object)) - .id(Id::new(object.as_ptr())) + .id(Id::unique(object.as_ptr())) .open(&mut keep_open) .scroll([true, true]) .show(egui_ctx, |ui| { @@ -105,7 +105,7 @@ impl Avm2ObjectWindow { activation: &mut Activation<'_, 'gc>, ui: &mut Ui, ) { - Grid::new(ui.id().with("info")) + Grid::new(ui.scope_id().with("info")) .num_columns(2) .striped(true) .show(ui, |ui| { @@ -242,7 +242,7 @@ impl Avm2ObjectWindow { context: &mut UpdateContext<'gc>, ui: &mut Ui, ) { - Grid::new(ui.id().with("class")) + Grid::new(ui.scope_id().with("class")) .num_columns(2) .striped(true) .spacing([8.0, 8.0]) diff --git a/core/src/debug_ui/avm2_class.rs b/core/src/debug_ui/avm2_class.rs index b4fab0525f77c..e1b6d790ce4ba 100644 --- a/core/src/debug_ui/avm2_class.rs +++ b/core/src/debug_ui/avm2_class.rs @@ -28,7 +28,7 @@ impl Avm2ClassWindow { ) -> bool { let mut keep_open = true; Window::new(class_name(context.gc(), class)) - .id(Id::new(class.as_ptr())) + .id(Id::unique(class.as_ptr())) .open(&mut keep_open) .scroll([true, true]) .show(egui_ctx, |ui| { @@ -57,7 +57,7 @@ impl Avm2ClassWindow { context: &mut UpdateContext<'gc>, ui: &mut Ui, ) { - Grid::new(ui.id().with("class")) + Grid::new(ui.scope_id().with("class")) .num_columns(2) .striped(true) .spacing([8.0, 8.0]) @@ -104,7 +104,7 @@ impl Avm2ClassWindow { context: &mut UpdateContext<'gc>, ui: &mut Ui, ) { - Grid::new(ui.id().with("class")) + Grid::new(ui.scope_id().with("class")) .num_columns(2) .striped(true) .spacing([8.0, 8.0]) diff --git a/core/src/debug_ui/common.rs b/core/src/debug_ui/common.rs index b397615d3fdf7..981da63d2c2ea 100644 --- a/core/src/debug_ui/common.rs +++ b/core/src/debug_ui/common.rs @@ -2,7 +2,7 @@ use crate::html::{StyleSheet, TextFormat}; use egui::{CollapsingHeader, Grid, Ui}; pub fn show_text_format(ui: &mut Ui, tf: &TextFormat, skip_none: bool) { - Grid::new(ui.id().with("text_format_table")) + Grid::new(ui.scope_id().with("text_format_table")) .num_columns(2) .striped(true) .show(ui, |ui| { @@ -51,7 +51,7 @@ pub fn show_style_sheet(ui: &mut Ui, style_sheet: StyleSheet<'_>) { selectors.sort(); for selector in selectors { CollapsingHeader::new(selector.to_utf8_lossy()) - .id_salt(ui.id().with(selector.to_utf8_lossy())) + .id_salt(ui.scope_id().with(selector.to_utf8_lossy())) .show(ui, |ui| { if let Some(tf) = style_sheet.get_style(&selector) { show_text_format(ui, &tf, true); diff --git a/core/src/debug_ui/display_object.rs b/core/src/debug_ui/display_object.rs index 2e0f96493dd29..6959f69d28010 100644 --- a/core/src/debug_ui/display_object.rs +++ b/core/src/debug_ui/display_object.rs @@ -181,7 +181,7 @@ impl DisplayObjectWindow { self.hovered_debug_rect = None; Window::new(summary_name(object)) - .id(Id::new(object.as_ptr())) + .id(Id::unique(object.as_ptr())) .open(&mut keep_open) .scroll([true, true]) .show(egui_ctx, |ui| { @@ -249,7 +249,7 @@ impl DisplayObjectWindow { context: &mut UpdateContext<'gc>, object: InteractiveObject<'gc>, ) { - Grid::new(ui.id().with("interactive")) + Grid::new(ui.scope_id().with("interactive")) .num_columns(2) .show(ui, |ui| { ui.label("Mouse Enabled"); @@ -310,7 +310,7 @@ impl DisplayObjectWindow { ui.label("Focus Rect"); let focus_rect = object.focus_rect(); let mut new_focus_rect = focus_rect; - ComboBox::from_id_salt(ui.id().with("focus_rect")) + ComboBox::from_id_salt(ui.scope_id().with("focus_rect")) .selected_text(optional_boolean_switch_value(focus_rect)) .show_ui(ui, |ui| { for value in [None, Some(true), Some(false)] { @@ -360,7 +360,7 @@ impl DisplayObjectWindow { object: EditText<'gc>, messages: &mut Vec, ) { - Grid::new(ui.id().with("edittext")) + Grid::new(ui.scope_id().with("edittext")) .num_columns(2) .show(ui, |ui| { ui.label("Is FTE"); @@ -519,7 +519,7 @@ impl DisplayObjectWindow { ui.label("Autosize"); ui.horizontal(|ui| { let mut autosize = object.autosize(); - ComboBox::from_id_salt(ui.id().with("autosize")) + ComboBox::from_id_salt(ui.scope_id().with("autosize")) .selected_text(format!("{autosize:?}")) .show_ui(ui, |ui| { for value in [ @@ -650,9 +650,9 @@ impl DisplayObjectWindow { }); CollapsingHeader::new("Span List") - .id_salt(ui.id().with("spans")) + .id_salt(ui.scope_id().with("spans")) .show(ui, |ui| { - Grid::new(ui.id().with("spans")) + Grid::new(ui.scope_id().with("spans")) .num_columns(7) .striped(true) .show(ui, |ui| { @@ -675,12 +675,12 @@ impl DisplayObjectWindow { }); CollapsingHeader::new("Layout") - .id_salt(ui.id().with("layout")) + .id_salt(ui.scope_id().with("layout")) .show(ui, |ui| { let text = object.spans().text().to_owned(); let layout = object.layout(); - Grid::new(ui.id().with("layout-props")) + Grid::new(ui.scope_id().with("layout-props")) .num_columns(2) .striped(true) .show(ui, |ui| { @@ -706,7 +706,7 @@ impl DisplayObjectWindow { }); let html_text_response = CollapsingHeader::new("HTML Text") - .id_salt(ui.id().with("html-text")) + .id_salt(ui.scope_id().with("html-text")) .show(ui, |ui| { ui.add_sized( ui.available_size(), @@ -743,9 +743,9 @@ impl DisplayObjectWindow { ) .expect("Serializing string shouldn't fail"); CollapsingHeader::new(format!("Line {line_index:0>2} ({line_text})")) - .id_salt(ui.id().with("line").with(line_index)) + .id_salt(ui.scope_id().with("line").with(line_index)) .show(ui, |ui| { - Grid::new(ui.id().with("line-props")) + Grid::new(ui.scope_id().with("line-props")) .num_columns(2) .striped(true) .show(ui, |ui| { @@ -789,9 +789,9 @@ impl DisplayObjectWindow { messages: &mut Vec, ) { CollapsingHeader::new("Characters") - .id_salt(ui.id().with("chars")) + .id_salt(ui.scope_id().with("chars")) .show(ui, |ui| { - Grid::new(ui.id().with("box-props")) + Grid::new(ui.scope_id().with("box-props")) .num_columns(2) .striped(true) .show(ui, |ui| { @@ -854,9 +854,9 @@ impl DisplayObjectWindow { .expect("Serializing string shouldn't fail"); CollapsingHeader::new(format!("{box_type} {index:0>2} ({box_text})")) - .id_salt(ui.id().with("box").with(index)) + .id_salt(ui.scope_id().with("box").with(index)) .show(ui, |ui| { - Grid::new(ui.id().with("box-props")) + Grid::new(ui.scope_id().with("box-props")) .num_columns(2) .striped(true) .show(ui, |ui| { @@ -898,7 +898,7 @@ impl DisplayObjectWindow { object: Avm2Button<'gc>, messages: &mut Vec, ) { - Grid::new(ui.id().with("avm2_button")) + Grid::new(ui.scope_id().with("avm2_button")) .num_columns(2) .show(ui, |ui| { ui.label("Enabled"); @@ -915,7 +915,7 @@ impl DisplayObjectWindow { ui.horizontal(|ui| { let original_state = object.state(); let mut state = original_state; - ComboBox::from_id_salt(ui.id().with("state")) + ComboBox::from_id_salt(ui.scope_id().with("state")) .selected_text(format!("{state:?}")) .show_ui(ui, |ui| { for value in [ButtonState::Up, ButtonState::Over, ButtonState::Down] { @@ -969,7 +969,7 @@ impl DisplayObjectWindow { context: &mut UpdateContext<'gc>, object: Bitmap<'gc>, ) { - Grid::new(ui.id().with("bitmap")) + Grid::new(ui.scope_id().with("bitmap")) .num_columns(2) .show(ui, |ui| { let bitmap_data = object.bitmap_data(); @@ -1015,7 +1015,7 @@ impl DisplayObjectWindow { }); CollapsingHeader::new("Preview") - .id_salt(ui.id().with("bitmap-preview")) + .id_salt(ui.scope_id().with("bitmap-preview")) .show(ui, |ui| { let bitmap_data = object.bitmap_data(); let bitmap_data = bitmap_data.sync(context.renderer).borrow(); @@ -1047,7 +1047,7 @@ impl DisplayObjectWindow { context: &mut UpdateContext<'gc>, object: MovieClip<'gc>, ) { - Grid::new(ui.id().with("movieclip")) + Grid::new(ui.scope_id().with("movieclip")) .num_columns(2) .show(ui, |ui| { let label = object.current_label(); @@ -1100,7 +1100,7 @@ impl DisplayObjectWindow { }); CollapsingHeader::new("Frame List") - .id_salt(ui.id().with("frames")) + .id_salt(ui.scope_id().with("frames")) .show(ui, |ui| { ui.checkbox(&mut self.track_current_frame, "Track current"); // Height of a table row. 2.0 is used for text "padding" between rows @@ -1239,7 +1239,7 @@ impl DisplayObjectWindow { ) { let focus_tracker = object.focus_tracker(); let focus = focus_tracker.get(); - Grid::new(ui.id().with("stage")) + Grid::new(ui.scope_id().with("stage")) .num_columns(2) .show(ui, |ui| { ui.label("Stage Focus Rect"); @@ -1293,9 +1293,9 @@ impl DisplayObjectWindow { "automatic" }; CollapsingHeader::new(format!("Tab Order ({tab_order_suffix})")) - .id_salt(ui.id().with("tab_order")) + .id_salt(ui.scope_id().with("tab_order")) .show(ui, |ui| { - Grid::new(ui.id().with("tab_order_grid")) + Grid::new(ui.scope_id().with("tab_order_grid")) .num_columns(3) .show(ui, |ui| { ui.label("#"); @@ -1338,7 +1338,7 @@ impl DisplayObjectWindow { object: DisplayObject<'gc>, messages: &mut Vec, ) { - Grid::new(ui.id().with("display")) + Grid::new(ui.scope_id().with("display")) .num_columns(2) .show(ui, |ui| { ui.label("Parent"); @@ -1469,7 +1469,7 @@ impl DisplayObjectWindow { ui.label("Blend mode"); let old_blend = object.blend_mode(); let mut new_blend = old_blend; - ComboBox::from_id_salt(ui.id().with("blendmode")) + ComboBox::from_id_salt(ui.scope_id().with("blendmode")) .selected_text(blend_mode_name(old_blend)) .show_ui(ui, |ui| { for mode in ALL_BLEND_MODES { @@ -1513,7 +1513,7 @@ impl DisplayObjectWindow { let filters = object.filters(); if !filters.is_empty() { CollapsingHeader::new(format!("Filters ({})", filters.len())) - .id_salt(ui.id().with("filters")) + .id_salt(ui.scope_id().with("filters")) .show(ui, |ui| { for filter in &*filters { ui.label(format!("{filter:?}")); @@ -1529,7 +1529,7 @@ impl DisplayObjectWindow { object: DisplayObject<'gc>, messages: &mut Vec, ) { - Grid::new(ui.id().with("preview-settings")) + Grid::new(ui.scope_id().with("preview-settings")) .num_columns(2) .show(ui, |ui| { ui.label("Scale"); @@ -1542,7 +1542,7 @@ impl DisplayObjectWindow { ui.end_row(); ui.label("Quality"); - ComboBox::from_id_salt(ui.id().with("preview-quality")) + ComboBox::from_id_salt(ui.scope_id().with("preview-quality")) .selected_text(match self.preview_quality { Some(quality) => quality.to_string(), None => "Stage Quality".to_string(), @@ -1628,7 +1628,7 @@ impl DisplayObjectWindow { object: DisplayObject<'gc>, messages: &mut Vec, ) { - Grid::new(ui.id().with("position")) + Grid::new(ui.scope_id().with("position")) .num_columns(2) .show(ui, |ui| { ui.label("Name"); @@ -1726,32 +1726,34 @@ impl DisplayObjectWindow { hoverable_bounds: bool, ) { ui.collapsing(name, |ui| { - Grid::new(ui.id().with(name)).num_columns(2).show(ui, |ui| { - ui.label("Bounds"); - let no_hover = &mut None; - bounds_label( - ui, - object.bounds_with_transform(matrix, BoundsMode::Engine), - if hoverable_bounds { - &mut self.hovered_bounds - } else { - no_hover - }, - ); - ui.end_row(); + Grid::new(ui.scope_id().with(name)) + .num_columns(2) + .show(ui, |ui| { + ui.label("Bounds"); + let no_hover = &mut None; + bounds_label( + ui, + object.bounds_with_transform(matrix, BoundsMode::Engine), + if hoverable_bounds { + &mut self.hovered_bounds + } else { + no_hover + }, + ); + ui.end_row(); - ui.label("Position"); - ui.label(format!("{:.2}, {:.2}", matrix.tx, matrix.ty)); - ui.end_row(); + ui.label("Position"); + ui.label(format!("{:.2}, {:.2}", matrix.tx, matrix.ty)); + ui.end_row(); - ui.label("Rotation"); - ui.label(format!("{}, {}", matrix.b, matrix.c)); - ui.end_row(); + ui.label("Rotation"); + ui.label(format!("{}, {}", matrix.b, matrix.c)); + ui.end_row(); - ui.label("Scale"); - ui.label(format!("{}, {}", matrix.a, matrix.d)); - ui.end_row(); - }); + ui.label("Scale"); + ui.label(format!("{}, {}", matrix.a, matrix.d)); + ui.end_row(); + }); }); } @@ -1787,26 +1789,30 @@ impl DisplayObjectWindow { return; } if let Some(ctr) = object.as_container().filter(|x| x.num_children() > 0) { - CollapsingState::load_with_default_open(ui.ctx(), ui.id().with(object.as_ptr()), false) - .show_header(ui, |ui| { - open_display_object_button( - ui, - context, - messages, - object, - &mut self.hovered_debug_rect, - ); - }) - .body(|ui| { - for child in ctr.iter_render_list() { - self.show_display_tree(ui, context, child, messages, search); - } - }); + CollapsingState::load_with_default_open( + ui.ctx(), + ui.scope_id().with(object.as_ptr()), + false, + ) + .show_header(ui, |ui| { + open_display_object_button( + ui, + context, + messages, + object, + &mut self.hovered_debug_rect, + ); + }) + .body(|ui| { + for child in ctr.iter_render_list() { + self.show_display_tree(ui, context, child, messages, search); + } + }); } else { // This item is not expandable, but we want to keep // the space empty where the expand button would be, // so it doesn't look like a sibling of the parent. - ui.indent(ui.id().with(object.as_ptr()), |ui| { + ui.indent(ui.scope_id().with(object.as_ptr()), |ui| { open_display_object_button( ui, context, diff --git a/core/src/debug_ui/display_object/search.rs b/core/src/debug_ui/display_object/search.rs index 07e4a2d0cf7b4..a2315569aa122 100644 --- a/core/src/debug_ui/display_object/search.rs +++ b/core/src/debug_ui/display_object/search.rs @@ -172,19 +172,23 @@ fn show_object_tree( if tree.children.is_empty() { // This item is not expandable, but we want to keep the space empty where the // expand button would be, so it doesn't look like a sibling of the parent. - ui.indent(ui.id().with(tree.handle.as_ptr()), |ui| { + ui.indent(ui.scope_id().with(tree.handle.as_ptr()), |ui| { show_item(ui, context, tree, messages, hovered_debug_rect); }); } else { - CollapsingState::load_with_default_open(ui.ctx(), ui.id().with(tree.handle.as_ptr()), true) - .show_header(ui, |ui| { - show_item(ui, context, tree, messages, hovered_debug_rect); - }) - .body(|ui| { - for child in &tree.children { - show_object_tree(ui, context, child, messages, hovered_debug_rect); - } - }); + CollapsingState::load_with_default_open( + ui.ctx(), + ui.scope_id().with(tree.handle.as_ptr()), + true, + ) + .show_header(ui, |ui| { + show_item(ui, context, tree, messages, hovered_debug_rect); + }) + .body(|ui| { + for child in &tree.children { + show_object_tree(ui, context, child, messages, hovered_debug_rect); + } + }); } } diff --git a/core/src/debug_ui/domain.rs b/core/src/debug_ui/domain.rs index 33ea34804acea..0e596e5f007bd 100644 --- a/core/src/debug_ui/domain.rs +++ b/core/src/debug_ui/domain.rs @@ -53,46 +53,42 @@ impl DomainListWindow { let domain_id = format!("domain_{}_{:p}", depth, domain.as_ptr()); ui.push_id(domain_id, |ui| { - CollapsingState::load_with_default_open(ui.ctx(), ui.id().with("domain_header"), false) - .show_header(ui, |ui| { - open_domain_button(ui, context, messages, domain); - }) - .body(|ui| { - for (child_index, child_domain) in - domain.children(context.gc()).into_iter().enumerate() - { - ui.push_id(format!("child_domain_{}_{}", depth, child_index), |ui| { - Self::show_domain( - ui, - context, - child_domain, - messages, - search, - depth + 1, - ); - }); - } + CollapsingState::load_with_default_open( + ui.ctx(), + ui.scope_id().with("domain_header"), + false, + ) + .show_header(ui, |ui| { + open_domain_button(ui, context, messages, domain); + }) + .body(|ui| { + for (child_index, child_domain) in + domain.children(context.gc()).into_iter().enumerate() + { + ui.push_id(format!("child_domain_{}_{}", depth, child_index), |ui| { + Self::show_domain(ui, context, child_domain, messages, search, depth + 1); + }); + } - let class_props = domain.classes(); - let mut classes: Vec<_> = class_props.iter().collect(); - classes.sort_by_key(|(name, _, _)| *name); + let class_props = domain.classes(); + let mut classes: Vec<_> = class_props.iter().collect(); + classes.sort_by_key(|(name, _, _)| *name); - for (class_index, (_, _, class)) in classes.iter().enumerate() { - let name = class_name(context.gc(), **class); - if !name.to_string().to_ascii_lowercase().contains(search) { - continue; - } - - ui.push_id(format!("class_{class_index}"), |ui| { - let button = ui.button(format!("Class {name}")); - if button.clicked() { - messages.push(Message::TrackAVM2Class(ClassHandle::new( - context, **class, - ))); - } - }); + for (class_index, (_, _, class)) in classes.iter().enumerate() { + let name = class_name(context.gc(), **class); + if !name.to_string().to_ascii_lowercase().contains(search) { + continue; } - }); + + ui.push_id(format!("class_{class_index}"), |ui| { + let button = ui.button(format!("Class {name}")); + if button.clicked() { + messages + .push(Message::TrackAVM2Class(ClassHandle::new(context, **class))); + } + }); + } + }); }); } } diff --git a/core/src/debug_ui/font.rs b/core/src/debug_ui/font.rs index 5a301deb88c02..3615583f3de69 100644 --- a/core/src/debug_ui/font.rs +++ b/core/src/debug_ui/font.rs @@ -39,7 +39,7 @@ impl FontWindow { } fn show_font_info(&self, ui: &mut Ui, font: Font<'_>) { - Grid::new(ui.id().with("font-info")) + Grid::new(ui.scope_id().with("font-info")) .num_columns(2) .striped(true) .show(ui, |ui| { @@ -77,11 +77,11 @@ impl FontWindow { fn show_font_metrics(&self, ui: &mut Ui, font: Font<'_>) { CollapsingHeader::new("Font Metrics") - .id_salt(ui.id().with("metrics")) + .id_salt(ui.scope_id().with("metrics")) .show(ui, |ui| { let metrics = font.metrics(); - Grid::new(ui.id().with("font-metrics")) + Grid::new(ui.scope_id().with("font-metrics")) .num_columns(2) .striped(true) .show(ui, |ui| { @@ -106,7 +106,7 @@ impl FontWindow { fn show_glyph_info(&mut self, ui: &mut Ui, font: Font<'_>) { CollapsingHeader::new("Glyph Info") - .id_salt(ui.id().with("glyph-info")) + .id_salt(ui.scope_id().with("glyph-info")) .show(ui, |ui| { ui.add( TextEdit::singleline(&mut self.glyph_info_text) @@ -118,7 +118,7 @@ impl FontWindow { return; } - Grid::new(ui.id().with("glyph-info-table")) + Grid::new(ui.scope_id().with("glyph-info-table")) .num_columns(4) .striped(true) .show(ui, |ui| { @@ -162,7 +162,7 @@ impl FontWindow { }; CollapsingHeader::new(format!("Glyph Source: {kind}")) - .id_salt(ui.id().with("glyph-source")) + .id_salt(ui.scope_id().with("glyph-source")) .show(ui, |ui| match source { GlyphSource::Memory { glyphs, @@ -187,7 +187,7 @@ impl FontWindow { glyphs: &[Glyph], kerning_pairs: &FnvHashMap<(u16, u16), Twips>, ) { - Grid::new(ui.id().with("glyph-source-table")) + Grid::new(ui.scope_id().with("glyph-source-table")) .num_columns(2) .striped(true) .show(ui, |ui| { @@ -208,7 +208,7 @@ impl FontWindow { face: &FontFace, messages: &mut Vec, ) { - Grid::new(ui.id().with("glyph-source-table")) + Grid::new(ui.scope_id().with("glyph-source-table")) .num_columns(2) .striped(true) .show(ui, |ui| { @@ -230,7 +230,7 @@ impl FontWindow { ui: &mut Ui, glyph_source: &FontRendererGlyphSource, ) { - Grid::new(ui.id().with("glyph-source-table")) + Grid::new(ui.scope_id().with("glyph-source-table")) .num_columns(2) .striped(true) .show(ui, |ui| { @@ -278,7 +278,7 @@ impl FontWindow { fn show_glyph_atlas(&self, ui: &mut Ui, atlas: &FontAtlas, name: &str) { CollapsingHeader::new(format!("Glyph Atlas ({name})")) - .id_salt(ui.id().with(format!("atlas-{name}"))) + .id_salt(ui.scope_id().with(format!("atlas-{name}"))) .show(ui, |ui| { ui.label(format!("Atlas: {:p}", atlas.as_ptr())); @@ -297,7 +297,7 @@ impl FontWindow { } CollapsingHeader::new(format!("Page {i}")) - .id_salt(ui.id().with("page").with(i)) + .id_salt(ui.scope_id().with("page").with(i)) .show(ui, |ui| { let texture = self .atlas_page_textures diff --git a/core/src/debug_ui/movie.rs b/core/src/debug_ui/movie.rs index 461e65113d894..a043a41171d46 100644 --- a/core/src/debug_ui/movie.rs +++ b/core/src/debug_ui/movie.rs @@ -150,7 +150,7 @@ impl MovieWindow { let mut keep_open = true; Window::new(movie_name(movie)) - .id(Id::new(movie.as_ptr())) + .id(Id::unique(movie.as_ptr())) .open(&mut keep_open) .scroll([true, true]) .show(egui_ctx, |ui| { @@ -190,7 +190,7 @@ impl MovieWindow { .hint_text("Search for name or ID") .show(ui); - Grid::new(ui.id().with("characters")) + Grid::new(ui.scope_id().with("characters")) .num_columns(3) .show(ui, |ui| { let mut sorted_keys: Vec = characters.keys().cloned().collect(); @@ -228,7 +228,7 @@ impl MovieWindow { save_swf(movie, messages); } - Grid::new(ui.id().with("information")) + Grid::new(ui.scope_id().with("information")) .num_columns(2) .show(ui, |ui| { ui.label("URL"); @@ -296,10 +296,10 @@ impl MovieWindow { if !movie.parameters().is_empty() { CollapsingHeader::new("Parameters") - .id_salt(ui.id().with("parameters")) + .id_salt(ui.scope_id().with("parameters")) .default_open(false) .show(ui, |ui| { - Grid::new(ui.id().with("parameters")) + Grid::new(ui.scope_id().with("parameters")) .num_columns(2) .show(ui, |ui| { for (key, value) in movie.parameters() { diff --git a/desktop/Cargo.toml b/desktop/Cargo.toml index 1c5c187615fba..3a67da740f11f 100644 --- a/desktop/Cargo.toml +++ b/desktop/Cargo.toml @@ -14,7 +14,7 @@ workspace = true clap = { workspace = true } clap_complete = { workspace = true, optional = true } cpal = { workspace = true } -egui = { workspace = true } +egui = { workspace = true, features = ["default_fonts", "monochrome_emoji_fonts"] } egui_extras = { workspace = true, default-features = false, features = ["image"] } egui-wgpu = { workspace = true, features = ["winit"] } image = { workspace = true, features = ["png"] } diff --git a/desktop/src/backends/ui.rs b/desktop/src/backends/ui.rs index b1967b8aa09dd..11ea8e1bf1091 100644 --- a/desktop/src/backends/ui.rs +++ b/desktop/src/backends/ui.rs @@ -178,7 +178,10 @@ impl DesktopUiBackend { ) -> Result { // The window handle is only relevant to linux/wayland // If it fails it'll fallback to x11 or wlr-data-control - let clipboard = Clipboard::new(window.display_handle().ok().map(|handle| handle.as_raw())); + let handle = window.display_handle().ok().map(|handle| handle.as_raw()); + // SAFETY: The declaration order of the `clipboard` and `window` fields + // ensures that `handle` remains valid for the lifetime of `clipboard`. + let clipboard = unsafe { Clipboard::new(handle) }; Ok(Self { window, event_loop, diff --git a/desktop/src/gui/context_menu.rs b/desktop/src/gui/context_menu.rs index 851e571018493..f0d718708f70c 100644 --- a/desktop/src/gui/context_menu.rs +++ b/desktop/src/gui/context_menu.rs @@ -38,7 +38,7 @@ impl ContextMenu { let mut item_clicked = false; self.position = self.position.or(egui_ctx.pointer_latest_pos()); - let area = Area::new(Id::new("context_menu")) + let area = Area::new(Id::unique("context_menu")) .order(Order::Foreground) .fixed_pos(self.position.unwrap_or_default()) .constrain_to(egui_ctx.content_rect()) diff --git a/desktop/src/gui/dialogs/open_dialog.rs b/desktop/src/gui/dialogs/open_dialog.rs index 26869ea85c9da..41f60632fdcca 100644 --- a/desktop/src/gui/dialogs/open_dialog.rs +++ b/desktop/src/gui/dialogs/open_dialog.rs @@ -720,7 +720,7 @@ type ValueToTextFn = dyn Fn(T, &LanguageIdentifier) -> Cow<'static, str>; type ValueToOptTextFn = dyn Fn(T, &LanguageIdentifier) -> Option>; struct EnumDropdownField { - id: egui::Id, + id_salt: egui::IdSalt, default: T, value_to_name: Box>, value_to_tooltip: Box>, @@ -730,7 +730,7 @@ struct EnumDropdownField { impl EnumDropdownField { pub fn new(default: T, possible_values: Vec, value_to_name: Box>) -> Self { Self { - id: egui::Id::new(rand::random::()), + id_salt: egui::IdSalt::new(rand::random::()), default, value_to_name, possible_values, @@ -753,7 +753,7 @@ impl InnerField for EnumDropdownField { } fn ui(&self, ui: &mut Ui, value: &mut Self::Value, _error: bool, locale: &LanguageIdentifier) { - ComboBox::from_id_salt(self.id) + ComboBox::from_id_salt(self.id_salt) .selected_text((self.value_to_name)(*value, locale)) .show_ui(ui, |ui| { for possible_value in &self.possible_values { @@ -776,7 +776,7 @@ impl InnerField for EnumDropdownField { } struct BooleanDropdownField { - id: egui::Id, + id_salt: egui::IdSalt, default: bool, value_to_name: Box>, } @@ -784,7 +784,7 @@ struct BooleanDropdownField { impl BooleanDropdownField { pub fn new(default: bool, value_to_name: Box>) -> Self { Self { - id: egui::Id::new(rand::random::()), + id_salt: egui::IdSalt::new(rand::random::()), default, value_to_name, } @@ -800,7 +800,7 @@ impl InnerField for BooleanDropdownField { } fn ui(&self, ui: &mut Ui, value: &mut Self::Value, _error: bool, locale: &LanguageIdentifier) { - ComboBox::from_id_salt(self.id) + ComboBox::from_id_salt(self.id_salt) .selected_text((self.value_to_name)(*value, locale)) .show_ui(ui, |ui| { ui.selectable_value(value, false, (self.value_to_name)(false, locale)); @@ -845,11 +845,20 @@ impl InnerField for FieldWithCheckbox { } fn ui(&self, ui: &mut Ui, value: &mut Self::Value, error: bool, locale: &LanguageIdentifier) { - self.field.ui(ui, &mut value.0, error, locale); - let response = ui.checkbox(&mut value.1, self.checkbox_label.localize(locale)); - if let Some(ref tooltip_label) = self.tooltip_label { - response.on_hover_text_at_pointer(tooltip_label.localize(locale)); - } + // Lay out the checkbox first, so that the field only fills the remaining space. + // Otherwise the checkbox overflows the available width, and the window keeps growing. + ui.with_layout(Layout::right_to_left(egui::Align::Center), |ui| { + let response = ui.checkbox(&mut value.1, self.checkbox_label.localize(locale)); + if let Some(ref tooltip_label) = self.tooltip_label { + response.on_hover_text_at_pointer(tooltip_label.localize(locale)); + } + ui.with_layout( + Layout::centered_and_justified(egui::Direction::LeftToRight), + |ui| { + self.field.ui(ui, &mut value.0, error, locale); + }, + ); + }); } fn value_to_result(&self, value: &Self::Value) -> Result {