fix: addressing issues

This commit is contained in:
DominicTheD3v
2026-10-30 22:51:33 +00:00
parent 82adf7326e
commit e812da58df
4 changed files with 41 additions and 9 deletions
+9 -3
View File
@@ -5504,6 +5504,7 @@ fn pending_resize_autofit(s: &mut Session, ids: &[u64]) {
.unwrap();
}
/// Resizing multiple selected shapes scales them proportionally around their anchors in one undo step.
#[test]
fn resizing_selected_shapes_is_one_undo_step() {
let (mut s, [a, b]) = resize_selection_scene();
@@ -5512,7 +5513,7 @@ fn resizing_selected_shapes_is_one_undo_step() {
let down = drag_gesture(&mut s, (200.0, 180.0), (250.0, 210.0));
assert_eq!(down["hit"]["kind"], "resize");
assert_eq!(down["hit"]["id"], a);
for (id, expected) in [(a, [100.0, 100.0, 150.0, 110.0]), (b, [120.0, 300.0, 130.0, 130.0])] {
for (id, expected) in [(a, [100.0, 100.0, 150.0, 110.0]), (b, [120.0, 300.0, 120.0, 137.5])] {
let actual = box_of(&mut s, id);
for (key, value) in ["x", "y", "w", "h"].into_iter().zip(expected) {
assert_eq!(actual[key], value, "{id}: {key}");
@@ -5526,6 +5527,7 @@ fn resizing_selected_shapes_is_one_undo_step() {
assert_eq!(s.doc().unwrap().doc, after, "one redo resizes both shapes again");
}
/// Resizing selected shapes refits their text boxes inside the same undo transaction.
#[test]
fn resizing_selected_shapes_refits_text_in_the_same_undo_step() {
let (mut s, ids) = resize_selection_scene();
@@ -5545,6 +5547,7 @@ fn resizing_selected_shapes_refits_text_in_the_same_undo_step() {
assert_eq!(s.doc().unwrap().doc, after, "redo includes the final text fit");
}
/// Clicking a resize handle without dragging neither modifies shapes nor triggers text autofit.
#[test]
fn clicking_a_resize_handle_does_not_change_or_refit_selected_shapes() {
let (mut s, ids) = resize_selection_scene();
@@ -5566,6 +5569,7 @@ fn clicking_a_resize_handle_does_not_change_or_refit_selected_shapes() {
assert_ne!(s.doc().unwrap().doc, before);
}
/// Locked shapes in a multi-selection are excluded from both resizing and post-resize text fitting.
#[test]
fn resizing_selected_shapes_skips_locked_shapes_and_their_text_fit() {
let (mut s, [a, b]) = resize_selection_scene();
@@ -5584,6 +5588,7 @@ fn resizing_selected_shapes_skips_locked_shapes_and_their_text_fit() {
assert_eq!(s.doc().unwrap().doc, before);
}
/// Resizing selected shapes excludes other selected resize targets from smart-guide snapping.
#[test]
fn resizing_selected_shapes_does_not_snap_to_other_resize_targets() {
for reverse in [false, true] {
@@ -5594,10 +5599,11 @@ fn resizing_selected_shapes_does_not_snap_to_other_resize_targets() {
// Within snap tolerance of the other selected shape's original right edge.
drag_gesture(&mut s, (200.0, 140.0), (203.0, 140.0));
assert_eq!(box_of(&mut s, a)["w"], 103.0, "first shape must not snap back");
assert_eq!(box_of(&mut s, b)["w"], 83.0, "selection order must not affect snapping");
assert_eq!(box_of(&mut s, b)["w"], 82.4, "selection order must not affect snapping");
}
}
/// Resizing selected shapes snaps the active shape against unselected stationary shapes and scales others proportionally.
#[test]
fn resizing_selected_shapes_still_snaps_to_stationary_shapes() {
let (mut s, [a, b]) = resize_selection_scene();
@@ -5607,7 +5613,7 @@ fn resizing_selected_shapes_still_snaps_to_stationary_shapes() {
s.prefs.smart_guides = true;
drag_gesture(&mut s, (200.0, 140.0), (203.0, 140.0));
assert_eq!(box_of(&mut s, a)["w"], 107.0);
assert_eq!(box_of(&mut s, b)["w"], 87.0);
assert!((box_of(&mut s, b)["w"].as_f64().unwrap() - 85.6).abs() < 1e-9);
assert_eq!(box_of(&mut s, fixed), fixed_before);
}
+2
View File
@@ -149,6 +149,8 @@ enum Drag {
enter_text: Option<(ShapeId, Point)>,
},
Resize {
id: ShapeId,
orig: Xfrm,
ids: Vec<ShapeId>,
handle: u8,
origs: Vec<(ShapeId, Xfrm)>,
+28 -5
View File
@@ -26,11 +26,34 @@ impl Session {
Drag::Move { ids, start, origs, moved, duplicate, enter_text } => {
return self.drag_move(MoveDrag { ids, start, origs, moved, duplicate, enter_text }, p, mods, tol);
}
Drag::Resize { ids, handle, origs, start } => {
for (id, o) in &origs {
let nx = resize_box(o, handle, p - start, mods.shift || self.is_picture(*id), mods.alt);
let nx = self.snap_resize(nx, handle, &ids, tol);
self.set_xfrm(*id, nx)?;
Drag::Resize { id, orig, ids, handle, origs, start } => {
let nx = resize_box(&orig, handle, p - start, mods.shift || self.is_picture(id), mods.alt);
let nx = self.snap_resize(nx, handle, &ids, tol);
let sx = if orig.w > 1e-9 { (nx.w / orig.w) * if nx.flip_h != orig.flip_h { -1.0 } else { 1.0 } - 1.0 } else { 0.0 };
let sy = if orig.h > 1e-9 { (nx.h / orig.h) * if nx.flip_v != orig.flip_v { -1.0 } else { 1.0 } - 1.0 } else { 0.0 };
let div = if mods.alt { 2.0 } else { 1.0 };
let hx = match handle {
0 | 6 | 7 => -1.0,
2..=4 => 1.0,
_ => 0.0,
};
let hy = match handle {
0..=2 => -1.0,
4..=6 => 1.0,
_ => 0.0,
};
for (tid, o) in &origs {
let target_nx = if *tid == id {
nx
} else {
let lp = Affine::rotate(o.rot.to_radians())
* Point::new(
hx * sx * o.w / div * if o.flip_h { -1.0 } else { 1.0 },
hy * sy * o.h / div * if o.flip_v { -1.0 } else { 1.0 },
);
resize_box(o, handle, Vec2::new(lp.x, lp.y), mods.shift || self.is_picture(*tid), mods.alt)
};
self.set_xfrm(*tid, target_nx)?;
}
}
Drag::LineEnd { id, end, orig } => {
+2 -1
View File
@@ -302,12 +302,13 @@ impl Session {
Some(Hit::TableColumn { id, col }) => self.begin_table_border(id, true, col, p)?,
Some(Hit::TableRow { id, row }) => self.begin_table_border(id, false, row, p)?,
Some(Hit::Resize { id, handle }) => {
let orig = st.shape(id).map(|s| xfrm_of(&st.doc, &st.selection, s)).unwrap_or_default();
let ids: Vec<ShapeId> = if st.selection.shapes.contains(&id) { st.selection.shapes.clone() } else { vec![id] };
let origs: Vec<(ShapeId, Xfrm)> =
ids.iter().filter_map(|i| st.shape(*i).filter(|s| !s.locked).map(|s| (*i, xfrm_of(&st.doc, &st.selection, s)))).collect();
let ids: Vec<ShapeId> = origs.iter().map(|(id, _)| *id).collect();
self.begin("Size");
self.tool.drag = Some(Drag::Resize { ids, handle, origs, start: p });
self.tool.drag = Some(Drag::Resize { id, orig, ids, handle, origs, start: p });
}
Some(Hit::LineEnd { id, end }) => {
let orig = st.shape(id).map(|s| xfrm_of(&st.doc, &st.selection, s)).unwrap_or_default();