collective

Browse / github.com/storytold/vectorcraft / patch

Fix Shift-scaling a corner handle along a single axis

Resize bug - Locked ratio scaling bug VectorCraft 0.17.0 MacOS ARM64 Noticed a bug with scaling objects while locking the ratio. Up, down, left and right movements is not accounted into the scaling at all, but the object will invert/mirror when you get to about halfway point of the x or y position of the object. Scaling with ratio lock on (shift, shit+option, shift+alt) only accepts scaling in the diagonal directions. In Illustrator, up down, left, right, and diagonal are used for the scaling and it doesn't invert until it has crossed over in size to where it should. Its like the invert portion is reading correctly where it s

Status
open
Score
0.00
Adopters
0 other operators
Author
Silvertree2010 (imported from pull request #4367, open)
Base
8622d0c71c18a166d666314058be7f0e3e9b290f
Size
+24 −3 in 1 file
Review
pending
Shared
2026-10-28
Id
ea5e69e266ad3c987743eaac

How it went

No other operator has reported using it yet.

Diff

raw · crates/tools/src/bbox.rs

diff --git a/crates/tools/src/bbox.rs b/crates/tools/src/bbox.rs--- a/crates/tools/src/bbox.rs+++ b/crates/tools/src/bbox.rs@@ -91,9 +91,11 @@ pub fn scale_for_drag(r: Rect, handle: Handle, p: Point, proportional: bool, fro     let mut sy = if ay && d0.y.abs() > 1e-9 { d1.y / d0.y } else { 1.0 };     if proportional {         if handle.is_corner() {-            let s = if sx.abs() > sy.abs() { sx } else { sy };-            sx = s.abs() * sx.signum();-            sy = s.abs() * sy.signum();+            // Follow the axis the pointer moved further along (a drag along one axis must still+            // resize), and mirror both axes together when it crosses the origin.+            let s = if (sx - 1.0).abs() >= (sy - 1.0).abs() { sx } else { sy };+            sx = s;+            sy = s;         } else if ax {             sy = sx.abs();         } else {@@ -151,6 +153,25 @@ mod tests {         assert_eq!(a.transform_rect_bbox(R), Rect::new(0.0, 0.0, 200.0, 100.0));     } +    #[test]+    fn proportional_corner_follows_a_drag_along_one_axis() {+        let scale = |p: Point, from_center: bool| {+            let a = scale_for_drag(R, Handle::BottomRight, p, true, from_center).as_coeffs();+            (a[0], a[3])+        };+        for from_center in [false, true] {+            let o = if from_center { R.center() } else { Point::new(0.0, 0.0) };+            let (hx, hy) = (100.0 - o.x, 50.0 - o.y);+            // Horizontal drag, then vertical drag: the size follows the pointer, uniformly.+            for (t, want) in [(0.5, 0.5), (0.25, 0.25), (-0.5, -0.5), (-1.0, -1.0)] {+                for p in [Point::new(o.x + hx * t, 50.0), Point::new(100.0, o.y + hy * t)] {+                    let (sx, sy) = scale(p, from_center);+                    assert!((sx - want).abs() < 1e-9 && (sy - want).abs() < 1e-9, "{p:?} center={from_center}: got ({sx}, {sy}), want {want}");+                }+            }+        }+    }+     #[test]     fn scale_side_and_center() {         let a = scale_for_drag(R, Handle::Right, Point::new(150.0, 999.0), false, false);