Fix #1629: an action clicked in the Actions panel stays selected, so Play and Delete act on it

This commit is contained in:
bflatastic committed 2026-10-14 07:37:53 +07:00
1 parent c10da25ce4
commit 0934f97627
1 file changed
+37 -4
+37 -4
View File
@@ -5,6 +5,7 @@
use serde::{Deserialize, Serialize};
use serde_json::{Value, json};
use super::{pstate, set_pstate};
use crate::theme::Tokens;
use crate::widgets::{self, dim_label};
use crate::{VectorcraftApp, icons};
@@ -52,8 +53,10 @@ pub fn play(app: &mut VectorcraftApp, set: usize, idx: usize) -> Result<Value, S
pub fn show(app: &mut VectorcraftApp, ui: &mut egui::Ui) {
let t = Tokens::get(ui.ctx());
let selected_id = egui::Id::new("actions-selected");
let mut selected: Option<(usize, usize)> = ui.data(|d| d.get_temp(selected_id));
// The selected action as (set, action). Read as the type it is stored as: egui keeps a
// value per type, so reading the bare pair never found it and no action stayed selected (#1629).
const SELECTED: &str = "actions-selected";
let mut selected: Option<(usize, usize)> = pstate(ui.ctx(), SELECTED);
let mut play_req = None;
egui::ScrollArea::vertical().max_height(260.0).show(ui, |ui| {
for (si, set) in app.ui.action_sets.iter().enumerate() {
@@ -89,7 +92,7 @@ pub fn show(app: &mut VectorcraftApp, ui: &mut egui::Ui) {
}
}
});
ui.data_mut(|d| d.insert_temp(selected_id, selected));
set_pstate(ui.ctx(), SELECTED, selected);
widgets::divider(ui);
// Bottom bar: stop, record, play, new, delete.
ui.horizontal(|ui| {
@@ -127,7 +130,7 @@ pub fn show(app: &mut VectorcraftApp, ui: &mut egui::Ui) {
&& ai < s.actions.len()
{
s.actions.remove(ai);
ui.data_mut(|d| d.insert_temp::<Option<(usize, usize)>>(selected_id, None));
set_pstate::<Option<(usize, usize)>>(ui.ctx(), SELECTED, None);
}
if recording {
ui.label(egui::RichText::new(tl!("● Recording")).color(egui::Color32::from_rgb(0xe0, 0x30, 0x30)));
@@ -160,6 +163,36 @@ mod tests {
}
}
/// #1629: a clicked action stays selected, so Play Current Selection plays it and Delete
/// Selection deletes it.
#[test]
fn a_clicked_action_stays_selected_for_play_and_delete() {
use super::super::tests_appearance::{click, frame_events, text_rect};
let mut app = VectorcraftApp::new(Session::new(), Default::default());
app.run("file.new", json!({"width": 200, "height": 100})).unwrap();
let id = app.run("shape.rectangle", json!({"x": 10, "y": 10, "width": 20, "height": 20})).unwrap()["id"].as_u64().unwrap();
let id = vectorcraft_doc::NodeId(id);
let ctx = egui::Context::default();
let texts = frame_events(&ctx, &mut app, vec![], show);
click(&ctx, &mut app, text_rect(&texts, "Reflect Horizontal").center(), show);
frame_events(&ctx, &mut app, vec![], show);
assert_eq!(pstate::<Option<(usize, usize)>>(&ctx, "actions-selected"), Some((0, 5)), "selected on the frames after the click");
// The bottom bar's 24-point buttons, left to right: stop, record, play, delete.
let mut bar = crate::toolbar::tests::widget_rects(&ctx, egui::vec2(24.0, 24.0));
bar.sort_by(|a, b| a.left().total_cmp(&b.left()));
let [_, _, play, delete] = bar[..] else { panic!("the bottom bar: {bar:?}") };
click(&ctx, &mut app, text_rect(&texts, "Duplicate and Offset 10 pt").center(), show);
click(&ctx, &mut app, play.center(), show);
assert_eq!(app.session.active().unwrap().selection.len(), 1);
assert_ne!(app.session.active().unwrap().selection.objects, [id], "played: the copy is selected");
let names = |app: &VectorcraftApp| app.ui.action_sets[0].actions.iter().map(|a| a.name.clone()).collect::<Vec<_>>();
let before = names(&app);
click(&ctx, &mut app, delete.center(), show);
assert_eq!(names(&app), before[1..], "the selected action is deleted");
click(&ctx, &mut app, delete.center(), show);
assert_eq!(names(&app), before[1..], "nothing selected after a delete: nothing more goes");
}
/// Actions recorded with Align to Artboard and Paste in Place, and the default Center on
/// Artboard, play on the artboard active when they play, not on the one active when they were
/// recorded.