Objects: the Format Chart Size fields show a chart's real size and send only the edited dimension

The Width and Height fields ranged 40 to 4,000 and sent both values on
every edit. egui clamps an existing value into a field's range, so a
chart a file made 12,000 wide showed "Width 4000", and typing a new
height sent that 4,000 as the width: the chart shrank although only its
height changed, and the cap `chart.set` keeps for an existing size
cannot help once the pane itself sends 4,000. Each field's range now
reaches the larger of 4,000 and the chart's current size, so the field
shows the real size, and a commit sends only the dimension that differs
from the chart's (`chart.set` reads `width` and `height` independently).

Test (real input): the_size_fields_keep_an_oversized_imported_chart_width_when_the_height_changes
reopens a workbook with a 12,000-wide chart, opens Format Chart Area's
Size section, checks the Width field shows 12000 and types 201 as the
height: the width stays 12,000, the height is 201 and the journaled
chart.set carries no width. Without the fix the field shows
"Width 4000".
This commit is contained in:
prxnvt
2026-11-02 02:03:47 -05:00
parent af28f01bfd
commit 05851de46c
2 changed files with 65 additions and 4 deletions
+20 -4
View File
@@ -308,13 +308,29 @@ fn format_chart(app: &mut SheetApp, ui: &mut Ui) {
ui.collapsing("Size", |ui| {
// Keep the value being typed or dragged between frames; reloading it from the chart every frame threw the edit away.
let draft = egui::Id::unique(("gridcraft.chart_size_draft", id));
let (mut w, mut h) = ui.data_mut(|d| d.get_temp::<(f32, f32)>(draft)).unwrap_or((chart.anchor.width, chart.anchor.height));
let a = ui.add(egui::DragValue::new(&mut w).prefix("Width ").range(40.0..=4000.0));
let b = ui.add(egui::DragValue::new(&mut h).prefix("Height ").range(40.0..=4000.0));
let current = (chart.anchor.width, chart.anchor.height);
let (mut w, mut h) = ui.data_mut(|d| d.get_temp::<(f32, f32)>(draft)).unwrap_or(current);
// A file can make a chart larger than the 4,000 points a field otherwise reaches. The
// range keeps such a size, so the field shows it instead of clamping it to 4,000.
let range = |v: f32| 40.0..=v.max(4000.0);
let a = ui.add(egui::DragValue::new(&mut w).prefix("Width ").range(range(current.0)));
let b = ui.add(egui::DragValue::new(&mut h).prefix("Height ").range(range(current.1)));
if a.drag_stopped() || a.lost_focus() || b.drag_stopped() || b.lost_focus() {
ui.data_mut(|d| d.remove::<(f32, f32)>(draft));
if !ui.input(|i| i.key_pressed(egui::Key::Escape)) {
app.run_or_alert("chart.set", json!({"chart": id, "width": w, "height": h}));
// Only an edited dimension is sent: the other keeps what the chart has, however
// large a file made it.
let mut params = serde_json::Map::new();
params.insert("chart".into(), json!(id));
if w != current.0 {
params.insert("width".into(), json!(w));
}
if h != current.1 {
params.insert("height".into(), json!(h));
}
if params.len() > 1 {
app.run_or_alert("chart.set", Json::Object(params));
}
}
} else if a.dragged() || a.has_focus() || b.dragged() || b.has_focus() {
ui.data_mut(|d| d.insert_temp(draft, (w, h)));
+45
View File
@@ -118,6 +118,51 @@ fn dragging_the_size_field_resizes_the_chart() {
assert!(w1 > w0 + 20.0, "width went from {w0} to {w1}");
}
/// Makes the chart 12,000 wide and reopens the workbook from its XLSX bytes, the way a file can
/// carry a chart larger than the 4,000 points the Size fields otherwise reach; returns its id.
fn imported_oversized_chart(h: &mut Harness, id: u32) -> u32 {
{
let wb = std::sync::Arc::make_mut(&mut h.state_mut().session.doc_mut().unwrap().wb);
wb.sheet_mut(0).unwrap().charts.iter_mut().find(|c| c.id == id).unwrap().anchor.width = 12_000.0;
}
let saved = h.state_mut().run("file.saveBytes", json!({"format": "xlsx"})).unwrap();
h.state_mut().run("file.open", json!({"name": "wide.xlsx", "base64": saved["base64"]})).unwrap();
h.run_steps(4);
let id = h.state().session.doc().unwrap().wb.active().unwrap().charts[0].id;
let (w, hh) = size(h, id);
assert_eq!((w.round(), hh.round()), (12_000.0, 200.0), "the reader keeps the file's size");
id
}
/// A chart a file made 12,000 wide shows that width in the Size fields, and a new height sends
/// the height alone, so nothing shrinks the width to the fields' 4,000 reach on the way.
#[test]
fn the_size_fields_keep_an_oversized_imported_chart_width_when_the_height_changes() {
let (mut h, id) = fixture();
let id = imported_oversized_chart(&mut h, id);
open_size_fields(&mut h, id);
let (width_value, height_field) = {
let mut fields = h.get_all_by_role(Role::SpinButton);
let width = fields.next().unwrap();
let height = fields.next().unwrap();
(width.value(), height.rect())
};
assert!(width_value.as_deref().is_some_and(|v| v.contains("12000")), "the field shows the file's width: {width_value:?}");
h.input_mut().events.push(Event::PointerMoved(height_field.center()));
button(&mut h, height_field.center(), true);
button(&mut h, height_field.center(), false);
for digit in ["2", "0", "1"] {
h.input_mut().events.push(Event::Text(digit.into()));
h.run_steps(2);
}
h.key_press(Key::Enter);
h.run_steps(2);
let (w, hh) = size(&h, id);
assert_eq!((w.round(), hh), (12_000.0, 201.0), "the width stays and the height is the typed one");
let (_, p) = h.state().session.journal.iter().rev().find(|(cmd, _)| cmd == "chart.set").unwrap();
assert!(p.get("width").is_none(), "a height edit sends no width: {p}");
}
fn right_click(h: &mut Harness, pos: egui::Pos2, wobble: egui::Vec2) {
h.input_mut().events.push(Event::PointerMoved(pos));
h.run_steps(2);