mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-03 06:30:00 -06:00
M8.12: Perspective Selection tool scales, copies, moves perpendicular and nudges in perspective
The Perspective Selection tool shows the selection's bounding box in perspective; its handles scale in plane space (perspective.transform; Shift proportional, Alt from the centre). Alt-drag moves copies that stay attached, pressing 5 while dragging moves along the plane's normal (ToolKey::Digit, delivered by the canvas and MCP press_key), and the arrow keys nudge in perspective (perspective.nudge). Transform Again repeats the last perspective move or scale in plane space. Attachments (plane and depth) now live on the objects (Node.perspective), so copies, duplicates and pastes keep them; grids from older files hand theirs over. Homography moves to vectorcraft-geom. Hint-bar text for the tool. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
7df7cf568a
commit
a0847e8a25
@@ -81,6 +81,9 @@ pub struct Interaction {
|
||||
/// Per-document state restored on cancel (current layer, isolation).
|
||||
pub active_layer: Option<NodeId>,
|
||||
pub isolation: Option<NodeId>,
|
||||
/// The perspective transform the previews make (`perspective.transform` params): Transform
|
||||
/// Again repeats it once the drag is committed.
|
||||
pub perspective_again: Option<Value>,
|
||||
}
|
||||
|
||||
/// Per-document editing state.
|
||||
@@ -131,6 +134,9 @@ pub struct DocState {
|
||||
pub recovery: Option<cmd::recovery::RecoveryCopy>,
|
||||
/// View → Show Print Tiling, per document (view state: not saved, not undoable).
|
||||
pub print_tiling: bool,
|
||||
/// Transform Again after a perspective move or scale (Perspective Selection tool): the
|
||||
/// `perspective.transform` params it repeats. `None` once an ordinary transform follows.
|
||||
pub last_perspective: Option<Value>,
|
||||
}
|
||||
|
||||
static NEXT_DOC_UID: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(1);
|
||||
@@ -163,6 +169,7 @@ impl DocState {
|
||||
recovered: false,
|
||||
recovery: None,
|
||||
print_tiling: false,
|
||||
last_perspective: None,
|
||||
}
|
||||
}
|
||||
/// Unsaved changes: the document differs from the saved one (selection changes don't count).
|
||||
@@ -1052,6 +1059,7 @@ impl Session {
|
||||
preview: None,
|
||||
active_layer: st.active_layer,
|
||||
isolation: st.isolation,
|
||||
perspective_again: None,
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
@@ -1080,14 +1088,19 @@ impl Session {
|
||||
let st = self.doc_mut()?;
|
||||
let Some(mut it) = st.interaction.take() else { return Ok(()) };
|
||||
let Some(preview) = it.preview.take() else { return Ok(()) };
|
||||
let perspective_again = it.perspective_again.take();
|
||||
st.keep_interaction(it);
|
||||
if preview.0 == "object.transform" {
|
||||
let m = cmd::matrix_param(&preview.1, "matrix");
|
||||
let copy = preview.1.get("copy").and_then(Value::as_bool).unwrap_or(false);
|
||||
if let Some(m) = m {
|
||||
st.last_transform = Some((m, copy));
|
||||
st.last_perspective = None;
|
||||
}
|
||||
}
|
||||
if perspective_again.is_some() {
|
||||
st.last_perspective = perspective_again;
|
||||
}
|
||||
self.journal.push(preview);
|
||||
Ok(())
|
||||
}
|
||||
@@ -1256,6 +1269,8 @@ mod tests_pdfpresets;
|
||||
#[cfg(test)]
|
||||
mod tests_pdfraster;
|
||||
#[cfg(test)]
|
||||
mod tests_persp_select;
|
||||
#[cfg(test)]
|
||||
mod tests_perspgrid;
|
||||
#[cfg(test)]
|
||||
mod tests_place;
|
||||
|
||||
Reference in New Issue
Block a user