diff --git a/crates/ui-egui/src/i18n/ui.rs b/crates/ui-egui/src/i18n/ui.rs index 1b7900bcb..4e010c469 100644 --- a/crates/ui-egui/src/i18n/ui.rs +++ b/crates/ui-egui/src/i18n/ui.rs @@ -316,7 +316,6 @@ const JAPANESE: &[(&str, &str)] = &[ ("Duration:", "デュレーション:"), ("Edit Gradient…", "グラデーションを編集…"), ("Edit Target: {}", "編集対象:{}"), - ("Edit in the Timeline", "タイムラインで編集"), ("EffectCraft didn't quit normally last time.", "EffectCraftは前回正常に終了しませんでした。"), ("Effects", "エフェクト"), ("Effects & Presets options", "エフェクト&プリセットのオプション"), @@ -1360,7 +1359,6 @@ const SIMPLIFIED_CHINESE: &[(&str, &str)] = &[ ("Duration:", "持续时间:"), ("Edit Gradient…", "编辑渐变…"), ("Edit Target: {}", "编辑目标:{}"), - ("Edit in the Timeline", "在时间轴中编辑"), ("EffectCraft didn't quit normally last time.", "EffectCraft 上次未正常退出。"), ("Effects", "效果"), ("Effects & Presets options", "效果和预设选项"), @@ -2469,7 +2467,6 @@ const TRADITIONAL_CHINESE: &[(&str, &str)] = &[ ("Duration:", "持續時間:"), ("Edit Gradient…", "編輯漸變…"), ("Edit Target: {}", "編輯目標:{}"), - ("Edit in the Timeline", "在時間軸中編輯"), ("EffectCraft didn't quit normally last time.", "EffectCraft 上次未正常結束。"), ("Effects", "效果"), ("Effects & Presets options", "效果和預設集選項"), @@ -3531,7 +3528,6 @@ const UKRAINIAN: &[(&str, &str)] = &[ ("Duration:", "Тривалість:"), ("Edit Gradient…", "Редагувати градієнт…"), ("Edit Target: {}", "Ціль редагування: {}"), - ("Edit in the Timeline", "Редагувати на шкалі часу"), ("EffectCraft didn't quit normally last time.", "Минулого разу EffectCraft завершив роботу некоректно."), ("Effects", "Ефекти"), ("Effects & Presets options", "Параметри ефектів і наборів"), @@ -4095,7 +4091,6 @@ const PORTUGUESE: &[(&str, &str)] = &[ ("Duration:", "Duração:"), ("Edit Gradient…", "Editar gradiente…"), ("Edit Target: {}", "Editar destino: {}"), - ("Edit in the Timeline", "Editar na linha do tempo"), ("EffectCraft didn't quit normally last time.", "O EffectCraft não foi encerrado normalmente da última vez."), ("Effects", "Efeitos"), ("Effects & Presets options", "Opções de Efeitos e predefinições"), @@ -4858,7 +4853,6 @@ const POLISH: &[(&str, &str)] = &[ ("Duration:", "Czas trwania:"), ("Edit Gradient…", "Edytuj gradient…"), ("Edit Target: {}", "Cel edycji: {}"), - ("Edit in the Timeline", "Edytuj na osi czasu"), ("EffectCraft didn't quit normally last time.", "EffectCraft nie zakończył się poprawnie ostatnim razem."), ("Effects & Presets options", "Opcje efektów i ustawień"), ("Copy Presets Folder Path", "Kopiuj ścieżkę folderu ustawień"), @@ -5603,7 +5597,6 @@ const CZECH: &[(&str, &str)] = &[ ("Duration:", "Délka trvání:"), ("Edit Gradient…", "Upravit přechod…"), ("Edit Target: {}", "Upravit cíl: {}"), - ("Edit in the Timeline", "Upravit na časové ose"), ("EffectCraft didn't quit normally last time.", "EffectCraft nebyl při posledním použití ukončen běžným způsobem."), ("Effects", "Efekty"), ("Effects & Presets options", "Možnosti efektů a přednastavení"), @@ -6171,7 +6164,6 @@ const SPANISH: &[(&str, &str)] = &[ ("Duration:", "Duración:"), ("Edit Gradient…", "Editar degradado…"), ("Edit Target: {}", "Destino de la edición: {}"), - ("Edit in the Timeline", "Editar en la cronología"), ("EffectCraft didn't quit normally last time.", "EffectCraft no se cerró normalmente la última vez."), ("Effects", "Efectos"), ("Effects & Presets options", "Opciones de Efectos y ajustes preestablecidos"), @@ -6723,7 +6715,6 @@ const GEORGIAN: &[(&str, &str)] = &[ ("Duration:", "ხანგრძლივობა:"), ("Edit Gradient…", "გრადიენტის რედაქტირება…"), ("Edit Target: {}", "რედაქტირების სამიზნე: {}"), - ("Edit in the Timeline", "რედაქტირება დროის ხაზზე"), ("EffectCraft didn't quit normally last time.", "EffectCraft ბოლოს ნორმალურად არ დახურულა."), ("Effects", "ეფექტები"), ("Effects & Presets options", "ეფექტებისა და პრესეტების პარამეტრები"), diff --git a/crates/ui-egui/src/panels/gradient_editor.rs b/crates/ui-egui/src/panels/gradient_editor.rs index 25e3d1d44..0f0bbe412 100644 --- a/crates/ui-egui/src/panels/gradient_editor.rs +++ b/crates/ui-egui/src/panels/gradient_editor.rs @@ -245,7 +245,7 @@ pub fn open(app: &mut EffectcraftApp, p: &Json) -> Result { /// Set the property to the draft: one `prop.set` at the time the editor opened, in composition /// time, or nothing when the draft is unchanged (so OK adds no keyframe). fn commit(app: &mut EffectcraftApp, ctx: &egui::Context) { - app.dialog = None; + close(app); let d = std::mem::take(&mut app.dialog_state.gradient); let g = d.gradient(); // The preview already set the property to this draft, in one merged undo step: OK keeps it. @@ -279,7 +279,12 @@ pub fn finish(app: &mut EffectcraftApp, ok: bool, ctx: &egui::Context) { preview_merge::rollback(app, cp, d.applied_at.as_ref()); } app.session.history.merge_key = None; - app.dialog = None; + close(app); +} + +/// Close the editor: back to the Layer Style dialog when it opened from there (#2057). +fn close(app: &mut EffectcraftApp) { + app.dialog = std::mem::take(&mut app.dialog_state.layer_style.gradient_open).then_some(Dialog::LayerStyles); } /// Keep the property in step with the draft while Preview is on: apply a changed draft with one diff --git a/crates/ui-egui/src/panels/layer_styles_dialog.rs b/crates/ui-egui/src/panels/layer_styles_dialog.rs index 5b415187d..09b775e30 100644 --- a/crates/ui-egui/src/panels/layer_styles_dialog.rs +++ b/crates/ui-egui/src/panels/layer_styles_dialog.rs @@ -23,6 +23,8 @@ pub struct LayerStyleState { pub selected: String, pub undo_mark: usize, checkpoint: Option, + /// The Gradient Editor opened from this dialog: closing it comes back here (#2057). + pub gradient_open: bool, } /// The project and undo history as a dialog found them, for a Cancel that rolls its live edits back. @@ -58,7 +60,8 @@ pub fn open(app: &mut EffectcraftApp, params: &Value) -> Result<(), String> { return Err(format!("unknown layer style `{style}`")); } let checkpoint = checkpoint(app); - app.dialog_state.layer_style = LayerStyleState { layer, selected: style, undo_mark: app.session.history.undo.len(), checkpoint: Some(checkpoint) }; + app.dialog_state.layer_style = + LayerStyleState { layer, selected: style, undo_mark: app.session.history.undo.len(), checkpoint: Some(checkpoint), gradient_open: false }; app.dialog = Some(Dialog::LayerStyles); Ok(()) } @@ -118,10 +121,6 @@ fn control(ui: &mut egui::Ui, p: &Property, v: &KV) -> Option { let changed = crate::widgets::srgb_color_button(ui, &mut rgb).changed(); changed.then(|| json!(rgb)) } - (KV::Gradient(_), _) => { - ui.label(egui::RichText::new(tr("Edit in the Timeline")).weak()); - None - } _ => { ui.label(egui::RichText::new(format!("{v:?}").chars().take(24).collect::()).weak()); None @@ -228,6 +227,19 @@ pub fn show(app: &mut EffectcraftApp, ctx: &egui::Context, t: &Tokens) { } let lbl = ui.label(&p.name); let v = p.value_at(lt); + if matches!(v, KV::Gradient(_)) { + // The Gradient Editor, over this dialog (a style the dialog + // only shows has no property to edit yet). + let path = g.match_path_of(p.uid).unwrap_or_default(); + let r = ui.add_enabled(missing.is_none(), egui::Button::new(tr("Edit Gradient…"))); + if r.clicked() { + actions.push(("prop.editGradient".into(), json!({"layer": lid, "prop": p.uid}))); + app.dialog_state.layer_style.gradient_open = true; + } + app.auto.add(&format!("dialog.layerStyle.value.{sel}/{path}"), r.rect, &p.name); + ui.end_row(); + return; + } let edit = ui.scope(|ui| control(ui, p, &v)); let path = g.match_path_of(p.uid).unwrap_or_default(); if let Some(nv) = edit.inner { diff --git a/crates/ui-egui/tests/it/ui_tail.rs b/crates/ui-egui/tests/it/ui_tail.rs index bd87a01a7..a824e065c 100644 --- a/crates/ui-egui/tests/it/ui_tail.rs +++ b/crates/ui-egui/tests/it/ui_tail.rs @@ -175,6 +175,30 @@ fn layer_style_buttons_stay_in_view() { } } +/// #2057: Gradient Overlay's gradient has an Edit Gradient… button in the Layer Style dialog. It +/// opens the Gradient Editor on that property, and closing the editor goes back to the dialog. +#[test] +fn layer_style_gradient_opens_the_gradient_editor() { + for ok in [true, false] { + let mut h = harness(1400.0); + let lid = h.state().session.active_comp().unwrap().layers[0].id.0; + h.state_mut().session.execute("layer.select", json!({"layers": [lid]})).unwrap(); + let ctx = h.ctx.clone(); + effectcraft_ui_egui::menus::invoke(h.state_mut(), &ctx, "layer.style.gradientOverlay", json!({})).unwrap(); + h.run_steps(5); + let edit = in_view(&h, "dialog.layerStyle.value.gradientOverlay/colors"); + click(&mut h, edit); + assert_eq!(h.state().dialog, Some(effectcraft_ui_egui::Dialog::GradientEditor), "Edit Gradient… opened the editor"); + effectcraft_ui_egui::panels::gradient_editor::finish(h.state_mut(), ok, &ctx); + h.run_steps(2); + assert_eq!(h.state().dialog, Some(effectcraft_ui_egui::Dialog::LayerStyles), "closing the editor (OK {ok}) went back to the dialog"); + // The dialog closes as before once the editor is gone. + effectcraft_ui_egui::panels::layer_styles_dialog::finish(h.state_mut(), true); + h.run_steps(2); + assert_eq!(h.state().dialog, None); + } +} + /// #1062: with the buttons kept at the bottom, the style's controls still scroll both ways, so /// every one of them can be reached in the smallest window (960×600) at 200 % UI Scale, and in a /// dialog opened in a large window that then narrows: here Noise, near the end of Drop Shadow,