mirror of
https://github.com/storytold/gridcraft.git
synced 2026-10-24 10:46:50 -06:00
crates/engine/src/cmd/mod.rs: kept #2033's wrap-only branch and #2049's wrapped_line_count helper, called inside the wrap branch; dropped #2049's explicit/else arm.
This commit is contained in:
@@ -453,6 +453,38 @@ fn same_content(a: Option<&gridcraft_model::Cell>, b: Option<&gridcraft_model::C
|
||||
}
|
||||
}
|
||||
|
||||
/// Lines a single text line needs when word-wrapped into `width` points. The grid wraps whole
|
||||
/// words (egui's LayoutJob), so dividing the total width by the column width undercounts: each
|
||||
/// drawn line ends early at the last word that fits. A word wider than the column breaks
|
||||
/// mid-word, the way egui does. (#1969)
|
||||
fn wrapped_line_count(line: &str, width: f32, size: f32, bold: bool) -> f32 {
|
||||
let word_w = |w: &str| crate::cmd::format::approx_text_width(w, size, bold);
|
||||
let space_w = word_w(" ");
|
||||
let mut lines = 1.0f32;
|
||||
let mut used = 0.0f32;
|
||||
for word in line.split_whitespace() {
|
||||
let w = word_w(word);
|
||||
if w > width {
|
||||
// wider than the column: egui fills the current line, then breaks it across lines
|
||||
if used > 0.0 {
|
||||
lines += 1.0;
|
||||
}
|
||||
let chunks = (w / width).ceil();
|
||||
lines += chunks - 1.0;
|
||||
used = w - (chunks - 1.0) * width;
|
||||
continue;
|
||||
}
|
||||
let gap = if used > 0.0 { space_w } else { 0.0 };
|
||||
if used + gap + w > width {
|
||||
lines += 1.0;
|
||||
used = w;
|
||||
} else {
|
||||
used += gap + w;
|
||||
}
|
||||
}
|
||||
lines
|
||||
}
|
||||
|
||||
/// Recomputes an automatic row height from its content: the largest font, and wrapped text.
|
||||
/// Rows with a user-set height keep it.
|
||||
///
|
||||
@@ -503,7 +535,7 @@ pub fn auto_row_height(wb: &mut Workbook, si: usize, row: u32) {
|
||||
let w = sh.col_width(c).max(1.0) - 6.0;
|
||||
lines = text
|
||||
.lines()
|
||||
.map(|l| (crate::cmd::format::approx_text_width(l, size, st.font.bold) / w.max(1.0)).ceil().max(1.0))
|
||||
.map(|l| wrapped_line_count(l, w.max(1.0), size, st.font.bold))
|
||||
.sum::<f32>()
|
||||
.max(1.0);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
//! #1969: a wrapped cell's row must fit WORD-wrapped lines, not the character-fit
|
||||
//! estimate (words can't split, so each drawn line ends early and narrow columns
|
||||
//! need more lines than width/estimate suggests).
|
||||
|
||||
use gridcraft_engine::Session;
|
||||
use serde_json::json;
|
||||
|
||||
fn session() -> Session {
|
||||
let mut s = Session::new();
|
||||
s.new_workbook();
|
||||
s
|
||||
}
|
||||
|
||||
fn row_height(s: &mut Session, row: u32) -> f32 {
|
||||
s.doc().unwrap().wb.active().unwrap().row_height(row)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wrapped_row_fits_word_wrapped_lines() {
|
||||
let mut s = session();
|
||||
// Column fits ~10 characters; six-character words mean only one word per line.
|
||||
s.execute("home.columnWidth", json!({"cols": "A:A", "chars": 10})).unwrap();
|
||||
s.execute("cell.set", json!({"cell": "A1", "input": "aaaaaa bbbbbb cccccc dddddd"})).unwrap();
|
||||
let plain = row_height(&mut s, 0);
|
||||
s.execute("home.wrapText", json!({"range": "A1", "on": true})).unwrap();
|
||||
let wrapped = row_height(&mut s, 0);
|
||||
// Word wrap: 4 lines (one word each). The old estimate: ceil(28/10) = 3 lines.
|
||||
// Line height at 11pt is ~19.8, so 4 lines need ~79 vs ~59 for 3.
|
||||
assert!(wrapped >= plain + 3.0 * 19.0, "4 word-wrapped lines must grow the row by ~4 line heights: plain={plain}, wrapped={wrapped}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn issue_repro_nasa_sentence() {
|
||||
let mut s = session();
|
||||
s.execute("home.columnWidth", json!({"cols": "A:A", "chars": 12})).unwrap();
|
||||
s.execute("cell.set", json!({"cell": "A1", "input": "Since the 1960s, NASA has left hardware across the solar system\u{2013}on the Moon, on Mars, and in deep space."}))
|
||||
.unwrap();
|
||||
s.execute("home.wrapText", json!({"range": "A1", "on": true})).unwrap();
|
||||
let h = row_height(&mut s, 0);
|
||||
// Excel shows this at ~10 lines in a 12-char column; the character estimate undercounts.
|
||||
assert!(h >= 9.0 * 19.0, "NASA sentence in a 12-char column needs ~10 lines, got height {h}");
|
||||
}
|
||||
Reference in New Issue
Block a user