Appearance panel: a drop on Delete keeps the active effect on its row

When an effect that isn't highlighted is dropped on Delete above the
active one, the active effect, the highlight and its anchor now move up
with their rows, and removed rows drop out of the highlight. Before,
they kept their old row numbers and pointed at the wrong effects.
This commit is contained in:
FarmerGeorg
2026-11-02 14:36:10 +07:00
committed by bflatastic
parent 9c59a4dcb4
commit 626ef7dd0e
2 changed files with 41 additions and 0 deletions
+19
View File
@@ -1456,10 +1456,29 @@ fn drop_on_buttons(app: &mut VectorcraftApp, ui: &Ui, node: Option<&Node>, sel:
&& let Dragged::Effect(item, _) = what
{
select_row(app, ctx, item.map_or(Sel::None, Sel::Item));
} else if removed && let Dragged::Effect(item, _) = what {
let gone: Vec<usize> = gone.iter().map(|k| *k as usize).collect();
highlight_after_removal(app, ctx, n, sel, Rows::Effects(item), &gone);
}
}
}
/// After the rows `gone` of kind `rows` were removed while the active row survived, the active row,
/// the highlight and its anchor move up past the removed rows below them; removed rows drop out of
/// the highlight. `n` is the object as it was before the removal.
fn highlight_after_removal(app: &mut VectorcraftApp, ctx: &egui::Context, n: &Node, sel: Sel, rows: Rows, gone: &[usize]) {
let h = highlight(ctx, n, sel);
if h.rows != rows {
return;
}
let shift = |k: usize| (!gone.contains(&k)).then(|| k - gone.iter().filter(|g| **g < k).count());
let order = h.order.iter().filter_map(|k| shift(*k)).collect();
let anchor = h.anchor.and_then(shift);
let active = sel.rows().filter(|(r, _)| *r == rows).and_then(|(_, a)| shift(a));
set_active(app, ctx, active.map_or(Sel::None, |a| rows.sel(a)));
set_pstate(ctx, "ap-multi", Highlight { owner: Some(n.id), rows, order, anchor });
}
/// The command a stack row `what` dropped on Duplicate Selected Item (`copy`) or Delete Selected
/// Item runs: a fill/stroke row acts on the highlighted rows `items` when it is one of them, an
/// effect row on the highlighted `effects` (list, positions) when it is one of them, else either on
@@ -1406,6 +1406,28 @@ fn a_drop_on_delete_that_removes_the_active_effect_leaves_no_effect_active() {
assert_eq!(object_effects(&app), ["distort.twist"], "Twist was never highlighted");
}
/// Dragging an effect that isn't highlighted onto Delete removes only it: the highlighted effects
/// below it move up with their rows, so they stay highlighted and active, and Delete Selected Item
/// then removes them.
#[test]
fn a_drop_on_delete_above_the_active_effect_keeps_the_highlight_on_its_rows() {
let mut app = rect_with_three_effects();
let ctx = drop_ctx();
let delete = panel_button(&ctx, &mut app, "Delete Selected Item");
let (glow, shadow, twist) =
(row_point(&ctx, &mut app, "Outer Glow", 0), row_point(&ctx, &mut app, "Drop Shadow", 0), row_point(&ctx, &mut app, "Twist", 0));
// Drop Shadow, then Twist with Ctrl: both highlighted, Twist active.
click_mod(&ctx, &mut app, shadow, egui::Modifiers::NONE);
click_mod(&ctx, &mut app, twist, egui::Modifiers::COMMAND);
drag_in_panel(&ctx, &mut app, glow, delete);
assert_eq!(object_effects(&app), ["stylize.dropShadow", "distort.twist"]);
let lit = lit_texts(&ctx, &mut app);
assert!(["Drop Shadow", "Twist"].iter().all(|t| lit.iter().any(|l| l.contains(t))), "still highlighted: {lit:?}");
let delete = panel_button(&ctx, &mut app, "Delete Selected Item");
click(&ctx, &mut app, delete, appearance::show);
assert!(object_effects(&app).is_empty(), "both highlighted effects removed: {:?}", object_effects(&app));
}
/// Whether Duplicate Selected Item and Delete Selected Item are enabled in a frame of the panel
/// with input `events`.
fn drop_buttons_on(ctx: &egui::Context, app: &mut VectorcraftApp, events: Vec<egui::Event>) -> [bool; 2] {