mirror of
https://github.com/storytold/gridcraft.git
synced 2026-10-24 10:46:50 -06:00
Merge fork's border keytips fix into main
This commit is contained in:
@@ -10,7 +10,12 @@ pub mod keytip_table;
|
||||
pub enum Action {
|
||||
Tab(&'static str),
|
||||
Command(&'static str),
|
||||
/// A command run with fixed params (a JSON object literal from keytips.json `params`), for
|
||||
/// menu items that share one command id, like the Borders presets (HBO bottom, HBN none).
|
||||
CommandWith(&'static str, &'static str),
|
||||
Dialog(&'static str),
|
||||
/// A dialog opened with fixed params, like Format Cells on its Border tab (HBM).
|
||||
DialogWith(&'static str, &'static str),
|
||||
/// The target command does not exist yet: the sequence is reserved, its badge shows, and
|
||||
/// invoking it is a silent no-op until the command lands (see keytips.json `pending`).
|
||||
Pending(&'static str),
|
||||
|
||||
@@ -50,8 +50,8 @@ pub fn is_group_level(seq: &str) -> bool {
|
||||
|
||||
fn matches_target(action: &Action, target: &str) -> bool {
|
||||
match action {
|
||||
Action::Command(id) | Action::Pending(id) | Action::Control(id) => *id == target,
|
||||
Action::Dialog(name) => format!("dialog:{name}") == target,
|
||||
Action::Command(id) | Action::CommandWith(id, _) | Action::Pending(id) | Action::Control(id) => *id == target,
|
||||
Action::Dialog(name) | Action::DialogWith(name, _) => format!("dialog:{name}") == target,
|
||||
Action::Tab(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,40 +38,40 @@ pub const SEQUENCES: &[(&str, Entry)] = &[
|
||||
("HAN", Entry::Finish(Action::Command("home.accounting"))), // Excel: Accounting Format; fires immediately in Excel; deeper aliases dropped as unreachable
|
||||
("HAS", Entry::Finish(Action::Command("home.addIns"))), // Excel: Add-ins; containment(Add-ins)
|
||||
("HB", Entry::Continue), // Excel: Borders Menu; group level:
|
||||
("HBA", Entry::Finish(Action::Command("home.borders"))), // Excel: All Borders; containment(Borders)
|
||||
("HBB", Entry::Finish(Action::Command("home.borders"))), // Excel: Bottom Double Border; border-side TBD
|
||||
("HBC", Entry::Finish(Action::Command("home.borders"))), // Excel: Top and Thick Bottom Border; border-side TBD
|
||||
("HBD", Entry::Finish(Action::Command("home.borders"))), // Excel: Top and Bottom Border; border-side TBD
|
||||
("HBE", Entry::Finish(Action::Command("home.borders"))), // Excel: Erase Border; border-side TBD
|
||||
("HBG", Entry::Finish(Action::Command("home.drawBorder"))), // Excel: Draw Border Grid; containment(Draw Border)
|
||||
("HBH", Entry::Finish(Action::Command("home.borders"))), // Excel: Thick Bottom Border; border-side TBD
|
||||
("HBI", Entry::Finish(Action::Command("home.borders"))), // Excel: Line Color; Line Color (submenu TBD)
|
||||
("HBL", Entry::Finish(Action::Command("home.borders"))), // Excel: Left Border; border-side TBD
|
||||
("HBM", Entry::Finish(Action::Command("home.borders"))), // Excel: More Borders; containment(Borders)
|
||||
("HBN", Entry::Finish(Action::Command("home.borders"))), // Excel: No Border; border-side TBD
|
||||
("HBO", Entry::Finish(Action::Command("home.borders"))), // Excel: Bottom Border; border-side TBD
|
||||
("HBP", Entry::Finish(Action::Command("home.borders"))), // Excel: Top Border; border-side TBD
|
||||
("HBR", Entry::Finish(Action::Command("home.borders"))), // Excel: Right Border; border-side TBD
|
||||
("HBS", Entry::Finish(Action::Command("home.borders"))), // Excel: Outside Borders; containment(Borders)
|
||||
("HBT", Entry::Finish(Action::Command("home.borders"))), // Excel: Thick Outside Borders; border-side TBD
|
||||
("HBU", Entry::Finish(Action::Command("home.borders"))), // Excel: Top and Double Bottom Border; border-side TBD
|
||||
("HBW", Entry::Finish(Action::Command("home.drawBorder"))), // Excel: Draw Border
|
||||
("HBY", Entry::Finish(Action::Command("home.borders"))), // Excel: Line Style; Line Style (submenu TBD)
|
||||
("HC", Entry::Finish(Action::Command("edit.copy"))), // Excel: Copy; fires immediately in Excel; deeper aliases dropped as unreachable
|
||||
("HDC", Entry::Finish(Action::Command("home.deleteColumns"))), // Excel: Delete Columns; Delete Columns
|
||||
("HDD", Entry::Finish(Action::Dialog("deleteCells"))), // Excel: Delete Cells
|
||||
("HDR", Entry::Finish(Action::Command("home.deleteRows"))), // Excel: Delete Rows; Delete Rows
|
||||
("HDS", Entry::Finish(Action::Command("home.deleteSheet"))), // Excel: Delete Sheet
|
||||
("HEA", Entry::Finish(Action::Command("edit.clearAll"))), // Excel: Clear All
|
||||
("HEC", Entry::Finish(Action::Command("edit.clearContents"))), // Excel: Clear Contents
|
||||
("HEF", Entry::Finish(Action::Command("edit.clearFormats"))), // Excel: Clear Formats
|
||||
("HBA", Entry::Finish(Action::CommandWith("home.borders", "{\"preset\":\"all\"}"))), // Excel: All Borders; Borders menu item
|
||||
("HBB", Entry::Finish(Action::CommandWith("home.borders", "{\"preset\":\"doubleBottom\"}"))), // Excel: Bottom Double Border; Borders menu item
|
||||
("HBC", Entry::Finish(Action::CommandWith("home.borders", "{\"preset\":\"topThickBottom\"}"))), // Excel: Top and Thick Bottom Border; Borders menu item
|
||||
("HBD", Entry::Finish(Action::CommandWith("home.borders", "{\"preset\":\"topBottom\"}"))), // Excel: Top and Bottom Border; Borders menu item
|
||||
("HBE", Entry::Finish(Action::Pending("home.eraseBorder"))), // pending; Excel: Erase Border; pending: Excel arms an eraser pen; GridCraft has no border pen mode yet
|
||||
("HBG", Entry::Finish(Action::Command("home.drawBorder"))), // Excel: Draw Border Grid; containment(Draw Border)
|
||||
("HBH", Entry::Finish(Action::CommandWith("home.borders", "{\"preset\":\"thickBottom\"}"))), // Excel: Thick Bottom Border; Borders menu item
|
||||
("HBI", Entry::Finish(Action::Pending("home.borderLineColor"))), // pending; Excel: Line Color; pending: Line Color submenu
|
||||
("HBL", Entry::Finish(Action::CommandWith("home.borders", "{\"preset\":\"left\"}"))), // Excel: Left Border; Borders menu item
|
||||
("HBM", Entry::Finish(Action::DialogWith("formatCells", "{\"tab\":\"Border\"}"))), // Excel: More Borders; Format Cells on its Border tab
|
||||
("HBN", Entry::Finish(Action::CommandWith("home.borders", "{\"preset\":\"none\"}"))), // Excel: No Border; Borders menu item
|
||||
("HBO", Entry::Finish(Action::CommandWith("home.borders", "{\"preset\":\"bottom\"}"))), // Excel: Bottom Border; Borders menu item
|
||||
("HBP", Entry::Finish(Action::CommandWith("home.borders", "{\"preset\":\"top\"}"))), // Excel: Top Border; Borders menu item
|
||||
("HBR", Entry::Finish(Action::CommandWith("home.borders", "{\"preset\":\"right\"}"))), // Excel: Right Border; Borders menu item
|
||||
("HBS", Entry::Finish(Action::CommandWith("home.borders", "{\"preset\":\"outside\"}"))), // Excel: Outside Borders; Borders menu item
|
||||
("HBT", Entry::Finish(Action::CommandWith("home.borders", "{\"preset\":\"thickOutside\"}"))), // Excel: Thick Outside Borders; Borders menu item
|
||||
("HBU", Entry::Finish(Action::CommandWith("home.borders", "{\"preset\":\"topDoubleBottom\"}"))), // Excel: Top and Double Bottom Border; Borders menu item
|
||||
("HBW", Entry::Finish(Action::Command("home.drawBorder"))), // Excel: Draw Border
|
||||
("HBY", Entry::Finish(Action::Pending("home.borderLineStyle"))), // pending; Excel: Line Style; pending: Line Style submenu
|
||||
("HC", Entry::Finish(Action::Command("edit.copy"))), // Excel: Copy; fires immediately in Excel; deeper aliases dropped as unreachable
|
||||
("HDC", Entry::Finish(Action::Command("home.deleteColumns"))), // Excel: Delete Columns; Delete Columns
|
||||
("HDD", Entry::Finish(Action::Dialog("deleteCells"))), // Excel: Delete Cells
|
||||
("HDR", Entry::Finish(Action::Command("home.deleteRows"))), // Excel: Delete Rows; Delete Rows
|
||||
("HDS", Entry::Finish(Action::Command("home.deleteSheet"))), // Excel: Delete Sheet
|
||||
("HEA", Entry::Finish(Action::Command("edit.clearAll"))), // Excel: Clear All
|
||||
("HEC", Entry::Finish(Action::Command("edit.clearContents"))), // Excel: Clear Contents
|
||||
("HEF", Entry::Finish(Action::Command("edit.clearFormats"))), // Excel: Clear Formats
|
||||
("HEL", Entry::Finish(Action::Command("edit.clearHyperlinks"))), // Excel: Clear Hyperlinks
|
||||
("HEM", Entry::Finish(Action::Command("edit.clearComments"))), // Excel: Clear Comments and Notes; containment(Clear Comments and Notes)
|
||||
("HFC", Entry::Finish(Action::Control("home.fontColor"))), // Excel: Font Color; opens the font-color palette
|
||||
("HEM", Entry::Finish(Action::Command("edit.clearComments"))), // Excel: Clear Comments and Notes; containment(Clear Comments and Notes)
|
||||
("HFC", Entry::Finish(Action::Control("home.fontColor"))), // Excel: Font Color; opens the font-color palette
|
||||
("HFDC", Entry::Finish(Action::Command("home.conditionalFormat"))), // Excel: Find Conditional Formatting; containment(Conditional Formatting)
|
||||
("HFDF", Entry::Finish(Action::Dialog("find"))), // Excel: Find
|
||||
("HFDG", Entry::Finish(Action::Dialog("goTo"))), // Excel: Go To
|
||||
("HFDM", Entry::Finish(Action::Command("edit.find"))), // Excel: Find Notes; containment(Find)
|
||||
("HFDF", Entry::Finish(Action::Dialog("find"))), // Excel: Find
|
||||
("HFDG", Entry::Finish(Action::Dialog("goTo"))), // Excel: Go To
|
||||
("HFDM", Entry::Finish(Action::Command("edit.find"))), // Excel: Find Notes; containment(Find)
|
||||
("HFDO", Entry::Finish(Action::Pending("home.selectObjects"))), // pending; Excel: Select Objects; Select Objects; reserved until the command lands
|
||||
("HFDP", Entry::Finish(Action::Command("arrange.selectionPane"))), // Excel: Selection Pane
|
||||
("HFDR", Entry::Finish(Action::Dialog("find"))), // Excel: Replace; opens Find and Replace
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
" \"continue\" (an explicit group level with no deeper sequences yet).",
|
||||
" - Intermediate levels need no entries: the matcher waits automatically when deeper sequences exist.",
|
||||
" - pending: true = the command does not exist yet; the sequence stays reserved and silent until it lands.",
|
||||
" - params: an optional JSON object passed to a command or dialog, for menu items that share one id (the Borders presets: HBO {\"preset\": \"bottom\"}).",
|
||||
" - Keep entries grouped by tab and sorted by sequence within a group; the FIRST entry for a tab is its canonical badge (legacy aliases come after it)."
|
||||
],
|
||||
"sequences": [
|
||||
@@ -203,36 +204,49 @@
|
||||
"seq": "HBA",
|
||||
"kind": "command",
|
||||
"target": "home.borders",
|
||||
"params": {
|
||||
"preset": "all"
|
||||
},
|
||||
"excel": "All Borders",
|
||||
"note": "containment(Borders)"
|
||||
"note": "Borders menu item"
|
||||
},
|
||||
{
|
||||
"seq": "HBB",
|
||||
"kind": "command",
|
||||
"target": "home.borders",
|
||||
"params": {
|
||||
"preset": "doubleBottom"
|
||||
},
|
||||
"excel": "Bottom Double Border",
|
||||
"note": "border-side TBD"
|
||||
"note": "Borders menu item"
|
||||
},
|
||||
{
|
||||
"seq": "HBC",
|
||||
"kind": "command",
|
||||
"target": "home.borders",
|
||||
"params": {
|
||||
"preset": "topThickBottom"
|
||||
},
|
||||
"excel": "Top and Thick Bottom Border",
|
||||
"note": "border-side TBD"
|
||||
"note": "Borders menu item"
|
||||
},
|
||||
{
|
||||
"seq": "HBD",
|
||||
"kind": "command",
|
||||
"target": "home.borders",
|
||||
"params": {
|
||||
"preset": "topBottom"
|
||||
},
|
||||
"excel": "Top and Bottom Border",
|
||||
"note": "border-side TBD"
|
||||
"note": "Borders menu item"
|
||||
},
|
||||
{
|
||||
"seq": "HBE",
|
||||
"kind": "command",
|
||||
"target": "home.borders",
|
||||
"target": "home.eraseBorder",
|
||||
"pending": true,
|
||||
"excel": "Erase Border",
|
||||
"note": "border-side TBD"
|
||||
"note": "pending: Excel arms an eraser pen; GridCraft has no border pen mode yet"
|
||||
},
|
||||
{
|
||||
"seq": "HBG",
|
||||
@@ -245,78 +259,109 @@
|
||||
"seq": "HBH",
|
||||
"kind": "command",
|
||||
"target": "home.borders",
|
||||
"params": {
|
||||
"preset": "thickBottom"
|
||||
},
|
||||
"excel": "Thick Bottom Border",
|
||||
"note": "border-side TBD"
|
||||
"note": "Borders menu item"
|
||||
},
|
||||
{
|
||||
"seq": "HBI",
|
||||
"kind": "command",
|
||||
"target": "home.borders",
|
||||
"target": "home.borderLineColor",
|
||||
"pending": true,
|
||||
"excel": "Line Color",
|
||||
"note": "Line Color (submenu TBD)"
|
||||
"note": "pending: Line Color submenu"
|
||||
},
|
||||
{
|
||||
"seq": "HBL",
|
||||
"kind": "command",
|
||||
"target": "home.borders",
|
||||
"params": {
|
||||
"preset": "left"
|
||||
},
|
||||
"excel": "Left Border",
|
||||
"note": "border-side TBD"
|
||||
"note": "Borders menu item"
|
||||
},
|
||||
{
|
||||
"seq": "HBM",
|
||||
"kind": "command",
|
||||
"target": "home.borders",
|
||||
"kind": "dialog",
|
||||
"target": "formatCells",
|
||||
"params": {
|
||||
"tab": "Border"
|
||||
},
|
||||
"excel": "More Borders",
|
||||
"note": "containment(Borders)"
|
||||
"note": "Format Cells on its Border tab"
|
||||
},
|
||||
{
|
||||
"seq": "HBN",
|
||||
"kind": "command",
|
||||
"target": "home.borders",
|
||||
"params": {
|
||||
"preset": "none"
|
||||
},
|
||||
"excel": "No Border",
|
||||
"note": "border-side TBD"
|
||||
"note": "Borders menu item"
|
||||
},
|
||||
{
|
||||
"seq": "HBO",
|
||||
"kind": "command",
|
||||
"target": "home.borders",
|
||||
"params": {
|
||||
"preset": "bottom"
|
||||
},
|
||||
"excel": "Bottom Border",
|
||||
"note": "border-side TBD"
|
||||
"note": "Borders menu item"
|
||||
},
|
||||
{
|
||||
"seq": "HBP",
|
||||
"kind": "command",
|
||||
"target": "home.borders",
|
||||
"params": {
|
||||
"preset": "top"
|
||||
},
|
||||
"excel": "Top Border",
|
||||
"note": "border-side TBD"
|
||||
"note": "Borders menu item"
|
||||
},
|
||||
{
|
||||
"seq": "HBR",
|
||||
"kind": "command",
|
||||
"target": "home.borders",
|
||||
"params": {
|
||||
"preset": "right"
|
||||
},
|
||||
"excel": "Right Border",
|
||||
"note": "border-side TBD"
|
||||
"note": "Borders menu item"
|
||||
},
|
||||
{
|
||||
"seq": "HBS",
|
||||
"kind": "command",
|
||||
"target": "home.borders",
|
||||
"params": {
|
||||
"preset": "outside"
|
||||
},
|
||||
"excel": "Outside Borders",
|
||||
"note": "containment(Borders)"
|
||||
"note": "Borders menu item"
|
||||
},
|
||||
{
|
||||
"seq": "HBT",
|
||||
"kind": "command",
|
||||
"target": "home.borders",
|
||||
"params": {
|
||||
"preset": "thickOutside"
|
||||
},
|
||||
"excel": "Thick Outside Borders",
|
||||
"note": "border-side TBD"
|
||||
"note": "Borders menu item"
|
||||
},
|
||||
{
|
||||
"seq": "HBU",
|
||||
"kind": "command",
|
||||
"target": "home.borders",
|
||||
"params": {
|
||||
"preset": "topDoubleBottom"
|
||||
},
|
||||
"excel": "Top and Double Bottom Border",
|
||||
"note": "border-side TBD"
|
||||
"note": "Borders menu item"
|
||||
},
|
||||
{
|
||||
"seq": "HBW",
|
||||
@@ -328,9 +373,10 @@
|
||||
{
|
||||
"seq": "HBY",
|
||||
"kind": "command",
|
||||
"target": "home.borders",
|
||||
"target": "home.borderLineStyle",
|
||||
"pending": true,
|
||||
"excel": "Line Style",
|
||||
"note": "Line Style (submenu TBD)"
|
||||
"note": "pending: Line Style submenu"
|
||||
},
|
||||
{
|
||||
"seq": "HC",
|
||||
|
||||
@@ -1392,7 +1392,19 @@ impl SheetApp {
|
||||
keytips::Action::Command(id @ ("edit.copy" | "edit.cut")) => self.copy_to_clipboard(ctx, id),
|
||||
keytips::Action::Command("edit.paste") => self.paste_from_clipboard(),
|
||||
keytips::Action::Command(id) => self.run_or_alert(id, json!({})),
|
||||
keytips::Action::CommandWith(id, params) => {
|
||||
let params: Json = serde_json::from_str(params).unwrap_or_else(|_| json!({}));
|
||||
// A Borders preset picked by key tip becomes the split button's face, as a
|
||||
// click on the same menu item does.
|
||||
if id == "home.borders"
|
||||
&& let Some(preset) = params.get("preset").and_then(Json::as_str)
|
||||
{
|
||||
self.grid.last_border = preset.to_string();
|
||||
}
|
||||
self.run_or_alert(id, params);
|
||||
}
|
||||
keytips::Action::Dialog(name) => self.open_dialog(name, json!({})),
|
||||
keytips::Action::DialogWith(name, params) => self.open_dialog(name, serde_json::from_str(params).unwrap_or_else(|_| json!({}))),
|
||||
// Reserved sequence: fires silently while its command is missing. When the
|
||||
// command lands in the catalog it goes live with no table edit.
|
||||
keytips::Action::Pending(id) => {
|
||||
|
||||
@@ -316,7 +316,10 @@ fn keytip_hbd_() {
|
||||
fn keytip_hbe_() {
|
||||
let mut h = harness(blank());
|
||||
sequence(&mut h, "HBE", false);
|
||||
assert!(h.state().session.journal.iter().any(|(id, _)| id == "home.borders"), "HBE must journal home.borders");
|
||||
assert!(h.state().dialog.is_none(), "HBE must not open a dialog");
|
||||
assert!(h.state().message.is_none(), "HBE must not open a message box");
|
||||
assert!(h.state().toast.is_none(), "HBE must not raise a toast");
|
||||
assert!(h.state().session.journal.is_empty(), "HBE must not journal");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -337,7 +340,10 @@ fn keytip_hbh_() {
|
||||
fn keytip_hbi_() {
|
||||
let mut h = harness(blank());
|
||||
sequence(&mut h, "HBI", false);
|
||||
assert!(h.state().session.journal.iter().any(|(id, _)| id == "home.borders"), "HBI must journal home.borders");
|
||||
assert!(h.state().dialog.is_none(), "HBI must not open a dialog");
|
||||
assert!(h.state().message.is_none(), "HBI must not open a message box");
|
||||
assert!(h.state().toast.is_none(), "HBI must not raise a toast");
|
||||
assert!(h.state().session.journal.is_empty(), "HBI must not journal");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -351,7 +357,7 @@ fn keytip_hbl_() {
|
||||
fn keytip_hbm_() {
|
||||
let mut h = harness(blank());
|
||||
sequence(&mut h, "HBM", false);
|
||||
assert!(h.state().session.journal.iter().any(|(id, _)| id == "home.borders"), "HBM must journal home.borders");
|
||||
assert!(h.state().dialog.is_some(), "HBM must open the formatCells dialog");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -414,7 +420,10 @@ fn keytip_hbw_() {
|
||||
fn keytip_hby_() {
|
||||
let mut h = harness(blank());
|
||||
sequence(&mut h, "HBY", false);
|
||||
assert!(h.state().session.journal.iter().any(|(id, _)| id == "home.borders"), "HBY must journal home.borders");
|
||||
assert!(h.state().dialog.is_none(), "HBY must not open a dialog");
|
||||
assert!(h.state().message.is_none(), "HBY must not open a message box");
|
||||
assert!(h.state().toast.is_none(), "HBY must not raise a toast");
|
||||
assert!(h.state().session.journal.is_empty(), "HBY must not journal");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -680,3 +680,96 @@ fn font_dropdown_highlight_follows_the_filtered_rows() {
|
||||
h.run_steps(3);
|
||||
assert!(h.query_all_by_label("Georgia").count() >= 1, "an emptied filter lists every font again");
|
||||
}
|
||||
|
||||
fn borders(h: &Harness, cell: &str) -> gridcraft_engine::model::Borders {
|
||||
let d = h.state().session.active().unwrap();
|
||||
let sh = d.wb.active().unwrap();
|
||||
d.wb.styles.get(sh.style_id(CellRef::parse(cell).unwrap())).borders
|
||||
}
|
||||
|
||||
/// [left, right, top, bottom] line styles of `cell`.
|
||||
fn sides(h: &Harness, cell: &str) -> [gridcraft_engine::model::BorderStyle; 4] {
|
||||
let b = borders(h, cell);
|
||||
[b.left.style, b.right.style, b.top.style, b.bottom.style]
|
||||
}
|
||||
|
||||
fn selected(range: &str) -> Session {
|
||||
let mut s = blank();
|
||||
s.execute("selection.set", json!({"range": range})).unwrap();
|
||||
s
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn border_keytips_apply_their_own_preset() {
|
||||
use gridcraft_engine::model::BorderStyle::{Double, None as N, Thick, Thin};
|
||||
// Alt, H, B, letter on A1 alone: each Borders menu letter draws its own preset (they all drew
|
||||
// a bare bottom border before). Letters observed in Excel's Borders menu.
|
||||
for (k, want) in [
|
||||
(Key::O, [N, N, N, Thin]),
|
||||
(Key::P, [N, N, Thin, N]),
|
||||
(Key::L, [Thin, N, N, N]),
|
||||
(Key::R, [N, Thin, N, N]),
|
||||
(Key::A, [Thin, Thin, Thin, Thin]),
|
||||
(Key::S, [Thin, Thin, Thin, Thin]),
|
||||
(Key::T, [Thick, Thick, Thick, Thick]),
|
||||
(Key::B, [N, N, N, Double]),
|
||||
(Key::H, [N, N, N, Thick]),
|
||||
(Key::D, [N, N, Thin, Thin]),
|
||||
(Key::C, [N, N, Thin, Thick]),
|
||||
(Key::U, [N, N, Thin, Double]),
|
||||
] {
|
||||
let mut h = harness(selected("A1"));
|
||||
sequence(&mut h, &[Key::H, Key::B, k], false);
|
||||
assert!(h.state().message.is_none() && h.state().toast.is_none(), "H,B,{k:?} must run cleanly");
|
||||
assert_eq!(sides(&h, "A1"), want, "H,B,{k:?}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn border_keytip_no_border_clears_a_bordered_cell() {
|
||||
use gridcraft_engine::model::BorderStyle::None as N;
|
||||
let mut s = selected("A1");
|
||||
s.execute("home.borders", json!({"range": "A1", "preset": "all"})).unwrap();
|
||||
let mut h = harness(s);
|
||||
sequence(&mut h, &[Key::H, Key::B, Key::N], false);
|
||||
assert_eq!(sides(&h, "A1"), [N, N, N, N], "H,B,N must clear every side, not add a bottom border");
|
||||
assert_eq!(h.state().grid.last_border, "none", "the picked preset becomes the Borders button's face");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn border_keytip_all_borders_covers_every_side_of_a_block() {
|
||||
use gridcraft_engine::model::BorderStyle::Thin;
|
||||
let mut h = harness(selected("A1:B2"));
|
||||
sequence(&mut h, &[Key::H, Key::B, Key::A], false);
|
||||
for cell in ["A1", "B1", "A2", "B2"] {
|
||||
assert_eq!(sides(&h, cell), [Thin; 4], "H,B,A must border every side of {cell}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn border_keytip_outside_borders_skips_the_inside_edges() {
|
||||
use gridcraft_engine::model::BorderStyle::{None as N, Thin};
|
||||
let mut h = harness(selected("A1:B2"));
|
||||
sequence(&mut h, &[Key::H, Key::B, Key::S], false);
|
||||
assert_eq!(sides(&h, "A1"), [Thin, N, Thin, N]);
|
||||
assert_eq!(sides(&h, "B2"), [N, Thin, N, Thin]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn border_keytip_more_borders_opens_format_cells_on_the_border_tab() {
|
||||
let mut h = harness(blank());
|
||||
sequence(&mut h, &[Key::H, Key::B, Key::M], false);
|
||||
let d = h.state().dialog.as_ref().expect("H,B,M opens Format Cells");
|
||||
assert_eq!(d.tab, "Border");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn border_keytips_without_a_command_stay_silent() {
|
||||
// Erase Border (a pen mode), Line Color and Line Style are reserved: no border is drawn.
|
||||
for k in [Key::E, Key::I, Key::Y] {
|
||||
let mut h = harness(selected("A1"));
|
||||
sequence(&mut h, &[Key::H, Key::B, k], false);
|
||||
assert!(!h.state().session.journal.iter().any(|(id, _)| id.starts_with("home.")), "H,B,{k:?} must not run a command");
|
||||
assert_eq!(borders(&h, "A1"), Default::default(), "H,B,{k:?} must not draw a border");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user