Merge branch 'control-panel-lists-shading' into paragraph-panel-indesign

This commit is contained in:
moppeeer
2026-10-22 17:32:39 +02:00
3 changed files with 34 additions and 7 deletions
+3
View File
@@ -1270,6 +1270,9 @@ attr_set! {
number_expression: String = "^#.^t".into(),
/// Text after the bullet (metacharacters expand as in [`expand_list_text`]).
list_separator: String = "\t".into(),
/// The hanging indent was set by the Bulleted or Numbered List button, which takes it away
/// again with the list (an indent the paragraph had before stays).
list_hang: bool = false,
balance_ragged: bool = false,
optical_margin: bool = false,
/// None uses the legacy built-in rules; an empty set explicitly disables kinsoku.
+30 -6
View File
@@ -99,8 +99,8 @@ fn apply_list(s: &mut Session, p: &Value, kind: ListType) -> Result<Value> {
return;
}
let (style, _) = styles.resolve_para_style(&pf.style);
// The hanging indent set on the paragraph itself (by a list button), not by its style.
let own_hang = pf.para.left_indent == Some(LIST_HANG) && pf.para.first_line_indent == Some(-LIST_HANG);
// The hanging indent this button set (and nothing has changed since).
let own_hang = pf.para.list_hang == Some(true) && now.left_indent == LIST_HANG && now.first_line_indent == -LIST_HANG;
// A value: left to the style when it gives the same, else set here.
let mut set = |key: &str, v: Value, same: bool| {
let _ = pf.para.set_json(key, if same { &Value::Null } else { &v });
@@ -110,10 +110,15 @@ fn apply_list(s: &mut Session, p: &Value, kind: ListType) -> Result<Value> {
if on && now.left_indent == 0.0 && now.first_line_indent == 0.0 {
set("leftIndent", json!(LIST_HANG), style.left_indent == LIST_HANG);
set("firstLineIndent", json!(-LIST_HANG), style.first_line_indent == -LIST_HANG);
} else if !on && now.list_type == kind && own_hang {
// Only the hanging indent set here: one the paragraph style gives stays.
set("leftIndent", json!(0.0), style.left_indent == 0.0);
set("firstLineIndent", json!(0.0), style.first_line_indent == 0.0);
set("listHang", json!(true), false);
} else if !on && now.list_type == kind {
// Only the hanging indent set here: one the paragraph had before, or its style
// gives, stays.
if own_hang {
set("leftIndent", json!(0.0), style.left_indent == 0.0);
set("firstLineIndent", json!(0.0), style.first_line_indent == 0.0);
}
set("listHang", Value::Null, true);
}
});
}
@@ -320,6 +325,25 @@ Flour
assert_eq!(kinds(&s), [ListType::Numbers; 4]);
}
/// A paragraph's own hanging indent, the same as the button's, stays when the list goes off:
/// the button takes away only the indent it set.
#[test]
fn a_paragraphs_own_hanging_indent_stays_when_the_list_goes_off() {
let mut s = Session::new();
s.execute("file.new", &json!({})).unwrap();
let f = s.execute("frame.create", &json!({"rect": [72, 72, 400, 300], "content": "text", "text": "Eggs"})).unwrap();
let sid = f["story"].as_u64().unwrap();
s.execute("text.select", &json!({"story": sid, "anchor": 0, "focus": 4})).unwrap();
s.execute("type.para", &json!({"attrs": {"leftIndent": 18, "firstLineIndent": -18}})).unwrap();
s.execute("list.bullets", &json!({"on": true})).unwrap();
s.execute("list.bullets", &json!({"on": false})).unwrap();
let d = &s.doc().unwrap().doc;
let pf = &d.story(designcraft_doc::StoryId(sid)).unwrap().paras[0];
let p = d.styles.resolve_para(pf).0;
assert_eq!((p.list_type, p.left_indent, p.first_line_indent), (designcraft_doc::ListType::None, 18.0, -18.0));
assert_eq!(pf.para.list_hang, None, "nothing of the list left");
}
/// A hanging indent the paragraph style gives stays when the list goes off.
#[test]
fn a_style_hanging_indent_stays_when_the_list_goes_off() {
+1 -1
View File
@@ -402,7 +402,7 @@ It is evidence of breadth: each item exists. It is not a claim of InDesign-level
- Drag and drop text editing: drag selected text to move it (Alt copies) with its formatting (`text.release`).
- Input methods (IME) in the Type tool: a Chinese, Japanese or Korean composition shows its marked text in place in the story, underlined (the clause being converted twice), with the IME's candidate window at the caret through zoom, scrolling, view rotation and vertical text; the commit is one `text.insert` and one undo step, a cancelled composition leaves the document as it was; keys, shortcuts, the clipboard and Undo wait while the IME composes, and a click or another command keeps the marked text as typed. The control channel's `ui.ime` and the MCP `ime` tool (headless too) send IME events. Not yet checked by hand with a system IME (macOS, Windows, Linux, web).
- Image Import Options: place any page of a multi-page PDF (`file.place {pdfPage}`; the app asks which page), shown on screen and embedded as that page in PDF export.
- Bulleted and Numbered List buttons (Properties › Bullets and Numbering; Type › Bulleted & Numbered Lists › Apply Bullets / Apply Numbers, ✓ when the selection has them; `list.bullets`, `list.numbers`): as InDesign's, a paragraph with no indents gets the default hanging indent (Left Indent 0.25 in, First Line Indent −0.25 in), so the bullet or number sits at the margin and the text after its tab at the indent; pressed again, the list goes and so does that indent if the button set it and it is still as applied (a hanging indent the paragraph style gives stays). A selection ending right after a return leaves the next paragraph out. One undo step; values equal to the paragraph style's are left to the style.
- Bulleted and Numbered List buttons (Properties › Bullets and Numbering; Type › Bulleted & Numbered Lists › Apply Bullets / Apply Numbers, ✓ when the selection has them; `list.bullets`, `list.numbers`): as InDesign's, a paragraph with no indents gets the default hanging indent (Left Indent 0.25 in, First Line Indent −0.25 in), so the bullet or number sits at the margin and the text after its tab at the indent; pressed again, the list goes and so does that indent if the button set it (`listHang`) and it is still as applied (a hanging indent the paragraph had before, or its style gives, stays). A selection ending right after a return leaves the next paragraph out. One undo step; values equal to the paragraph style's are left to the style.
- Define Lists: named numbered lists that continue across stories in page order (`list.define`, paragraph `listName` / `startAt`), round-tripped through IDML; `null` in `type.para` / `type.char` now removes an override.
- View › Overprint Preview (⌥⇧⌘Y): overprinting fills, strokes and 100% [Black] text mix with what's beneath on screen.
- Type on a Path (⇧T tool, `type.onPath`): a story along any line, curve or shape on screen and in PDF; Type on a Path Options (start, flip, baseline/ascender/descender/centre) and Delete Type from Path. Round-trips through IDML as TextPath; on-path caret drawing is still to come.