Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make the transform cage resize about the pivot when Alt is pressed #2226

Merged
merged 3 commits into from
Jan 31, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions editor/src/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@ pub const MIN_LENGTH_FOR_MIDPOINT_VISIBILITY: f64 = 20.;
pub const MIN_LENGTH_FOR_CORNERS_VISIBILITY: f64 = 12.;
/// When the width or height of the transform cage is less than this value, only the exterior of the bounding box will act as a click target for resizing.
pub const MIN_LENGTH_FOR_RESIZE_TO_INCLUDE_INTERIOR: f64 = 40.;
/// When dragging the edge of a cage with Alt, it centers around the pivot.
/// However if the pivot is on or near the same edge you are dragging, we should avoid scaling by a massive factor caused by the small denominator.
///
/// The motion of the user's cursor by an `x` pixel offset results in `x * scale_factor` pixels of offset on the other side.
pub const MAXIMUM_ALT_SCALE_FACTOR: f64 = 25.;

// PATH TOOL
pub const MANIPULATOR_GROUP_MARKER_SIZE: f64 = 6.;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::consts::{
BOUNDS_ROTATE_THRESHOLD, BOUNDS_SELECT_THRESHOLD, MIN_LENGTH_FOR_CORNERS_VISIBILITY, MIN_LENGTH_FOR_MIDPOINT_VISIBILITY, MIN_LENGTH_FOR_RESIZE_TO_INCLUDE_INTERIOR, SELECTION_DRAG_ANGLE,
BOUNDS_ROTATE_THRESHOLD, BOUNDS_SELECT_THRESHOLD, MAXIMUM_ALT_SCALE_FACTOR, MIN_LENGTH_FOR_CORNERS_VISIBILITY, MIN_LENGTH_FOR_MIDPOINT_VISIBILITY, MIN_LENGTH_FOR_RESIZE_TO_INCLUDE_INTERIOR,
SELECTION_DRAG_ANGLE,
};
use crate::messages::frontend::utility_types::MouseCursorIcon;
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
Expand All @@ -8,9 +9,9 @@ use crate::messages::prelude::*;
use crate::messages::tool::common_functionality::snapping::SnapTypeConfiguration;

use graphene_core::renderer::Quad;
use graphene_std::renderer::Rect;

use glam::{DAffine2, DVec2};
use graphene_std::renderer::Rect;

use super::snapping::{self, SnapCandidatePoint, SnapConstraint, SnapData, SnapManager, SnappedPoint};

Expand Down Expand Up @@ -88,6 +89,7 @@ impl SelectedEdges {

let mut min = self.bounds[0];
let mut max = self.bounds[1];

if self.top {
min.y = mouse.y;
} else if self.bottom {
Expand All @@ -100,24 +102,43 @@ impl SelectedEdges {
}

let mut pivot = self.pivot_from_bounds(min, max);

// Alt: Scaling around the pivot
if let Some(center_around) = center_around {
let center_around = transform.inverse().transform_point2(center_around);
if self.top {
pivot.y = center_around.y;
max.y = center_around.y * 2. - min.y;
} else if self.bottom {
pivot.y = center_around.y;
min.y = center_around.y * 2. - max.y;
}
if self.left {
pivot.x = center_around.x;
max.x = center_around.x * 2. - min.x;
} else if self.right {
pivot.x = center_around.x;
min.x = center_around.x * 2. - max.x;

let calculate_distance = |moving_opposite_to_drag: &mut f64, center: f64, dragging: f64, original_dragging: f64, current_side: bool| {
if !current_side {
return true;
}

// The motion of the user's cursor by an `x` pixel offset results in `x * scale_factor` pixels of offset on the other side
let scale_factor = (center - *moving_opposite_to_drag) / (center - original_dragging);
let new_distance = center - scale_factor * (center - dragging);

// Ignore the Alt key press and scale the dragged edge normally
if !new_distance.is_finite() || scale_factor.abs() > MAXIMUM_ALT_SCALE_FACTOR {
// Don't go on to check the other sides since this side is already invalid, so Alt-dragging is disabled and updating the pivot would be incorrect
return false;
}

*moving_opposite_to_drag = new_distance;

true
};

// Update the value of the first argument through mutation, and if we make it through all of them without
// encountering a case where the pivot is too near the edge, we also update the pivot so scaling occurs around it
if calculate_distance(&mut max.y, center_around.y, min.y, self.bounds[0].y, self.top)
&& calculate_distance(&mut min.y, center_around.y, max.y, self.bounds[1].y, self.bottom)
&& calculate_distance(&mut max.x, center_around.x, min.x, self.bounds[0].x, self.left)
&& calculate_distance(&mut min.x, center_around.x, max.x, self.bounds[1].x, self.right)
{
pivot = center_around;
}
}

// Shift: Aspect ratio constraint
if constrain {
let size = max - min;
let min_pivot = (pivot - min) / size;
Expand Down