Merge pull request #2652 from storytold/fix/2057-layer-style-gradient

Layer Style dialog: Edit Gradient… opens the Gradient Editor (#2057)
This commit is contained in:
BFlat
2026-10-30 11:57:13 +07:00
committed by GitHub
4 changed files with 48 additions and 16 deletions
-9
View File
@@ -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", "ეფექტებისა და პრესეტების პარამეტრები"),
+7 -2
View File
@@ -245,7 +245,7 @@ pub fn open(app: &mut EffectcraftApp, p: &Json) -> Result<Json, String> {
/// 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
@@ -23,6 +23,8 @@ pub struct LayerStyleState {
pub selected: String,
pub undo_mark: usize,
checkpoint: Option<Checkpoint>,
/// 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<Value> {
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::<String>()).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 {
+24
View File
@@ -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,