Direct Selection: an anchor of type on a path's path drags and the type reflows along it (part of #3980)

This commit is contained in:
Marco Arnulfo
2026-10-24 22:06:20 +02:00
parent 8bf090b253
commit ec97ee2c80
7 changed files with 158 additions and 22 deletions
+40
View File
@@ -97,6 +97,15 @@ pub fn specs() -> Vec<CommandSpec> {
has_doc,
reshape_area
),
cmd!(
"text.reshapePath",
"Reshape Type Path",
[],
None,
"{id, anchors: [[subpath, anchor]…], dx, dy} move anchors of type on a path's path by dx, dy points, with their handles; the start and end brackets keep their fractions of the path and the text reflows along it (what Direct Selection does dragging an anchor of the path)",
has_doc,
reshape_path
),
cmd!(
"text.fitHeadline",
"Fit Headline",
@@ -1066,6 +1075,37 @@ fn reshape_area(s: &mut Session, p: &Value) -> Result<Value> {
ok()
}
fn reshape_path(s: &mut Session, p: &Value) -> Result<Value> {
const C: &str = "text.reshapePath";
let id = id_param(p, "id").ok_or_else(|| bad(C, "missing id"))?;
let mut refs = super::select::checked_refs(p.get("anchors"), C)?;
refs.sort_unstable();
refs.dedup();
if refs.is_empty() {
return Err(bad(C, "missing anchors [[subpath, anchor]…]"));
}
let d = Vec2::new(f64_req(p, "dx", C)?, f64_req(p, "dy", C)?);
let node = s.doc()?.doc.node(id);
let on_path = matches!(node.map(|n| &n.kind), Some(NodeKind::Text(t)) if matches!(t.kind, vectorcraft_doc::TextKind::OnPath { .. }));
if !on_path || node.is_some_and(|n| n.extras().perspective.is_some()) {
return Err(bad(C, "not type on a path outside perspective"));
}
s.edit("Reshape Type Path", |doc, _| {
let Some(NodeKind::Text(t)) = doc.node_mut(id).map(|n| &mut n.kind) else { return Err(EngineError::NoNode(id)) };
let before = t.kind.clone();
let within = |t: &TextObject| {
t.type_path().and_then(|p| p.bounds()).is_some_and(|b| [b.x0, b.y0, b.x1, b.y1].iter().all(|v| v.abs() <= crate::MAX_COORD))
};
if !(t.move_path_anchors(&refs, d) && within(t)) {
t.kind = before;
return Err(bad(C, "no such path anchor, or the path would reach past the canvas"));
}
refresh_bounds(t);
Ok(())
})?;
ok()
}
#[cfg(test)]
mod area_tests {
use super::*;