mirror of
https://github.com/storytold/gridcraft.git
synced 2026-10-24 10:46:50 -06:00
Merge pull request #1925 from DrM7md:nux/insert-delete-whole-lines
This commit is contained in:
@@ -2452,14 +2452,25 @@ pub fn shortcut(app: &mut SheetApp, key: Key, m: Modifiers) {
|
||||
Key::Num9 => Some(("home.hideRows", json!({}))),
|
||||
Key::Num0 if shift => Some(("home.unhideColumns", json!({}))),
|
||||
Key::Num0 => Some(("home.hideColumns", json!({}))),
|
||||
Key::Minus => {
|
||||
app.open_dialog("deleteCells", json!({}));
|
||||
None
|
||||
}
|
||||
Key::Plus | Key::Equals if shift => {
|
||||
app.open_dialog("insertCells", json!({}));
|
||||
None
|
||||
}
|
||||
// As in Excel: with whole rows or whole columns selected, Ctrl+Shift+= / Ctrl+- insert or
|
||||
// delete them at once; any other selection asks which way to shift.
|
||||
Key::Minus => match whole_lines(app) {
|
||||
Some(true) => Some(("home.deleteRows", json!({}))),
|
||||
Some(false) => Some(("home.deleteColumns", json!({}))),
|
||||
None => {
|
||||
app.open_dialog("deleteCells", json!({}));
|
||||
None
|
||||
}
|
||||
},
|
||||
// Insert works on one area at a time, so several areas still go through the dialog.
|
||||
Key::Plus | Key::Equals if shift => match whole_lines(app).filter(|_| single_area(app)) {
|
||||
Some(true) => Some(("home.insertRows", json!({}))),
|
||||
Some(false) => Some(("home.insertColumns", json!({}))),
|
||||
None => {
|
||||
app.open_dialog("insertCells", json!({}));
|
||||
None
|
||||
}
|
||||
},
|
||||
Key::Semicolon => {
|
||||
// Insert today's date.
|
||||
let text = app
|
||||
@@ -2514,3 +2525,23 @@ mod checkbox_on_tests {
|
||||
assert!(!checkbox_on(false, true));
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether the selection is a single area.
|
||||
fn single_area(app: &SheetApp) -> bool {
|
||||
app.session.active().is_some_and(|d| d.selection.ranges.len() == 1)
|
||||
}
|
||||
|
||||
/// `Some(true)` when every selected area is whole rows, `Some(false)` when every one is whole
|
||||
/// columns, `None` otherwise (including the whole sheet).
|
||||
fn whole_lines(app: &SheetApp) -> Option<bool> {
|
||||
let sel = &app.session.active()?.selection;
|
||||
let rows = sel.ranges.iter().all(|r| r.is_full_rows() && !r.is_full_cols());
|
||||
let cols = sel.ranges.iter().all(|r| r.is_full_cols() && !r.is_full_rows());
|
||||
if rows {
|
||||
Some(true)
|
||||
} else if cols {
|
||||
Some(false)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
//! Ctrl+Shift+= and Ctrl+- on whole rows or columns insert or delete them at once, as in Excel;
|
||||
//! any other selection opens the Insert or Delete dialog.
|
||||
|
||||
use egui::{Key, Modifiers};
|
||||
use gridcraft_engine::Session;
|
||||
use gridcraft_engine::core::{CellRef, Value};
|
||||
use gridcraft_ui_egui::SheetApp;
|
||||
use serde_json::json;
|
||||
|
||||
type Harness = egui_kittest::Harness<'static, SheetApp>;
|
||||
|
||||
fn harness(selection: &str) -> Harness {
|
||||
let mut session = Session::new();
|
||||
session.new_workbook();
|
||||
session.execute("range.setValues", json!({"range": "A1", "values": [["a1", "b1"], ["a2", "b2"], ["a3", "b3"]]})).unwrap();
|
||||
session.execute("selection.set", json!({"range": selection})).unwrap();
|
||||
let mut h = Harness::builder().with_size(egui::vec2(1200.0, 800.0)).build_ui_state(
|
||||
|ui, app: &mut SheetApp| {
|
||||
let ctx = ui.ctx().clone();
|
||||
app.logic(&ctx);
|
||||
app.ui(ui);
|
||||
},
|
||||
SheetApp::new(session, Default::default()),
|
||||
);
|
||||
h.run_steps(4);
|
||||
h
|
||||
}
|
||||
|
||||
fn value(h: &Harness, a1: &str) -> Value {
|
||||
h.state().session.active().unwrap().wb.active().unwrap().value(CellRef::parse(a1).unwrap())
|
||||
}
|
||||
|
||||
fn press(h: &mut Harness, key: Key, shift: bool) {
|
||||
let modifiers = Modifiers { shift, ..Modifiers::COMMAND };
|
||||
h.key_press_modifiers(modifiers, key);
|
||||
h.run_steps(3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn whole_rows_are_inserted_and_deleted_at_once() {
|
||||
let mut h = harness("2:2");
|
||||
press(&mut h, Key::Equals, true);
|
||||
assert!(h.state().dialog.is_none(), "no dialog for whole rows");
|
||||
assert!(value(&h, "A2").is_empty(), "a row was inserted above row 2");
|
||||
assert_eq!(value(&h, "A3"), Value::from("a2"));
|
||||
press(&mut h, Key::Minus, false);
|
||||
assert_eq!(value(&h, "A2"), Value::from("a2"), "and deleted again");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn whole_columns_are_inserted_and_deleted_at_once() {
|
||||
let mut h = harness("A:A");
|
||||
press(&mut h, Key::Equals, true);
|
||||
assert!(h.state().dialog.is_none(), "no dialog for whole columns");
|
||||
assert_eq!(value(&h, "B1"), Value::from("a1"));
|
||||
press(&mut h, Key::Minus, false);
|
||||
assert_eq!(value(&h, "A1"), Value::from("a1"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn other_selections_still_ask_which_way_to_shift() {
|
||||
let mut h = harness("A2:B2");
|
||||
press(&mut h, Key::Minus, false);
|
||||
assert_eq!(h.state().dialog.as_ref().map(|d| d.name().to_string()).as_deref(), Some("deleteCells"));
|
||||
}
|
||||
Reference in New Issue
Block a user