mirror of
https://github.com/storytold/designcraft.git
synced 2026-11-01 06:06:49 -06:00
Merge PR #902: Direct Selection: pressing on a corner of an unselected object pulls just that corner
This commit is contained in:
@@ -459,6 +459,7 @@ Newest first.
|
||||
- **2026-10-21** · With a gradient fill or stroke, the Color panel shows the stop selected in the Gradient panel (the stop before a selected midpoint) with its values, and its C/M/Y/K or R/G/B sliders and spectrum colour that stop, keeping the others, as in InDesign. It showed "[None] — choose a colour on the ramp", and a spectrum click replaced the whole gradient with a flat colour. Found in the Learn Skills Daily course, chapter 24. No readiness percentage change.
|
||||
- **2026-10-20** · A new document's Swatches panel lists InDesign's defaults: [None], [Registration], [Paper], [Black] and six process colours (C=100, M=100, Y=100, C=15 M=100 Y=100, C=75 M=5 Y=100, C=100 M=90 Y=10); the extra M=100 Y=100, C=100 Y=100 and C=100 M=100 swatches are gone. No readiness percentage change.
|
||||
- **2026-10-21** · The readout beside the cursor while drawing or measuring ("W: 3.13 cm") is InDesign's light grey box with white text, measured from the tutorials' frames; High Contrast keeps it black. It was a dark translucent box. No readiness percentage change.
|
||||
- **2026-10-14** · The Direct Selection tool pressed on a corner or anchor of an object that isn't selected selects it and pulls just that point, as in InDesign (it moved the whole object). No readiness percentage change.
|
||||
- **2026-10-21** · Properties › Character and Paragraph: ••• (More Options) expands the section in place, as InDesign's: Character adds vertical and horizontal scale, baseline shift, skew, language and OpenType, and All Caps, Small Caps, Superscript, Subscript, Underline and Strikethrough; Paragraph adds the left, right, first line and last line indents, space before and after, the drop cap's lines and characters, Align to Baseline Grid and Hyphenate. It used to open the Character or Paragraph panel; the language field moved under ••• as in InDesign. Found in the Learn Skills Daily course, chapter 16. No readiness percentage change.
|
||||
- **2026-10-21** · The text Control panel has InDesign's two modes: A (Character Formatting Controls: font and style, size and leading, All Caps/Superscript/Underline and Small Caps/Subscript/Strikethrough, kerning and tracking, vertical and horizontal scale, baseline shift and skew, character style and language) and ¶ (Paragraph Formatting Controls: the nine alignments, left/first line and right/last line indents, space before and after, the drop cap's lines and characters, paragraph style, Hyphenate and Align to Baseline Grid). It used to show a fixed mix of both. Found in the Learn Skills Daily course, chapter 16. No readiness percentage change.
|
||||
- **2026-10-20** · With the Type tool, the Control panel's font size, leading and tracking fields have a spinner and a list of common values, as in InDesign (auto leading in parentheses). No readiness percentage change.
|
||||
|
||||
@@ -1661,6 +1661,48 @@ fn a_line_fits_when_its_baseline_does() {
|
||||
assert!(overset(&mut s, 50.0), "a baseline below the frame still oversets the line");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn direct_selection_pulls_one_corner_of_an_unselected_frame() {
|
||||
// Chris Nielsen's "The Adobe InDesign Toolbox" (10:10): with the White Arrow, click outside,
|
||||
// then press on a frame's corner and pull it: only that corner moves (a triangle, nearly).
|
||||
use designcraft_tools::{PointerEvent, PointerKind, SnapView};
|
||||
let mut s = Session::new();
|
||||
s.execute("file.new", &json!({"width": 612, "height": 792, "facingPages": false})).unwrap();
|
||||
let id = s.execute("frame.create", &json!({"rect": [156, 219, 455, 569], "content": "graphic"})).unwrap()["id"].as_u64().unwrap();
|
||||
s.execute("edit.deselectAll", &json!({})).unwrap();
|
||||
let corners = |s: &Session| {
|
||||
let d = &s.doc().unwrap().doc;
|
||||
let it = d.item(designcraft_doc::ItemId(id)).unwrap();
|
||||
it.path.subpaths[0].anchors.iter().map(|a| it.xf * a.p).collect::<Vec<_>>()
|
||||
};
|
||||
let before = corners(&s);
|
||||
s.set_tool("directSelection");
|
||||
let v = ViewInfo { snap: SnapView::OFF, ..ViewInfo::at_zoom(1.0) };
|
||||
let layout = s.layout();
|
||||
let at = |x: f64, y: f64| layout.to_canvas(designcraft_doc::SpreadRef::Doc(0), designcraft_geom::Point::new(x, y));
|
||||
let (a, b) = (at(455.0, 219.0), at(455.0, 150.0));
|
||||
s.pointer(&PointerEvent::new(PointerKind::Down, a.x, a.y), v).unwrap();
|
||||
s.pointer(&PointerEvent::new(PointerKind::Drag, a.x, a.y - 30.0), v).unwrap();
|
||||
s.pointer(&PointerEvent::new(PointerKind::Drag, b.x, b.y), v).unwrap();
|
||||
s.pointer(&PointerEvent::new(PointerKind::Up, b.x, b.y), v).unwrap();
|
||||
let after = corners(&s);
|
||||
let moved: Vec<_> = before.iter().zip(&after).filter(|(p, q)| (**p - **q).hypot() > 1e-6).collect();
|
||||
assert_eq!(moved.len(), 1, "one corner moved: {before:?} → {after:?}");
|
||||
assert!((*moved[0].1 - designcraft_geom::Point::new(455.0, 150.0)).hypot() < 1e-6, "{after:?}");
|
||||
assert_eq!(s.doc().unwrap().selection.items, [designcraft_doc::ItemId(id)], "the frame is selected");
|
||||
// One undo step puts the corner back.
|
||||
s.execute("edit.undo", &json!({})).unwrap();
|
||||
assert_eq!(corners(&s), before);
|
||||
// Away from its corners, the White Arrow still drags the whole unselected frame.
|
||||
s.execute("edit.deselectAll", &json!({})).unwrap();
|
||||
let (c, d) = (at(300.0, 219.0), at(300.0, 269.0));
|
||||
s.pointer(&PointerEvent::new(PointerKind::Down, c.x, c.y), v).unwrap();
|
||||
s.pointer(&PointerEvent::new(PointerKind::Drag, c.x, c.y + 20.0), v).unwrap();
|
||||
s.pointer(&PointerEvent::new(PointerKind::Drag, d.x, d.y), v).unwrap();
|
||||
s.pointer(&PointerEvent::new(PointerKind::Up, d.x, d.y), v).unwrap();
|
||||
assert!(corners(&s).iter().zip(&before).all(|(p, q)| (p.y - q.y - 50.0).abs() < 1e-6), "{:?}", corners(&s));
|
||||
}
|
||||
|
||||
/// Issue #1637: with several objects selected, a click on one of them (no drag) makes it the key
|
||||
/// object, and Align to Key Object leaves it in place. A second click on it drops the key.
|
||||
#[test]
|
||||
|
||||
@@ -703,6 +703,19 @@ impl SelectionTool {
|
||||
self.drag = Drag::Anchor { id, si, ai, handle, start: p, at };
|
||||
return vec![Action::Begin(if handle.is_some() { "Move Direction Handle".into() } else { "Move Anchor".into() })];
|
||||
}
|
||||
// As in InDesign, the Direct Selection tool pressed on a corner or anchor of an object
|
||||
// that isn't selected selects it and moves just that point (Chris Nielsen's "The
|
||||
// InDesign Toolbox", 10:10: click outside, then pull a frame's corner).
|
||||
if self.direct
|
||||
&& !ev.mods.shift
|
||||
&& let Some((_, hit)) = cx.hit(p)
|
||||
&& !cx.selection.contains(hit)
|
||||
&& let Some((id, si, ai, None)) = anchor_at_in(cx, &[hit], p)
|
||||
{
|
||||
let at = anchor_spread_point(cx, id, si, ai);
|
||||
self.drag = Drag::Anchor { id, si, ai, handle: None, start: p, at };
|
||||
return vec![Action::Exec("selection.set".into(), json!({"ids": [id], "content": true})), Action::Begin("Move Anchor".into())];
|
||||
}
|
||||
// A selected placed graphic's own handles resize it inside its frame (the
|
||||
// frame's anchors, under Direct Selection, come first).
|
||||
if let Some((id, h)) = content_handle_at(cx, p)
|
||||
|
||||
Reference in New Issue
Block a user