mirror of
https://github.com/storytold/gridcraft.git
synced 2026-10-24 10:46:50 -06:00
In-cell editor: a Wrap Text cell edits wrapped at the column width
The in-cell editor ignored Wrap Text: it widened to the text's one-line width, up to the grid's right edge, so a long wrapped cell became one unmanageable line while edited. With Wrap Text on it now keeps the column's width, wraps, and grows down to show every line, as Excel's does. The multiline field is one row tall at least, not four, so a short edit doesn't reach over the rows below.
This commit is contained in:
@@ -279,7 +279,13 @@ pub fn editor_widget(app: &mut SheetApp, ui: &mut egui::Ui, id: egui::Id, font:
|
||||
job.wrap.max_width = if multiline { wrap_width } else { f32::INFINITY };
|
||||
ui.fonts_mut(|f| f.layout_job(job))
|
||||
};
|
||||
let edit = if multiline || ed.text.contains('\n') { TextEdit::multiline(&mut ed.text) } else { TextEdit::singleline(&mut ed.text) };
|
||||
// The in-cell editor is as tall as its lines (a multiline field reserves four rows).
|
||||
let in_cell = id == egui::Id::new("gridcraft.cell_editor");
|
||||
let edit = if multiline || ed.text.contains('\n') {
|
||||
TextEdit::multiline(&mut ed.text).desired_rows(if in_cell { 1 } else { 4 })
|
||||
} else {
|
||||
TextEdit::singleline(&mut ed.text)
|
||||
};
|
||||
let mut output = edit
|
||||
.id(id)
|
||||
.frame(egui::Frame::NONE)
|
||||
|
||||
@@ -2707,10 +2707,18 @@ fn in_cell_editor(app: &mut SheetApp, ui: &mut egui::Ui, geo: &Geo, sh: &Sheet,
|
||||
let st = wb.styles.get(sh.style_id(cell)).clone();
|
||||
let size = st.font.size * 96.0 / 72.0 * geo.z;
|
||||
let font = FontId::new(size, theme::cell_family(&st.font.name, st.font.bold, st.font.italic));
|
||||
let text_w = ui.painter().layout_no_wrap(ed.text.clone(), font.clone(), Color32::BLACK).size().x;
|
||||
let lines = ed.text.lines().count().max(1) as f32 + if ed.text.ends_with('\n') { 1.0 } else { 0.0 };
|
||||
let w = (text_w + 14.0).max(rect.width()).min(geo.cells.right() - rect.left());
|
||||
let h = (size * 1.3 * lines + 4.0).max(rect.height());
|
||||
// Wrap Text: the editor keeps the column's width and wraps, growing down as Excel's does.
|
||||
// Otherwise it widens to the text's one-line width.
|
||||
let wrap = st.align.wrap;
|
||||
let (w, h) = if wrap {
|
||||
// The field's own margins (4 px a side) and the 2 px inset leave this much for the text.
|
||||
let wrapped = ui.painter().layout(ed.text.clone(), font.clone(), Color32::BLACK, (rect.width() - 12.0).max(1.0));
|
||||
(rect.width(), (wrapped.size().y.max(size * 1.3 * lines) + 4.0).max(rect.height()))
|
||||
} else {
|
||||
let text_w = ui.painter().layout_no_wrap(ed.text.clone(), font.clone(), Color32::BLACK).size().x;
|
||||
((text_w + 14.0).max(rect.width()).min(geo.cells.right() - rect.left()), (size * 1.3 * lines + 4.0).max(rect.height()))
|
||||
};
|
||||
// Grows to the left on a right-to-left sheet.
|
||||
let erect = geo.mirror_rect(Rect::from_min_size(rect.min, vec2(w, h)));
|
||||
let fill = match st.fill.pattern {
|
||||
@@ -2729,7 +2737,7 @@ fn in_cell_editor(app: &mut SheetApp, ui: &mut egui::Ui, geo: &Geo, sh: &Sheet,
|
||||
let id = egui::Id::new("gridcraft.cell_editor");
|
||||
let mut child = ui.new_child(egui::UiBuilder::new().max_rect(erect.shrink2(vec2(2.0, 1.0))));
|
||||
child.set_clip_rect(clip);
|
||||
crate::formula_bar::editor_widget(app, &mut child, id, font, false, erect.width() - 4.0);
|
||||
crate::formula_bar::editor_widget(app, &mut child, id, font, wrap, erect.width() - 4.0);
|
||||
}
|
||||
|
||||
/// Test the popup itself, not whether the pointer is over any part of the app.
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
//! 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:?}");
|
||||
}
|
||||
Reference in New Issue
Block a user