mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-28 19:57:05 -06:00
M7: per-paragraph paragraph attributes
Each paragraph has its own alignment, indents, spacing, hyphenation, tab stops and paragraph style (TextObject.paras; para stays paragraph 0's, so old files and readers work). Layout, editing (split/merge), threads, the Paragraph/Tabs/Paragraph Styles panels, ranged text.setStyle/setFormat/ tabs/paraStyle.apply, SVG export/import and the fuzzers follow.
This commit is contained in:
@@ -75,14 +75,24 @@ pub(crate) fn reflow(before: &Document, doc: &mut Document) {
|
||||
});
|
||||
// The story: live frames' runs, plus the text of frames deleted by this edit.
|
||||
let mut story: Vec<TextRun> = vec![];
|
||||
let mut sources: Vec<TextObject> = vec![];
|
||||
let mut later_wins = vec![];
|
||||
let mut live = vec![];
|
||||
for id in &thread {
|
||||
match (text_of(doc, *id), text_of(before, *id)) {
|
||||
(Some(t), _) => {
|
||||
(Some(t), old) => {
|
||||
story.extend(t.runs.iter().cloned());
|
||||
// A frame whose first paragraph was just restyled gives the paragraph it
|
||||
// shares with the frame before it that style.
|
||||
later_wins.push(old.is_some_and(|o| o.para_at(0) != t.para_at(0)));
|
||||
sources.push(t.clone());
|
||||
live.push(*id);
|
||||
}
|
||||
(None, Some(old)) => story.extend(old.runs.iter().cloned()),
|
||||
(None, Some(old)) => {
|
||||
story.extend(old.runs.iter().cloned());
|
||||
later_wins.push(false);
|
||||
sources.push(old.clone());
|
||||
}
|
||||
(None, None) => {}
|
||||
}
|
||||
}
|
||||
@@ -92,6 +102,8 @@ pub(crate) fn reflow(before: &Document, doc: &mut Document) {
|
||||
}
|
||||
continue;
|
||||
}
|
||||
let source_refs: Vec<&TextObject> = sources.iter().collect();
|
||||
let paras = vectorcraft_text::thread::story_paras(&source_refs, &later_wins);
|
||||
vectorcraft_text::edit::normalize(&mut story);
|
||||
if live.len() >= 2 {
|
||||
// Threaded frames keep their size: Auto Size is off for them (as in Illustrator).
|
||||
@@ -105,13 +117,18 @@ pub(crate) fn reflow(before: &Document, doc: &mut Document) {
|
||||
}
|
||||
let frames: Vec<TextObject> = live.iter().filter_map(|id| text_of(doc, *id).cloned()).collect();
|
||||
let refs: Vec<&TextObject> = frames.iter().collect();
|
||||
let parts = vectorcraft_text::thread::distribute(vectorcraft_text::FontDb::global(), &refs, &story);
|
||||
for (id, runs) in live.iter().zip(parts) {
|
||||
if let Some(NodeKind::Text(t)) = doc.node_mut(*id).map(|n| &mut n.kind)
|
||||
&& t.runs != runs
|
||||
{
|
||||
t.runs = runs;
|
||||
refresh_bounds(t);
|
||||
let parts = vectorcraft_text::thread::distribute(vectorcraft_text::FontDb::global(), &refs, &story, ¶s);
|
||||
for (id, part) in live.iter().zip(parts) {
|
||||
if let Some(NodeKind::Text(t)) = doc.node_mut(*id).map(|n| &mut n.kind) {
|
||||
let mut next = (**t).clone();
|
||||
next.runs = part.runs;
|
||||
next.set_paragraph_styles(part.paras);
|
||||
if next.runs != t.runs || next.para != t.para || next.paras != t.paras {
|
||||
t.runs = next.runs;
|
||||
t.para = next.para;
|
||||
t.paras = next.paras;
|
||||
refresh_bounds(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
if live.len() >= 2 {
|
||||
@@ -193,15 +210,17 @@ fn release(s: &mut Session, _: &Value) -> Result<Value> {
|
||||
continue;
|
||||
}
|
||||
let mut story: Vec<TextRun> = vec![];
|
||||
for id in &thread {
|
||||
if let Some(t) = text_of(d, *id) {
|
||||
story.extend(t.runs.iter().cloned());
|
||||
}
|
||||
let sources: Vec<TextObject> = thread.iter().filter_map(|id| text_of(d, *id).cloned()).collect();
|
||||
for t in &sources {
|
||||
story.extend(t.runs.iter().cloned());
|
||||
}
|
||||
let paras = vectorcraft_text::thread::story_paras(&sources.iter().collect::<Vec<_>>(), &[]);
|
||||
let style = story.first().map(|r| r.style.clone()).unwrap_or_default();
|
||||
let first_para = paras.first().cloned().unwrap_or_default();
|
||||
for id in &out {
|
||||
if let Some(NodeKind::Text(t)) = d.node_mut(*id).map(|n| &mut n.kind) {
|
||||
t.runs = vec![TextRun { text: String::new(), style: style.clone() }];
|
||||
t.set_all_paras(first_para.clone());
|
||||
refresh_bounds(t);
|
||||
}
|
||||
}
|
||||
@@ -210,6 +229,7 @@ fn release(s: &mut Session, _: &Value) -> Result<Value> {
|
||||
{
|
||||
vectorcraft_text::edit::normalize(&mut story);
|
||||
t.runs = story;
|
||||
t.set_paragraph_styles(paras);
|
||||
}
|
||||
let i = d.text_threads.iter().position(|t| *t == thread).unwrap_or(0);
|
||||
d.text_threads[i] = keep;
|
||||
|
||||
Reference in New Issue
Block a user