mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-08 22:28:09 +00:00
Layers: row keys follow the click and release after the last row (#5870)
This commit is contained in:
committed by
bflatastic
parent
5b98ed3b7d
commit
a3ed60650e
@@ -176,6 +176,9 @@ struct Out {
|
||||
column: Option<Option<ColumnDrag>>,
|
||||
/// Rows to open or close, and whether to open them.
|
||||
toggle: Vec<(NodeId, bool)>,
|
||||
/// The highlighted rows after this frame's row click, when one happened: the click's action
|
||||
/// runs after `delete_key`, so `view.rows` is still the state before it.
|
||||
rows_after_click: Option<Vec<NodeId>>,
|
||||
}
|
||||
|
||||
/// The panel state that says the Layers panel's rows have the keyboard ([`super::has_row_keys`]).
|
||||
@@ -365,10 +368,13 @@ pub fn show(app: &mut VectorcraftApp, ui: &mut Ui) {
|
||||
// left (the last one was deleted) the panel gives the keys back, so Delete clears the selected
|
||||
// art again instead of doing nothing.
|
||||
let pressed_outside = ui.input(|i| i.pointer.any_pressed() && i.pointer.interact_pos().is_some_and(|p| !list_rect.contains(p)));
|
||||
let focus = super::has_row_keys(ui.ctx(), ROW_KEYS) && !pressed_outside && !view.rows.is_empty();
|
||||
// A click's highlight action runs after this block, so read the rows it will leave, not the
|
||||
// snapshot `view.rows` took before it.
|
||||
let rows = out.rows_after_click.as_deref().unwrap_or(&view.rows);
|
||||
let focus = super::has_row_keys(ui.ctx(), ROW_KEYS) && !pressed_outside && !rows.is_empty();
|
||||
super::set_row_keys(ui.ctx(), ROW_KEYS, focus);
|
||||
if focus
|
||||
&& !view.rows.is_empty()
|
||||
&& !rows.is_empty()
|
||||
&& ui.ctx().memory(|m| m.focused().is_none())
|
||||
&& ui.input_mut(|i| i.consume_key(egui::Modifiers::NONE, egui::Key::Delete) || i.consume_key(egui::Modifiers::NONE, egui::Key::Backspace))
|
||||
{
|
||||
@@ -378,6 +384,11 @@ pub fn show(app: &mut VectorcraftApp, ui: &mut Ui) {
|
||||
for (c, p) in out.actions {
|
||||
app.run(&c, p).ok();
|
||||
}
|
||||
// A deletion that took the last highlighted row leaves the panel nothing to delete. Release the
|
||||
// keys now, not at the next draw, so the very next frame's Delete reaches Edit › Clear.
|
||||
if app.session.active().is_some_and(|st| st.highlighted_rows().is_empty()) {
|
||||
super::set_row_keys(ui.ctx(), ROW_KEYS, false);
|
||||
}
|
||||
see_selection(app, ui, selected);
|
||||
}
|
||||
|
||||
|
||||
@@ -91,6 +91,9 @@ pub(super) fn resolve_click(ui: &Ui, view: &View, list: &[Row], out: &mut Out) {
|
||||
if click.moves_anchor() {
|
||||
ui.data_mut(|d| d.insert_temp(key("anchor"), id));
|
||||
}
|
||||
let mut rows = view.rows.clone();
|
||||
widgets::apply_row_click(&mut rows, &click);
|
||||
out.rows_after_click = Some(rows);
|
||||
let ids = |rows: &[NodeId]| rows.iter().map(|r| r.0).collect::<Vec<_>>();
|
||||
out.actions.push(match click {
|
||||
widgets::RowClick::Only(id) => ("layer.setCurrent".into(), json!({"id": id.0})),
|
||||
|
||||
@@ -1348,10 +1348,15 @@ fn app_click(ctx: &egui::Context, app: &mut VectorcraftApp, pos: egui::Pos2, f:
|
||||
}
|
||||
}
|
||||
|
||||
/// `key` pressed and released in an app-like frame of `f`, then one more frame.
|
||||
fn app_key(ctx: &egui::Context, app: &mut VectorcraftApp, key: egui::Key, f: fn(&mut VectorcraftApp, &mut egui::Ui)) {
|
||||
/// `key` pressed and released in one app-like frame of `f`, with no idle frame after it.
|
||||
fn app_key_now(ctx: &egui::Context, app: &mut VectorcraftApp, key: egui::Key, f: fn(&mut VectorcraftApp, &mut egui::Ui)) {
|
||||
let ev = |pressed| egui::Event::Key { key, physical_key: None, pressed, repeat: false, modifiers: egui::Modifiers::NONE };
|
||||
app_frame(ctx, app, vec![ev(true), ev(false)], f);
|
||||
}
|
||||
|
||||
/// `key` pressed and released in an app-like frame of `f`, then one more frame.
|
||||
fn app_key(ctx: &egui::Context, app: &mut VectorcraftApp, key: egui::Key, f: fn(&mut VectorcraftApp, &mut egui::Ui)) {
|
||||
app_key_now(ctx, app, key, f);
|
||||
app_frame(ctx, app, vec![], f);
|
||||
}
|
||||
|
||||
@@ -1493,13 +1498,41 @@ fn delete_after_the_last_highlighted_layer_row_is_deleted_clears_the_selection()
|
||||
let texts = frame_events(&ctx, &mut app, vec![], boxed_layers);
|
||||
let row = text_rect(&texts, "Layer 2").center();
|
||||
app_click(&ctx, &mut app, row, boxed_layers);
|
||||
app_key(&ctx, &mut app, egui::Key::Delete, boxed_layers);
|
||||
app_key_now(&ctx, &mut app, egui::Key::Delete, boxed_layers);
|
||||
assert_eq!(app.session.active().unwrap().doc.layers.len(), 1, "Layer 2 is deleted");
|
||||
assert!(app.session.active().unwrap().selection.contains(rect), "the rectangle stays selected");
|
||||
app_key(&ctx, &mut app, egui::Key::Delete, boxed_layers);
|
||||
app_key_now(&ctx, &mut app, egui::Key::Delete, boxed_layers);
|
||||
assert!(app.session.active().unwrap().doc.node(rect).is_none(), "Delete clears the selected object once the panel has no rows");
|
||||
}
|
||||
|
||||
/// Clicking a row right after the last highlighted row was deleted restores the row keys: Delete
|
||||
/// then deletes that row, not the selected art.
|
||||
#[test]
|
||||
fn clicking_a_row_after_the_last_one_was_deleted_keeps_delete_with_the_layers_panel() {
|
||||
let ctx = drop_ctx();
|
||||
let mut app = app_with_rect();
|
||||
run(&mut app, "layer.new", json!({}));
|
||||
run(&mut app, "layer.new", json!({}));
|
||||
let rect = first_selected(&app).unwrap().id;
|
||||
let texts = frame_events(&ctx, &mut app, vec![], boxed_layers);
|
||||
let layer2 = text_rect(&texts, "Layer 2").center();
|
||||
app_click(&ctx, &mut app, layer2, boxed_layers);
|
||||
app_key_now(&ctx, &mut app, egui::Key::Delete, boxed_layers);
|
||||
assert_eq!(app.session.active().unwrap().doc.layers.len(), 2, "Layer 2 is deleted");
|
||||
// Click Layer 3 and press Delete in the very next frame: the click's highlight action runs at
|
||||
// the end of its frame, so the panel must read the rows the click will leave.
|
||||
let texts = frame_events(&ctx, &mut app, vec![], boxed_layers);
|
||||
let layer3 = text_rect(&texts, "Layer 3").center();
|
||||
let button =
|
||||
|pressed| egui::Event::PointerButton { pos: layer3, button: egui::PointerButton::Primary, pressed, modifiers: egui::Modifiers::NONE };
|
||||
for e in [egui::Event::PointerMoved(layer3), button(true), button(false)] {
|
||||
app_frame(&ctx, &mut app, vec![e], boxed_layers);
|
||||
}
|
||||
app_key_now(&ctx, &mut app, egui::Key::Delete, boxed_layers);
|
||||
assert_eq!(app.session.active().unwrap().doc.layers.len(), 1, "Delete removes the clicked row");
|
||||
assert!(app.session.active().unwrap().doc.node(rect).is_some(), "the rectangle on Layer 1 stays");
|
||||
}
|
||||
|
||||
/// A tool that claims Delete and Backspace (the Artboard tool's active artboard) leaves them to a
|
||||
/// clicked Layers row.
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user