Draw Inside marks the corners of the object it draws into (#4319)

This commit is contained in:
bflatastic
2026-10-30 17:12:17 +07:00
parent 9b3b662f5d
commit 89b673a826
5 changed files with 71 additions and 4 deletions
+2 -1
View File
@@ -58,7 +58,7 @@ use outline::KEY_OUTLINE;
use outline::{OVERLAY_MAX_ANCHORS, c32, node_outline, walk_drawn};
#[cfg(test)]
use overlays::selected_anchor;
use overlays::{HandleLook, draw_overlays, hover_highlight, ime_geometry, selection_overlay};
use overlays::{HandleLook, draw_inside_overlay, draw_overlays, hover_highlight, ime_geometry, selection_overlay};
pub(crate) use raster::color_image;
use raster::{changed_pixels, pixel_region, upload};
use task_bar::task_bar;
@@ -792,6 +792,7 @@ fn selection_visuals(
hover_highlight(app, painter, xf);
}
selection_overlay(app, painter, xf, overlays.iter().any(|o| matches!(o, Overlay::CurvePoint { .. })));
draw_inside_overlay(app, painter, xf);
mirror_axis_overlay(app, painter, xf);
grid_repeat_overlay(app, painter, xf);
if app.ui.view.text_threads {
+21
View File
@@ -24,6 +24,27 @@ pub(super) fn hover_highlight(app: &VectorcraftApp, p: &egui::Painter, xf: &Xf)
}
}
/// Draw Inside (Shift+D): while the mode lasts, a dotted open rectangle round the corners of the
/// object drawn into, selected or not (#4319).
pub(super) fn draw_inside_overlay(app: &VectorcraftApp, p: &egui::Painter, xf: &Xf) {
if app.session.draw_mode != vectorcraft_engine::DrawMode::Inside {
return;
}
let (Some(id), Some(st)) = (app.session.draw_inside, app.session.active()) else { return };
let Some(bounds) = st.doc.node(id).and_then(|n| n.visual_bounds()) else { return };
// A few pixels outside the object, clear of its stroke.
let pad = 4.0 / xf.zoom;
let [a, b, c, d] = xf.quad(bounds.inflate(pad, pad))[..] else { return };
let stroke = Stroke::new(1.0, c32(st.doc.layer_color(id)));
for (corner, sides) in [(a, [b, d]), (b, [c, a]), (c, [d, b]), (d, [a, c])] {
for next in sides {
// Each arm runs a third of its side at most, so the rectangle stays open.
let arm = ((next - corner).length() / 3.0).min(16.0);
p.extend(Shape::dashed_line(&[corner, corner + (next - corner).normalized() * arm], stroke, 3.0, 2.0));
}
}
}
/// Selected anchors are drawn slightly deeper than the layer colour (#4f80ff → #3d82ff for Layer 1).
pub(super) fn selected_anchor(c: Color32) -> Color32 {
if c == Color32::from_rgb(0x4f, 0x80, 0xff) { Color32::from_rgb(0x3d, 0x82, 0xff) } else { c }
+42
View File
@@ -7937,3 +7937,45 @@ fn text_threads_skip_the_links_of_a_frame_in_perspective() {
// One thread line (c to d) and its two arrows of three strokes each.
assert_eq!(o.iter().filter(|x| matches!(x, Overlay::Line { .. })).count(), 7);
}
/// #4319: Draw Inside marks the object it draws into with a dotted open rectangle round its
/// corners while the mode lasts, selected or not, and the marks go with the mode.
#[test]
fn draw_inside_marks_the_corners_of_its_object() {
let mut app = VectorcraftApp::new(Session::new(), Default::default());
app.run("file.new", json!({"width": 400, "height": 300})).unwrap();
let id =
vectorcraft_doc::NodeId(app.run("shape.rectangle", json!({"x": 100, "y": 100, "width": 120, "height": 90})).unwrap()["id"].as_u64().unwrap());
let ctx = egui::Context::default();
let color = c32(app.session.active().unwrap().doc.layer_color(id));
// The marks' dashes: one-pixel dashes in the layer colour no longer than a dash.
let dashes = |app: &mut VectorcraftApp| -> Vec<[Pos2; 2]> {
shapes(app, &ctx)
.into_iter()
.filter_map(|s| match s {
Shape::LineSegment { points, stroke } if stroke.color == color && stroke.width == 1.0 && points[0].distance(points[1]) <= 3.01 => {
Some(points)
}
_ => None,
})
.collect()
};
let normal = dashes(&mut app).len();
app.run("view.drawMode", json!({"mode": "inside"})).unwrap();
let marks = dashes(&mut app);
// Eight arms of 16 px, each four dashes of 3 px with 2 px gaps.
assert_eq!(marks.len() - normal, 32, "{marks:?}");
let xf = Xf::new(app.canvas_rect.unwrap(), app.view().unwrap());
let b = app.session.active().unwrap().doc.node(id).unwrap().visual_bounds().unwrap();
let corner = xf.to_screen(Point::new(b.x0, b.y0)) - vec2(4.0, 4.0);
assert!(marks.iter().any(|m| m[0].distance(corner) < 2.0), "a mark starts at the padded top-left corner");
// Deselected, the object is still marked.
app.run("select.set", json!({"ids": []})).unwrap();
assert_eq!(dashes(&mut app).len(), marks.len());
// Rotated, the arms follow the object's turned sides.
app.view_mut().unwrap().rotation = 30.0;
assert_eq!(dashes(&mut app).len(), marks.len());
app.view_mut().unwrap().rotation = 0.0;
app.run("view.drawMode", json!({"mode": "normal"})).unwrap();
assert_eq!(dashes(&mut app).len(), normal);
}
+3 -2
View File
@@ -1,6 +1,6 @@
# Parity with Adobe Illustrator
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-30 · **Change:** minor (Effects: bounded effect length inputs clamp on commit and reject invalid text visibly (#4638)) · **Target:** Adobe Illustrator 2026 (30.x; public release notes through 30.7, August 2026)
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-30 · **Change:** minor (Draw Inside marks the corners of the object it draws into (#4319); scores unchanged) · **Target:** Adobe Illustrator 2026 (30.x; public release notes through 30.7, August 2026)
## Feature submission evidence
@@ -666,7 +666,7 @@ Moved from the ROADMAP's "Shipped so far" on 2026-10-10. Update it when a featur
- **Compound paths:** Make keeps the backmost object's appearance and each contour; selecting a member in Direct Selection reads and changes the compound's fill rule in Attributes. Direction remains a per-member edit. Rendered holes, unchanged contour geometry, no-op history and Undo/Redo are covered by `engine/tests/it/compound_attributes.rs` (#1197). Behaviour reference: [public compound-path documentation](https://helpx.adobe.com/illustrator/desktop/manage-objects/reshape-transform-objects/create-compound-paths.html). Make Compound Path on a group (such as outlined type) keeps the paint of its backmost path instead of drawing nothing, and compound paths joined into one keep their holes (#1537).
- **Saved selections:** Select ▸ Save Selection… asks for a name and keeps the selection in the document (saved with the file, undoable, up to 25); each one is listed at the bottom of the Select menu and a click selects its objects again; Edit Selection… lists them to rename or delete, applied together on OK. A file's saved selections are capped and checked against its objects when it opens.
Select ▸ Update Selection replaces the objects of the saved selection last recalled with the selected objects, in one undo step that marks the document changed (`select.update`). After Edit Selection… renames that saved selection, Update Selection replaces it under the new name; after Edit Selection… deletes it, Update Selection is disabled until another saved selection is recalled or the delete is undone. Undo and Redo do not change which saved selection is recalled.
- **Drawing modes:** in Draw Inside, a double-click with a selection tool outside the object being drawn into sets the drawing mode to Draw Normal, as Shift+D does. Pastes follow the drawing mode ([drawing modes](https://helpx.adobe.com/illustrator/desktop/draw-shapes-and-paths/learn-drawing-basics/drawing-modes-overview.html)) (#3705): in Draw Inside, Paste, Paste in Place and Paste on All Artboards put the copies inside the object drawn into, in one undo step, Paste Remembers Layers aside; in Draw Behind, Paste in Place and Paste on All Artboards put them just below the selection; Paste in Front and Paste in Back ignore the mode. Shift+D cycles Draw Normal → Draw Behind → Draw Inside → Draw Normal, skipping Draw Inside unless one path, compound path or type is selected. With the object drawn into isolated (a double-click on it with the Selection tool), art drawn or pasted inside it takes isolation mode into its clip group, so it can be clicked and isn't dimmed, as art added in isolation mode belongs with what is isolated ([isolation mode](https://helpx.adobe.com/illustrator/desktop/manage-objects/select-objects/isolate-objects.html)) (#3705); undo or redo that removes the isolated object ends isolation mode.
- **Drawing modes:** in Draw Inside, a double-click with a selection tool outside the object being drawn into sets the drawing mode to Draw Normal, as Shift+D does. Pastes follow the drawing mode ([drawing modes](https://helpx.adobe.com/illustrator/desktop/draw-shapes-and-paths/learn-drawing-basics/drawing-modes-overview.html)) (#3705): in Draw Inside, Paste, Paste in Place and Paste on All Artboards put the copies inside the object drawn into, in one undo step, Paste Remembers Layers aside; in Draw Behind, Paste in Place and Paste on All Artboards put them just below the selection; Paste in Front and Paste in Back ignore the mode. Shift+D cycles Draw Normal → Draw Behind → Draw Inside → Draw Normal, skipping Draw Inside unless one path, compound path or type is selected. With the object drawn into isolated (a double-click on it with the Selection tool), art drawn or pasted inside it takes isolation mode into its clip group, so it can be clicked and isn't dimmed, as art added in isolation mode belongs with what is isolated ([isolation mode](https://helpx.adobe.com/illustrator/desktop/manage-objects/select-objects/isolate-objects.html)) (#3705); undo or redo that removes the isolated object ends isolation mode. While Draw Inside lasts, a dotted open rectangle marks the corners of the object drawn into (#4319).
- **Drawing:** Pen, Curvature, anchor tools, Pencil, Paintbrush, Blob Brush, Smooth, Path Eraser, Join. Direction handles dragged with Direct Selection or the Anchor Point tool snap to smart guides, and Shift keeps them at 45° steps from their anchor. The Pen continues any open path from the end clicked, and while drawing, a click on an end of another open path joins the two into one (#776). The Curvature tool edits any selected path, whatever drew it, keeping its shape except where edited (#798): a click on a point makes it current and a drag moves it, re-curving only its two segments; Alt-click or double-click toggles it smooth or corner and Delete removes it; a click on a segment adds a point without changing the shape; with an end of an open path current, clicks go on from it and its other end closes it (`path.curvatureEdit`). Every point a drawing tool places snaps to Smart Guides through one snapper (#506): the Pen's and Curvature tool's anchors, the Pencil's ends, the shape tools' start and dragged corner or radius (Rectangle, Rounded Rectangle, Ellipse, Polygon, Star, Line Segment, Arc, Spiral, the grids), the Type tool's click and frame, a new artboard's corners. A filled Pencil path keeps a stroke of None (#1804, part of #1679). While a Pencil or Paintbrush stroke is drawn back to within Close Paths When Ends Are Within of its start, the cursor shows the closing ring and a release there closes the path, as [Draw straight lines with the Pencil tool](https://helpx.adobe.com/illustrator/desktop/draw-shapes-and-paths/draw-shapes/draw-straight-lines-with-the-pencil-tool.html) describes for the Pencil. The [ and ] keys reach the Blob Brush, the Eraser and the Symbolism tools in the app (#1734, part of #1661).
Blob Brush and Eraser Tool Options' Size is Fixed or Pressure with a Variation (#4590, #3961): with Pressure a pen stroke is Size − Variation wide where it presses lightest and Size + Variation where it presses hardest, and a mouse stroke keeps the Size.
With the Blob Brush, Shift held during a drag keeps the stroke on the horizontal or vertical line through the press point, whichever is nearer to the pointer (90° steps from the Constrain Angle preference), and the points dragged since Shift went down move to the other line when the pointer crosses to it; the points dragged while Shift is up follow the pointer.
@@ -1260,6 +1260,7 @@ undo step, with any adjustment and its params; bad requests refused) and `addons
| Date | Change | Summary |
|---|---|---|
| 2026-10-30 | minor | Draw Inside marks the corners of the object it draws into (#4319); scores and estimates unchanged |
| 2026-10-30 | minor | Smart Pen add-on (a VectorCraft addition): evidence added; scores unchanged. |
| 2026-10-30 | minor | Path Precision Tools add-on (a VectorCraft addition): evidence added; scores unchanged. |
| 2026-10-30 | minor | Color Effects, a built-in add-on beyond Illustrator; scores and estimates unchanged |
+3 -1
View File
@@ -1,6 +1,6 @@
# UI and interaction parity
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-30 · **Change:** minor (Smart Pen add-on: its tool, panel and Object › Plug-ins submenu; scores unchanged) · **Target:** Adobe Illustrator 2026 (30.x)
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-30 · **Change:** minor (Draw Inside marks the corners of the object it draws into (#4319); scores unchanged) · **Target:** Adobe Illustrator 2026 (30.x)
## Feature submission evidence
@@ -101,6 +101,7 @@ tools, never checked side by side) isn't captured row by row.
| Simplify (slider, auto, corner angle threshold), of a whole path or of the part of it selected with Direct Selection ([manually simplify paths](https://helpx.adobe.com/illustrator/desktop/draw-shapes-and-paths/modify-paths/manually-simplify-paths.html)) | done | Tolerance, default-on Preview and original/new point counts (#1272); Corner Point Angle Threshold, Convert to Straight Lines and Show Original Path; the slider under the selection with Auto-Simplify and More Options, opening at the Auto-Simplify level for the selection with that result previewed, and the dialog's option to open it directly with its last settings. With anchors or segments direct-selected, the slider, Auto-Simplify and the dialog refit only each run of selected segments between its end anchors, a closed path's run across its start point included; the rest of the path stays exactly as it was (`tests/simplify_part.rs`, `simplify_slider_and_dialog_simplify_only_the_direct_selected_part_of_a_path`) |
| Smooth (Object › Path › Smooth…: slider from minimum to maximum smoothing, Auto-Smooth) ([smooth slider](https://helpx.adobe.com/illustrator/desktop/draw-shapes-and-paths/modify-paths/refine-path-segments-with-the-smooth-slider.html)) | done | #4115: the slider under the selection previews `object.path.smooth {level}`, Auto-Smooth picks level 50, Enter or a click outside keeps one undo step and Escape restores; the smoothing rule beyond the two ends is VectorCraft's own (`tests/smooth_path.rs`, `smooth_slider_previews_auto_smooth_and_keeps_the_result`) |
| Draw Inside in isolation mode: art drawn or pasted inside the isolated object takes isolation mode into its clip group, clickable and undimmed ([isolation mode](https://helpx.adobe.com/illustrator/desktop/manage-objects/select-objects/isolate-objects.html), [drawing modes](https://helpx.adobe.com/illustrator/desktop/draw-shapes-and-paths/learn-drawing-basics/drawing-modes-overview.html)) | done | #3705; `drawing_inside_an_isolated_object_keeps_the_new_art_in_isolation_mode` |
| Draw Inside marks the object it draws into: a dotted open rectangle round its corners, in its layer's colour, while the mode lasts, selected or not | done | #4319, `canvas::tests::draw_inside_marks_the_corners_of_its_object` ([drawing modes](https://helpx.adobe.com/illustrator/desktop/draw-shapes-and-paths/learn-drawing-basics/drawing-modes-overview.html)) |
| Simplify (slider, auto, corner angle threshold) | partial | Tolerance, default-on Preview and original/new point counts (#1272); Corner Point Angle Threshold, Convert to Straight Lines and Show Original Path; the slider under the selection with Auto-Simplify and More Options, and the dialog's option to open it directly with its last settings; the slider opens at 1 pt rather than at the Auto-Simplify level, and simplifying only a Direct Selection part of a path remains missing |
| Simplify (slider, auto, corner angle threshold) | partial | Tolerance, default-on Preview and original/new point counts (#1272); Corner Point Angle Threshold, Convert to Straight Lines and Show Original Path; the slider under the selection with Auto-Simplify and More Options, opening at the Auto-Simplify level for the selection with that result previewed, and the dialog's option to open it directly with its last settings; simplifying only a Direct Selection part of a path remains missing |
@@ -365,6 +366,7 @@ separate. Scores and hours unchanged. [Behavior and command details](development
| Date | Change | Summary |
|---|---|---|
| 2026-10-30 | minor | Draw Inside marks the corners of the object it draws into (#4319); scores and estimates unchanged |
| 2026-10-30 | minor | Smart Pen add-on (a VectorCraft addition): its tool, panel and Object › Plug-ins › Smart Pen; scores and estimates unchanged |
| 2026-10-30 | minor | Path Precision Tools add-on (a VectorCraft addition): its tools, Anchor Inspector panel and Object › Plug-ins › Path Precision Tools; scores and estimates unchanged |
| 2026-10-30 | minor | Color Effects add-on: its effects, panel and Object › Plug-ins submenu; scores and estimates unchanged |