mirror of
https://github.com/storytold/gridcraft.git
synced 2026-10-27 04:06:52 -06:00
The grid's look() and print's cell_look() layered a rule's fill, font and borders onto the cell style but not its num_fmt, so a cell under a rule with a number format kept its own. Take the rule's code when it isn't General (in a differential style General means "not set", as layer_under treats it). Print also re-formatted every non-General cell from its own style through display::cell_text; format with the look's code instead, through a new display::value_text_as that value_text now calls (CSV/Text output unchanged). Show Formulas keeps cell_text. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
83189c0ccd
commit
19f4387cca
@@ -650,6 +650,10 @@ fn cell_look(wb: &Workbook, si: usize, sh: &Sheet, c: CellRef, cf: &mut Option<c
|
||||
if st.font.underline != Underline::None {
|
||||
style.font.underline = st.font.underline;
|
||||
}
|
||||
// In a differential style General means "not set" (#1163).
|
||||
if st.num_fmt.as_str() != "General" {
|
||||
style.num_fmt = st.num_fmt.clone();
|
||||
}
|
||||
for (dst, src) in [
|
||||
(&mut style.borders.left, st.borders.left),
|
||||
(&mut style.borders.right, st.borders.right),
|
||||
@@ -1076,7 +1080,8 @@ fn draw_text(pg: &mut Page, b: &Block, c: CellRef, l: &Look, rect: (f32, f32, f3
|
||||
let max_chars = (avail / digit).floor().max(1.0) as usize;
|
||||
gridcraft_numfmt::format_general_fit(n, max_chars.min(11)).unwrap_or_else(|| "#".repeat(max_chars.min(255)))
|
||||
} else {
|
||||
crate::display::cell_text(wb, sh, c)
|
||||
// The look's code, which a conditional format can override (#1163).
|
||||
crate::display::value_text_as(wb, &v, code)
|
||||
};
|
||||
if !wrap {
|
||||
text = text.replace(['\n', '\r'], " ");
|
||||
@@ -1932,6 +1937,21 @@ mod tests {
|
||||
assert_eq!(expand_header_footer("&", &cx)[1].text, "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn conditional_number_format_prints() {
|
||||
// #1163: a rule's number format replaces the cell's own, whether that is General or not;
|
||||
// cells the rule doesn't match keep theirs.
|
||||
let mut s = s();
|
||||
s.execute("range.setValues", json!({"range": "A1", "values": [[1], [3], [4]]})).unwrap();
|
||||
s.execute("home.numberFormat", json!({"range": "A3", "code": "0.0"})).unwrap();
|
||||
let rule = json!({"type": "cellIs", "operator": "greater", "value": "2", "style": {"num_fmt": "0.00"}});
|
||||
s.execute("home.conditionalFormat", json!({"range": "A1:A3", "rule": rule})).unwrap();
|
||||
let (pdf, _) = pdf_of(&mut s, json!({}));
|
||||
assert!(contains(&pdf, "(1) Tj"), "an unmatched cell keeps General");
|
||||
assert!(contains(&pdf, "(3.00) Tj") && !contains(&pdf, "(3) Tj"), "General cell under the rule");
|
||||
assert!(contains(&pdf, "(4.00) Tj") && !contains(&pdf, "(4.0) Tj"), "formatted cell under the rule");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn export_writes_file() {
|
||||
let mut s = s();
|
||||
|
||||
@@ -95,7 +95,13 @@ pub fn cell_text(wb: &Workbook, sheet: &Sheet, c: CellRef) -> String {
|
||||
/// and no General narrowing (Save As CSV/Text writes this). Formulas give their result.
|
||||
pub fn value_text(wb: &Workbook, sheet: &Sheet, c: CellRef) -> String {
|
||||
let style = wb.styles.get(sheet.style_id(c));
|
||||
let f = format(&sheet.value(c), style.num_fmt.as_str(), wb);
|
||||
value_text_as(wb, &sheet.value(c), style.num_fmt.as_str())
|
||||
}
|
||||
|
||||
/// [`value_text`] for a value and a format code given apart from a cell (print takes the code
|
||||
/// from the cell's effective look, which a conditional format can override).
|
||||
pub fn value_text_as(wb: &Workbook, v: &Value, code: &str) -> String {
|
||||
let f = format(v, code, wb);
|
||||
match f.fill {
|
||||
Some((_, pos)) => {
|
||||
let mut t = f.text;
|
||||
|
||||
@@ -482,6 +482,10 @@ fn look(wb: &Workbook, si: usize, sh: &Sheet, c: CellRef, cf: &mut CfCache) -> (
|
||||
if st.font.strike {
|
||||
style.font.strike = true;
|
||||
}
|
||||
// In a differential style General means "not set" (#1163).
|
||||
if st.num_fmt.as_str() != "General" {
|
||||
style.num_fmt = st.num_fmt.clone();
|
||||
}
|
||||
for (dst, src) in [
|
||||
(&mut style.borders.left, st.borders.left),
|
||||
(&mut style.borders.right, st.borders.right),
|
||||
@@ -3406,6 +3410,28 @@ mod tests {
|
||||
assert_eq!(center_across_end(0, 1, |_| true), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn conditional_number_format_reaches_the_cell_text() {
|
||||
// #1163: a rule's number format replaces the cell's own; unmatched cells keep theirs.
|
||||
let mut session = gridcraft_engine::Session::new();
|
||||
session.new_workbook();
|
||||
session.execute("range.setValues", json!({"range": "A1", "values": [[1], [3], [4]]})).unwrap();
|
||||
session.execute("home.numberFormat", json!({"range": "A3", "code": "0.0"})).unwrap();
|
||||
let rule = json!({"type": "cellIs", "operator": "greater", "value": "2", "style": {"num_fmt": "0.00"}});
|
||||
session.execute("home.conditionalFormat", json!({"range": "A1:A3", "rule": rule})).unwrap();
|
||||
let wb = session.active().unwrap().wb.clone();
|
||||
let sh = wb.sheet(0).unwrap();
|
||||
let mut cf = CfCache::new();
|
||||
let text = |row: u32, cf: &mut CfCache| {
|
||||
let c = CellRef::new(row, 0);
|
||||
let (lk, _) = look(&wb, 0, sh, c, cf);
|
||||
display_text(&wb, sh, c, &sh.value(c), &lk.style, 200.0, 7.0).0
|
||||
};
|
||||
assert_eq!(text(0, &mut cf), "1");
|
||||
assert_eq!(text(1, &mut cf), "3.00");
|
||||
assert_eq!(text(2, &mut cf), "4.00");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn filter_menu_uses_the_table_whose_header_was_clicked() {
|
||||
use gridcraft_engine::model::Table;
|
||||
|
||||
Reference in New Issue
Block a user