mirror of
https://github.com/storytold/wordcraft.git
synced 2026-10-24 10:27:44 -06:00
The dialog shows line spacing as a multiple, so Exactly and At Least read as 1.0, and OK (and Tabs…) always sent that back as Multiple 1.0. Accepting the dialog unchanged, or changing only Keep with next, turned a fixed rule into single spacing. The dialog now remembers the value it showed and sends line spacing only when it changed, as it already does for Asian Typography. A changed value still sets a multiple. generated with Claude Code Co-authored-by: Brandon Thomas <echelon@gmail.com>
This commit is contained in:
co-authored by
Brandon Thomas
parent
0652e7f72f
commit
29ee256c86
@@ -159,7 +159,12 @@ pub enum Dialog {
|
||||
first: f32,
|
||||
before: f32,
|
||||
after: f32,
|
||||
/// Line spacing as a multiple; Exactly and At Least show as 1.0.
|
||||
line: f32,
|
||||
/// `line` when the dialog opened: OK keeps the paragraph's spacing, whatever its rule,
|
||||
/// unless this changed (#467).
|
||||
#[serde(skip)]
|
||||
line_was: f32,
|
||||
keep_next: bool,
|
||||
keep_lines: bool,
|
||||
page_break: bool,
|
||||
@@ -969,6 +974,7 @@ impl Dialog {
|
||||
before: rp.space_before,
|
||||
after: rp.space_after,
|
||||
line,
|
||||
line_was: line,
|
||||
keep_next: rp.keep_next,
|
||||
keep_lines: rp.keep_lines,
|
||||
page_break: rp.page_break_before,
|
||||
@@ -1503,6 +1509,7 @@ fn body(app: &mut WordApp, ui: &mut Ui, d: &mut Dialog) -> bool {
|
||||
before,
|
||||
after,
|
||||
line,
|
||||
line_was,
|
||||
keep_next,
|
||||
keep_lines,
|
||||
page_break,
|
||||
@@ -1620,7 +1627,7 @@ fn body(app: &mut WordApp, ui: &mut Ui, d: &mut Dialog) -> bool {
|
||||
*first,
|
||||
*before,
|
||||
*after,
|
||||
*line,
|
||||
(*line, *line_was),
|
||||
[*keep_next, *keep_lines, *page_break, *widow],
|
||||
(*opts, *opts_was),
|
||||
);
|
||||
@@ -2762,11 +2769,12 @@ fn apply_paragraph(
|
||||
first: f32,
|
||||
before: f32,
|
||||
after: f32,
|
||||
line: f32,
|
||||
line: (f32, f32),
|
||||
flags: [bool; 4],
|
||||
opts: ([bool; 4], [bool; 4]),
|
||||
) {
|
||||
let [keep_next, keep_lines, page_break, widow] = flags;
|
||||
let (line, line_was) = line;
|
||||
// Direction first: the alignment and indents are as seen on the page, and their logical
|
||||
// values depend on it.
|
||||
let _ = app.run(if rtl { "para.rtl" } else { "para.ltr" }, json!({}));
|
||||
@@ -2774,9 +2782,15 @@ fn apply_paragraph(
|
||||
let (start, end) = if rtl { (right, left) } else { (left, right) };
|
||||
let mut props = json!({
|
||||
"indentLeft": start * crate::options::unit().pt_per_unit(), "indentRight": end * crate::options::unit().pt_per_unit(), "indentFirst": first * crate::options::unit().pt_per_unit(),
|
||||
"spaceBefore": before, "spaceAfter": after, "lineSpacing": {"rule": "multiple", "value": line},
|
||||
"spaceBefore": before, "spaceAfter": after,
|
||||
"keepNext": keep_next, "keepLines": keep_lines, "pageBreakBefore": page_break, "widowControl": widow,
|
||||
});
|
||||
// The dialog edits only multiples: an untouched value keeps Exactly and At Least.
|
||||
if line != line_was
|
||||
&& let Some(m) = props.as_object_mut()
|
||||
{
|
||||
m.insert("lineSpacing".into(), json!({"rule": "multiple", "value": line}));
|
||||
}
|
||||
let (now, was) = opts;
|
||||
for (key, (on, was)) in ["mirrorIndents", "contextualSpacing", "suppressLineNumbers", "suppressHyphens"].into_iter().zip(now.into_iter().zip(was))
|
||||
{
|
||||
@@ -3135,14 +3149,40 @@ mod tests {
|
||||
/// Open the Paragraph dialog, change its options (`opts`) with `edit` and press OK.
|
||||
fn ok_with(app: &mut WordApp, edit: impl FnOnce(&mut [bool; 4])) {
|
||||
let Some(Dialog::Paragraph {
|
||||
rtl, align, left, right, first, before, after, line, keep_next, keep_lines, page_break, widow, mut opts, ..
|
||||
rtl,
|
||||
align,
|
||||
left,
|
||||
right,
|
||||
first,
|
||||
before,
|
||||
after,
|
||||
line,
|
||||
line_was,
|
||||
keep_next,
|
||||
keep_lines,
|
||||
page_break,
|
||||
widow,
|
||||
mut opts,
|
||||
..
|
||||
}) = Dialog::open("paragraph", app)
|
||||
else {
|
||||
panic!("no paragraph dialog")
|
||||
};
|
||||
let was = opts;
|
||||
edit(&mut opts);
|
||||
apply_paragraph(app, rtl, &align, left, right, first, before, after, line, [keep_next, keep_lines, page_break, widow], (opts, was));
|
||||
apply_paragraph(
|
||||
app,
|
||||
rtl,
|
||||
&align,
|
||||
left,
|
||||
right,
|
||||
first,
|
||||
before,
|
||||
after,
|
||||
(line, line_was),
|
||||
[keep_next, keep_lines, page_break, widow],
|
||||
(opts, was),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -3191,6 +3231,60 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn paragraph_dialog_keeps_fixed_line_spacing() {
|
||||
use wordcraft_doc::props::LineSpacing;
|
||||
for (cmd, rule) in [(json!({"exactly": 24}), LineSpacing::Exactly(24.0)), (json!({"atLeast": 24}), LineSpacing::AtLeast(24.0))] {
|
||||
// OK without changes, and OK after changing only Keep with next (#467).
|
||||
let mut app = app_with("Example");
|
||||
let _ = app.run("para.lineSpacing", cmd.clone());
|
||||
ok_unchanged(&mut app);
|
||||
assert_eq!(props(&app).line_spacing, Some(rule), "unchanged OK, {cmd}");
|
||||
let Some(Dialog::Paragraph { rtl, align, left, right, first, before, after, line, line_was, keep_lines, page_break, widow, .. }) =
|
||||
Dialog::open("paragraph", &mut app)
|
||||
else {
|
||||
panic!("no paragraph dialog")
|
||||
};
|
||||
apply_paragraph(
|
||||
&mut app,
|
||||
rtl,
|
||||
&align,
|
||||
left,
|
||||
right,
|
||||
first,
|
||||
before,
|
||||
after,
|
||||
(line, line_was),
|
||||
[true, keep_lines, page_break, widow],
|
||||
([false; 4], [false; 4]),
|
||||
);
|
||||
let p = props(&app);
|
||||
assert_eq!((p.line_spacing, p.keep_next), (Some(rule), Some(true)), "Keep with next, {cmd}");
|
||||
}
|
||||
// A changed value still sets a multiple.
|
||||
let mut app = app_with("Example");
|
||||
let _ = app.run("para.lineSpacing", json!({"exactly": 24}));
|
||||
let Some(Dialog::Paragraph { rtl, align, left, right, first, before, after, line_was, keep_next, keep_lines, page_break, widow, .. }) =
|
||||
Dialog::open("paragraph", &mut app)
|
||||
else {
|
||||
panic!("no paragraph dialog")
|
||||
};
|
||||
apply_paragraph(
|
||||
&mut app,
|
||||
rtl,
|
||||
&align,
|
||||
left,
|
||||
right,
|
||||
first,
|
||||
before,
|
||||
after,
|
||||
(1.5, line_was),
|
||||
[keep_next, keep_lines, page_break, widow],
|
||||
([false; 4], [false; 4]),
|
||||
);
|
||||
assert_eq!(props(&app).line_spacing, Some(LineSpacing::Multiple(1.5)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn font_dialog_sets_the_asian_and_latin_fonts_separately() {
|
||||
// #505: the Asian text font box and the Latin text font box each set their own font, and
|
||||
@@ -3223,7 +3317,7 @@ mod tests {
|
||||
#[test]
|
||||
fn paragraph_dialog_changes_direction() {
|
||||
let mut app = app_with("Hello");
|
||||
let Some(Dialog::Paragraph { align, left, right, first, before, after, line, keep_next, keep_lines, page_break, widow, .. }) =
|
||||
let Some(Dialog::Paragraph { align, left, right, first, before, after, line, line_was, keep_next, keep_lines, page_break, widow, .. }) =
|
||||
Dialog::open("paragraph", &mut app)
|
||||
else {
|
||||
panic!()
|
||||
@@ -3238,7 +3332,7 @@ mod tests {
|
||||
first,
|
||||
before,
|
||||
after,
|
||||
line,
|
||||
(line, line_was),
|
||||
[keep_next, keep_lines, page_break, widow],
|
||||
([false; 4], [false; 4]),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user