mirror of
https://github.com/storytold/gridcraft.git
synced 2026-11-02 07:06:48 -06:00
Icon buttons no longer carry an accessible name: the tests that came with main since the branch was written (menu hover, popup dismissal, the File menu, More Colors) find Copy, Save and Cancel by label, and the Quick Access Toolbar and formula bar icons gave those labels twice. The macro tests need the names of large, small and toggle ribbon buttons only. The chart menu test takes the menu's Delete, which is drawn after the ribbon's Home > Cells > Delete. The Trust Scripts row ported into the Macros dialog is formatted.
169 lines
7.3 KiB
Rust
169 lines
7.3 KiB
Rust
//! Resizing a chart by dragging its bottom-right corner or with the Format Chart Area Size fields, through real input.
|
||
|
||
use egui::{Event, Key, Modifiers, PointerButton, accesskit::Role, pos2, vec2};
|
||
use egui_kittest::kittest::Queryable as _;
|
||
use gridcraft_engine::Session;
|
||
use gridcraft_engine::core::CellRef;
|
||
use gridcraft_ui_egui::{SheetApp, grid::Geo};
|
||
use serde_json::json;
|
||
|
||
type Harness = egui_kittest::Harness<'static, SheetApp>;
|
||
|
||
fn fixture() -> (Harness, u32) {
|
||
let mut session = Session::new();
|
||
session.new_workbook();
|
||
session.execute("cell.set", json!({"cell": "A1", "input": "1"})).unwrap();
|
||
session.execute("cell.set", json!({"cell": "A2", "input": "2"})).unwrap();
|
||
session.execute("selection.set", json!({"range": "A1:A2"})).unwrap();
|
||
let chart = session.execute("insert.chart", json!({"type": "column", "at": "D3", "width": 300, "height": 200})).unwrap();
|
||
let id = chart["chart"].as_u64().unwrap() as u32;
|
||
let mut h = egui_kittest::Harness::builder().with_size(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, id)
|
||
}
|
||
|
||
fn size(h: &Harness, id: u32) -> (f32, f32) {
|
||
let a = h.state().session.doc().unwrap().wb.active().unwrap().charts.iter().find(|c| c.id == id).unwrap().anchor;
|
||
(a.width, a.height)
|
||
}
|
||
|
||
fn corner(h: &Harness, id: u32) -> egui::Pos2 {
|
||
let app = h.state();
|
||
let sh = app.session.doc().unwrap().wb.active().unwrap();
|
||
let geo = Geo::new(sh, app.grid.rect.unwrap(), app.view().scroll);
|
||
let a = sh.charts.iter().find(|c| c.id == id).unwrap().anchor;
|
||
let min = geo.cell_rect(sh, CellRef::parse("D3").unwrap()).min + vec2(a.dx, a.dy) * geo.z;
|
||
min + vec2(a.width, a.height) * geo.z
|
||
}
|
||
|
||
fn button(h: &mut Harness, pos: egui::Pos2, pressed: bool) {
|
||
h.input_mut().events.push(Event::PointerButton { pos, button: PointerButton::Primary, pressed, modifiers: Modifiers::NONE });
|
||
h.run_steps(2);
|
||
}
|
||
|
||
#[test]
|
||
fn dragging_the_corner_handle_resizes_the_chart() {
|
||
let (mut h, id) = fixture();
|
||
let (w0, h0) = size(&h, id);
|
||
let start = corner(&h, id);
|
||
// Select the chart first, as the user does before grabbing a handle.
|
||
let inside = start - vec2(40.0, 40.0);
|
||
h.input_mut().events.push(Event::PointerMoved(inside));
|
||
h.run_steps(2);
|
||
button(&mut h, inside, true);
|
||
button(&mut h, inside, false);
|
||
assert_eq!(h.state().selected_chart, Some(id));
|
||
|
||
h.input_mut().events.push(Event::PointerMoved(start));
|
||
h.run_steps(2);
|
||
assert_eq!(h.output().platform_output.cursor_icon, egui::CursorIcon::ResizeNwSe, "the corner shows a resize cursor");
|
||
button(&mut h, start, true);
|
||
// The pointer moves well past the drag threshold in one step, like a quick drag.
|
||
let end = start + vec2(60.0, 30.0);
|
||
h.input_mut().events.push(Event::PointerMoved(pos2(end.x, end.y)));
|
||
h.run_steps(3);
|
||
button(&mut h, end, false);
|
||
let (w1, h1) = size(&h, id);
|
||
assert!(w1 > w0 + 40.0 && h1 > h0 + 20.0, "chart grew from {w0}x{h0} to {w1}x{h1}");
|
||
}
|
||
|
||
/// Opens Format Chart Area for the chart and expands its Size section; returns the Width field's rect.
|
||
fn open_size_fields(h: &mut Harness, id: u32) -> egui::Rect {
|
||
h.state_mut().selected_chart = Some(id);
|
||
h.state_mut().grid.pane = Some("formatChart".into());
|
||
h.run_steps(2);
|
||
h.get_by_role_and_label(Role::Button, "Size").click();
|
||
h.run_steps(2);
|
||
h.get_all_by_role(Role::SpinButton).next().unwrap().rect()
|
||
}
|
||
|
||
#[test]
|
||
fn typing_a_width_in_the_size_field_resizes_the_chart() {
|
||
let (mut h, id) = fixture();
|
||
let (_, h0) = size(&h, id);
|
||
let field = open_size_fields(&mut h, id);
|
||
h.input_mut().events.push(Event::PointerMoved(field.center()));
|
||
button(&mut h, field.center(), true);
|
||
button(&mut h, field.center(), false);
|
||
// Clicking the field selects its text; each keystroke must survive the next frame.
|
||
for digit in ["6", "4", "0"] {
|
||
h.input_mut().events.push(Event::Text(digit.into()));
|
||
h.run_steps(2);
|
||
}
|
||
h.key_press(Key::Enter);
|
||
h.run_steps(2);
|
||
assert_eq!(size(&h, id), (640.0, h0));
|
||
}
|
||
|
||
#[test]
|
||
fn dragging_the_size_field_resizes_the_chart() {
|
||
let (mut h, id) = fixture();
|
||
let (w0, _) = size(&h, id);
|
||
let field = open_size_fields(&mut h, id);
|
||
h.input_mut().events.push(Event::PointerMoved(field.center()));
|
||
button(&mut h, field.center(), true);
|
||
for step in 1..=6 {
|
||
h.input_mut().events.push(Event::PointerMoved(field.center() + vec2(10.0 * step as f32, 0.0)));
|
||
h.run_steps(1);
|
||
}
|
||
button(&mut h, field.center() + vec2(60.0, 0.0), false);
|
||
let (w1, _) = size(&h, id);
|
||
assert!(w1 > w0 + 20.0, "width went from {w0} to {w1}");
|
||
}
|
||
|
||
fn right_click(h: &mut Harness, pos: egui::Pos2, wobble: egui::Vec2) {
|
||
h.input_mut().events.push(Event::PointerMoved(pos));
|
||
h.run_steps(2);
|
||
h.input_mut().events.push(Event::PointerButton { pos, button: PointerButton::Secondary, pressed: true, modifiers: Modifiers::NONE });
|
||
h.run_steps(2);
|
||
let end = pos + wobble;
|
||
if wobble != vec2(0.0, 0.0) {
|
||
h.input_mut().events.push(Event::PointerMoved(end));
|
||
h.run_steps(2);
|
||
}
|
||
h.input_mut().events.push(Event::PointerButton { pos: end, button: PointerButton::Secondary, pressed: false, modifiers: Modifiers::NONE });
|
||
h.run_steps(2);
|
||
}
|
||
|
||
#[test]
|
||
fn right_clicking_a_chart_opens_its_menu_not_the_cells() {
|
||
// #2067: a right-click on a chart opened the menu of the cell under it, or nothing at all.
|
||
for wobble in [vec2(0.0, 0.0), vec2(20.0, 10.0)] {
|
||
let (mut h, id) = fixture();
|
||
let (w0, h0) = size(&h, id);
|
||
let inside = corner(&h, id) - vec2(100.0, 80.0);
|
||
right_click(&mut h, inside, wobble);
|
||
assert_eq!(h.state().selected_chart, Some(id), "the right-clicked chart is selected ({wobble:?})");
|
||
assert!(matches!(h.state().grid.object_menu, Some((_, "chart", i)) if i == id), "the chart's menu opens ({wobble:?})");
|
||
assert!(h.state().grid.context_menu.is_none(), "the cell menu stays closed ({wobble:?})");
|
||
assert_eq!(size(&h, id), (w0, h0));
|
||
let a = h.state().session.doc().unwrap().wb.active().unwrap().charts.iter().find(|c| c.id == id).unwrap().anchor;
|
||
assert_eq!(a.cell, CellRef::parse("D3").unwrap(), "a right-button drag does not move the chart ({wobble:?})");
|
||
}
|
||
// Delete from the menu removes the chart.
|
||
let (mut h, id) = fixture();
|
||
let inside = corner(&h, id) - vec2(100.0, 80.0);
|
||
right_click(&mut h, inside, vec2(0.0, 0.0));
|
||
// Home › Cells › Delete has the same accessible name; the menu is drawn over the ribbon, last.
|
||
h.get_all_by_label("Delete").last().unwrap().click();
|
||
h.run_steps(3);
|
||
assert!(h.state().session.doc().unwrap().wb.active().unwrap().charts.is_empty());
|
||
assert!(h.state().grid.object_menu.is_none());
|
||
// Outside the chart a right-click still opens the cell menu.
|
||
let (mut h, _) = fixture();
|
||
let cell = {
|
||
let app = h.state();
|
||
let sh = app.session.doc().unwrap().wb.active().unwrap();
|
||
Geo::new(sh, app.grid.rect.unwrap(), app.view().scroll).cell_rect(sh, CellRef::parse("A10").unwrap()).center()
|
||
};
|
||
right_click(&mut h, cell, vec2(0.0, 0.0));
|
||
assert!(h.state().grid.context_menu.is_some() && h.state().grid.object_menu.is_none());
|
||
}
|