From d4e310b2525cb64456831ec3aeede3965bd1a6b6 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Tue, 6 Oct 2026 10:22:15 -0400 Subject: [PATCH] Merge fixes for #95 + #71 on current main - Project panel Clear (#95's focus routing) goes through invoke, so deleting items that compositions use still asks first (M3.16). - ui_project_delete: let a dialog finish egui::Modal's sizing frame before clicking its buttons (#95 moved dialogs to egui::Modal). - #71's i18n / theme tests clear the frame's texture delta; egui asserts on unhandled deltas in debug builds. Co-Authored-By: Claude Opus 5.5 --- crates/ui-egui/src/i18n.rs | 4 +++- crates/ui-egui/src/menus.rs | 3 ++- crates/ui-egui/src/theme.rs | 4 +++- crates/ui-egui/tests/ui_project_delete.rs | 3 +++ 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/crates/ui-egui/src/i18n.rs b/crates/ui-egui/src/i18n.rs index ef46ff48..bdbeafb3 100644 --- a/crates/ui-egui/src/i18n.rs +++ b/crates/ui-egui/src/i18n.rs @@ -756,9 +756,11 @@ mod tests { let tokens = crate::theme::Tokens::for_kind(crate::theme::ThemeKind::Dark); crate::theme::install(&ctx, &tokens); crate::panels::settings::open(&mut app, "general"); - let _ = ctx.run_ui(egui::RawInput::default(), |_| { + let mut out = ctx.run_ui(egui::RawInput::default(), |_| { crate::panels::settings::show(&mut app, &ctx, &tokens); }); + // No renderer here: drop the frame's texture uploads (egui asserts on unhandled ones in debug). + out.textures_delta.clear(); assert!(app.auto.find("settings.general.language").is_some()); } } diff --git a/crates/ui-egui/src/menus.rs b/crates/ui-egui/src/menus.rs index b1bb61b6..acbe8ac9 100644 --- a/crates/ui-egui/src/menus.rs +++ b/crates/ui-egui/src/menus.rs @@ -211,7 +211,8 @@ pub fn invoke(app: &mut EffectcraftApp, ctx: &egui::Context, id: &str, params: V } // Clear follows panel focus, including the Edit menu and keyboard shortcut. if id == "edit.clear" && params.as_object().is_some_and(|p| p.is_empty()) && app.ui.focused == PanelKind::Project { - return run_engine(app, ctx, "project.delete", json!({})); + // Through `invoke`, so deleting items that compositions use still asks first (M3.16). + return invoke(app, ctx, "project.delete", json!({})); } if id == "edit.clear" && params.as_object().is_some_and(|p| p.is_empty()) && app.ui.focused == PanelKind::RenderQueue { let selected = ctx.data(|d| d.get_temp::<(Vec, Option)>(egui::Id::new("rq-ui"))).and_then(|(_, id)| id); diff --git a/crates/ui-egui/src/theme.rs b/crates/ui-egui/src/theme.rs index 90365d8c..0fcdb7eb 100644 --- a/crates/ui-egui/src/theme.rs +++ b/crates/ui-egui/src/theme.rs @@ -366,7 +366,9 @@ mod japanese_font_tests { } let ctx = egui::Context::default(); super::install(&ctx, &super::Tokens::for_kind(super::ThemeKind::Dark)); - let _ = ctx.run_ui(egui::RawInput::default(), |_| {}); + let mut out = ctx.run_ui(egui::RawInput::default(), |_| {}); + // No renderer here: drop the frame's texture uploads (egui asserts on unhandled ones in debug). + out.textures_delta.clear(); ctx.fonts_mut(|fonts| { for family in [ egui::FontFamily::Proportional, diff --git a/crates/ui-egui/tests/ui_project_delete.rs b/crates/ui-egui/tests/ui_project_delete.rs index 83b5fee1..9963727d 100644 --- a/crates/ui-egui/tests/ui_project_delete.rs +++ b/crates/ui-egui/tests/ui_project_delete.rs @@ -31,6 +31,9 @@ fn harness() -> (Harness<'static, EffectcraftApp>, Vec, LayerId) { } fn click(h: &mut Harness<'_, EffectcraftApp>, id: &str, modifiers: Modifiers) { + // Let a dialog opened by the previous input finish its first (sizing) frame, so its buttons + // are where the automation tree says. + h.run_steps(2); let e = h.state().auto.find(id).unwrap_or_else(|| panic!("no {id}")).clone(); let p = pos2(e.rect[0] + e.rect[2] / 2.0, e.rect[1] + e.rect[3] / 2.0); h.input_mut().events.push(Event::ModifiersChanged(modifiers));