Files
gridcraft/crates/ui-egui/tests/it/in_cell_editor_wrap.rs
T
aiongg a7608ada6d CI: one test binary per crate, nextest, line tables only (#2372)
* CI: dev builds keep line tables only

* CI: one integration-test binary per crate

* CI: xtask runs tests with nextest, doctests apart, --keep-going on clippy and wasm

cargo xtask test runs the workspace tests (--lib --bins --tests) with cargo-nextest when it is installed, else cargo test, then the doctests. cargo xtask ci uses the same two steps.

* CI: docs name cargo xtask test

* CI: agent guides name the moved fuzz test

* CI: tests added on main join their crate's test binary
2026-10-23 12:59:46 -04:00

107 lines
5.4 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! The in-cell editor of a Wrap Text cell keeps the column's width and wraps, growing down, as
//! Excel's does; it used to widen to one long line.
use egui::{Context, Id, RawInput, Rect, pos2, vec2};
use gridcraft_engine::Session;
use gridcraft_ui_egui::SheetApp;
use serde_json::json;
const TEXT: &str = "Since the 1960s, NASA has left hardware across the solar system, on the Moon, on Mars, and in deep space.";
/// Runs a few frames of the app in a 1200 × 800 window.
fn frames(ctx: &Context, app: &mut SheetApp) {
for _ in 0..4 {
let mut output =
ctx.run_ui(RawInput { screen_rect: Some(Rect::from_min_size(pos2(0.0, 0.0), vec2(1200.0, 800.0))), ..Default::default() }, |ui| {
let ctx = ui.ctx().clone();
app.logic(&ctx);
app.ui(ui);
});
output.textures_delta.clear();
}
}
/// The editor's text field rect while A1 (narrow, wrap on or off) is edited with [`TEXT`].
fn editor_rect(wrap: bool) -> Rect {
let ctx = Context::default();
let mut session = Session::new();
session.new_workbook();
session.execute("home.columnWidth", json!({"cols": "A:A", "chars": 12})).unwrap();
session.execute("home.wrapText", json!({"range": "A1", "on": wrap})).unwrap();
let mut app = SheetApp::new(session, Default::default());
frames(&ctx, &mut app);
app.begin_edit(Some(TEXT.into()), false);
frames(&ctx, &mut app);
ctx.read_response(Id::new("gridcraft.cell_editor")).expect("the in-cell editor is shown").rect
}
#[test]
fn a_wrap_text_cell_edits_wrapped_at_the_column_width() {
let wrapped = editor_rect(true);
let one_line = editor_rect(false);
assert!(one_line.width() > 400.0, "without Wrap Text the editor widens to the text: {one_line:?}");
assert!(wrapped.width() < 120.0, "with Wrap Text the editor keeps the column's width: {wrapped:?}");
assert!(wrapped.height() > 4.0 * one_line.height(), "and grows down to show every line: {wrapped:?} vs {one_line:?}");
}
/// A short Wrap Text edit stays one line tall: the field doesn't reserve rows over the cells below.
#[test]
fn a_short_wrap_text_edit_stays_one_line_tall() {
let ctx = Context::default();
let mut session = Session::new();
session.new_workbook();
session.execute("home.wrapText", json!({"range": "A1", "on": true})).unwrap();
let mut app = SheetApp::new(session, Default::default());
frames(&ctx, &mut app);
app.begin_edit(Some("short".into()), false);
frames(&ctx, &mut app);
let field = ctx.read_response(Id::new("gridcraft.cell_editor")).expect("the in-cell editor is shown").rect;
assert!(field.height() < 30.0, "a one-line edit doesn't reach over the rows below: {field:?}");
}
/// The editor is sized from the text wrapped where the field wraps it: the editor's width less its
/// 2 px inset a side, with no text margin (the field has no frame). Measured narrower, the editor
/// would count rows the field doesn't have and reach over the cells below.
#[test]
fn the_editor_measures_the_text_at_the_fields_wrap_width() {
let ctx = Context::default();
let mut session = Session::new();
session.new_workbook();
session.execute("home.columnWidth", json!({"cols": "A:A", "chars": 12})).unwrap();
session.execute("home.wrapText", json!({"range": "A1", "on": true})).unwrap();
let mut app = SheetApp::new(session, Default::default());
frames(&ctx, &mut app);
app.begin_edit(Some(TEXT.into()), false);
frames(&ctx, &mut app);
let field = ctx.read_response(Id::new("gridcraft.cell_editor")).expect("the in-cell editor is shown").rect;
let sheet = app.session.active().unwrap().wb.active().unwrap().clone();
let st = app.session.active().unwrap().wb.styles.get(sheet.style_id(gridcraft_engine::cell(0, 0))).clone();
// The grid draws at its zoom: the cell is the field plus the 2 px inset a side, the font scales.
let z = (field.width() + 4.0) / sheet.col_width(0);
let font = egui::FontId::new(st.font.size * 96.0 / 72.0 * z, gridcraft_ui_egui::theme::cell_family(&st.font.name, st.font.bold, st.font.italic));
let at =
|w: f32| ctx.fonts_mut(|f| f.layout_job(egui::text::LayoutJob::simple(TEXT.into(), font.clone(), egui::Color32::PLACEHOLDER, w)).size().y);
let (own, with_margin) = (at(field.width()), at(field.width() - 8.0));
assert!(own != with_margin, "the test text must wrap differently 8 px narrower");
assert!((field.height() - own).abs() < 1.0, "the field wraps at its whole width, no text margin: {} vs {own}", field.height());
}
/// An edit with line breaks (Alt+Enter) in a cell without Wrap Text shows every line: the field's
/// one row is a minimum, it grows with the text and never scrolls.
#[test]
fn an_unwrapped_multiline_edit_shows_every_line() {
let field = |text: &str| {
let ctx = Context::default();
let mut session = Session::new();
session.new_workbook();
let mut app = SheetApp::new(session, Default::default());
frames(&ctx, &mut app);
app.begin_edit(Some(text.into()), false);
frames(&ctx, &mut app);
ctx.read_response(Id::new("gridcraft.cell_editor")).expect("the in-cell editor is shown").rect
};
let one = field("one").height();
let three = field("one\ntwo\nthree").height();
assert!(three > 2.5 * one, "three lines are shown: {three} vs one line {one}");
assert!(three < 3.5 * one, "and no more rows are reserved: {three} vs one line {one}");
}