Split out viewport handling into its own message handler (#3331)

* extract viewport handeling

* fix web overlays

* some cleanup

* remove some physical conversions

* fix resize snapping

* fixup

* apply some review feedback

* make viewport api more ergonomic

* fix

* fix web overlay canvas clear size

* clear workaround for canvas

* rename trigger message

---------

Co-authored-by: Dennis Kobert <dennis@kobert.dev>
This commit is contained in:
Timon
2025-11-08 08:59:38 +00:00
committed by GitHub
co-authored by Dennis Kobert
parent 3490111b96
commit 881ec0b193
60 changed files with 1326 additions and 607 deletions
@@ -34,9 +34,9 @@ impl AutoPanning {
}
}
pub fn setup_by_mouse_position(&mut self, input: &InputPreprocessorMessageHandler, messages: &[Message], responses: &mut VecDeque<Message>) {
pub fn setup_by_mouse_position(&mut self, input: &InputPreprocessorMessageHandler, viewport: &ViewportMessageHandler, messages: &[Message], responses: &mut VecDeque<Message>) {
let mouse_position = input.mouse.position;
let viewport_size = input.viewport_bounds.size();
let viewport_size = viewport.size().into_dvec2();
let is_pointer_outside_edge = mouse_position.x < 0. || mouse_position.x > viewport_size.x || mouse_position.y < 0. || mouse_position.y > viewport_size.y;
match is_pointer_outside_edge {
@@ -50,12 +50,12 @@ impl AutoPanning {
/// If the mouse was beyond any edge, it returns the amount shifted. Otherwise it returns None.
/// The shift is proportional to the distance between edge and mouse, and to the duration of the frame.
/// It is also guaranteed to be integral.
pub fn shift_viewport(&self, input: &InputPreprocessorMessageHandler, responses: &mut VecDeque<Message>) -> Option<DVec2> {
pub fn shift_viewport(&self, input: &InputPreprocessorMessageHandler, viewport: &ViewportMessageHandler, responses: &mut VecDeque<Message>) -> Option<DVec2> {
if !self.subscribed_to_animation_frame {
return None;
}
let viewport_size = input.viewport_bounds.size();
let viewport_size = viewport.size().into_dvec2();
let mouse_position = input.mouse.position.clamp(
DVec2::ZERO - DVec2::splat(DRAG_BEYOND_VIEWPORT_MAX_OVEREXTENSION_PIXELS),
viewport_size + DVec2::splat(DRAG_BEYOND_VIEWPORT_MAX_OVEREXTENSION_PIXELS),
@@ -142,7 +142,7 @@ impl PointRadiusHandle {
}
}
pub fn overlays(&self, selected_star_layer: Option<LayerNodeIdentifier>, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, overlay_context: &mut OverlayContext) {
pub fn overlays(&self, selected_star_layer: Option<LayerNodeIdentifier>, document: &DocumentMessageHandler, overlay_context: &mut OverlayContext) {
match &self.handle_state {
PointRadiusHandleState::Inactive => {
let Some(layer) = selected_star_layer else { return };
@@ -187,7 +187,7 @@ impl PointRadiusHandle {
let viewport = document.metadata().transform_to_viewport(layer);
let center = viewport.transform_point2(DVec2::ZERO);
let viewport_diagonal = input.viewport_bounds.size().length();
let viewport_diagonal = overlay_context.viewport.size().into_dvec2().length();
// Star
if let Some((sides, radius1, radius2)) = extract_star_parameters(Some(layer), document) {
@@ -15,10 +15,10 @@ pub struct Resize {
impl Resize {
/// Starts a resize, assigning the snap targets and snapping the starting position.
pub fn start(&mut self, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler) {
pub fn start(&mut self, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, viewport: &ViewportMessageHandler) {
let root_transform = document.metadata().document_to_viewport;
let point = SnapCandidatePoint::handle(root_transform.inverse().transform_point2(input.mouse.position));
let snapped = self.snap_manager.free_snap(&SnapData::new(document, input), &point, SnapTypeConfiguration::default());
let snapped = self.snap_manager.free_snap(&SnapData::new(document, input, viewport), &point, SnapTypeConfiguration::default());
self.drag_start = snapped.snapped_point_document;
}
@@ -30,7 +30,14 @@ impl Resize {
/// Compute the drag start and end based on the current mouse position. If the layer doesn't exist, returns [`None`].
/// If you want to draw even without a layer, use [`Resize::calculate_points_ignore_layer`].
pub fn calculate_points(&mut self, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, center: Key, lock_ratio: Key) -> Option<[DVec2; 2]> {
pub fn calculate_points(
&mut self,
document: &DocumentMessageHandler,
input: &InputPreprocessorMessageHandler,
viewport: &ViewportMessageHandler,
center: Key,
lock_ratio: Key,
) -> Option<[DVec2; 2]> {
let layer = self.layer?;
if layer == LayerNodeIdentifier::ROOT_PARENT {
@@ -42,21 +49,37 @@ impl Resize {
self.layer.take();
return None;
}
Some(self.calculate_points_ignore_layer(document, input, center, lock_ratio, false))
Some(self.calculate_points_ignore_layer(document, input, viewport, center, lock_ratio, false))
}
/// Compute the drag start and end based on the current mouse position. Ignores the state of the layer.
/// If you want to only draw whilst a layer exists, use [`Resize::calculate_points`].
pub fn calculate_points_ignore_layer(&mut self, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, center: Key, lock_ratio: Key, in_document: bool) -> [DVec2; 2] {
pub fn calculate_points_ignore_layer(
&mut self,
document: &DocumentMessageHandler,
input: &InputPreprocessorMessageHandler,
viewport: &ViewportMessageHandler,
center: Key,
lock_ratio: Key,
in_document: bool,
) -> [DVec2; 2] {
let ratio = input.keyboard.get(lock_ratio as usize);
let center = input.keyboard.get(center as usize);
// Use shared snapping logic with optional center and ratio constraints, considering if coordinates are in document space.
self.compute_snapped_resize_points(document, input, center, ratio, in_document)
self.compute_snapped_resize_points(document, input, viewport, center, ratio, in_document)
}
pub fn calculate_transform(&mut self, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, center: Key, lock_ratio: Key, skip_rerender: bool) -> Option<Message> {
let points_viewport = self.calculate_points(document, input, center, lock_ratio)?;
pub fn calculate_transform(
&mut self,
document: &DocumentMessageHandler,
input: &InputPreprocessorMessageHandler,
viewport: &ViewportMessageHandler,
center: Key,
lock_ratio: Key,
skip_rerender: bool,
) -> Option<Message> {
let points_viewport = self.calculate_points(document, input, viewport, center, lock_ratio)?;
Some(
GraphOperationMessage::TransformSet {
layer: self.layer?,
@@ -68,23 +91,33 @@ impl Resize {
)
}
pub fn calculate_circle_points(&mut self, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, center: Key) -> [DVec2; 2] {
pub fn calculate_circle_points(&mut self, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, viewport: &ViewportMessageHandler, center: Key) -> [DVec2; 2] {
let center = input.keyboard.get(center as usize);
// Use shared snapping logic with enforced aspect ratio and optional center snapping.
self.compute_snapped_resize_points(document, input, center, true, false)
self.compute_snapped_resize_points(document, input, viewport, center, true, false)
}
/// Calculates two points in viewport space from a drag, applying snapping, optional center mode, and aspect ratio locking.
fn compute_snapped_resize_points(&mut self, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, center: bool, lock_ratio: bool, in_document: bool) -> [DVec2; 2] {
fn compute_snapped_resize_points(
&mut self,
document: &DocumentMessageHandler,
input: &InputPreprocessorMessageHandler,
viewport: &ViewportMessageHandler,
center: bool,
lock_ratio: bool,
in_document: bool,
) -> [DVec2; 2] {
let start = self.viewport_drag_start(document);
let mouse = input.mouse.position;
let document_to_viewport = document.navigation_handler.calculate_offset_transform(input.viewport_bounds.center(), &document.document_ptz);
let document_to_viewport = document
.navigation_handler
.calculate_offset_transform(viewport.center_in_viewport_space().into(), &document.document_ptz);
let drag_start = self.drag_start;
let mut points_viewport = [start, mouse];
let ignore = if let Some(layer) = self.layer { vec![layer] } else { vec![] };
let snap_data = &SnapData::ignore(document, input, &ignore);
let snap_data = &SnapData::ignore(document, input, viewport, &ignore);
if lock_ratio {
let viewport_size = points_viewport[1] - points_viewport[0];
@@ -503,8 +503,16 @@ impl ShapeState {
}
// Snap, returning a viewport delta
pub fn snap(&self, snap_manager: &mut SnapManager, snap_cache: &SnapCache, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, previous_mouse: DVec2) -> DVec2 {
let snap_data = SnapData::new_snap_cache(document, input, snap_cache);
pub fn snap(
&self,
snap_manager: &mut SnapManager,
snap_cache: &SnapCache,
document: &DocumentMessageHandler,
input: &InputPreprocessorMessageHandler,
viewport: &ViewportMessageHandler,
previous_mouse: DVec2,
) -> DVec2 {
let snap_data = SnapData::new_snap_cache(document, input, viewport, snap_cache);
let mouse_delta = document
.network_interface
@@ -146,13 +146,14 @@ impl Arc {
pub fn update_shape(
document: &DocumentMessageHandler,
ipp: &InputPreprocessorMessageHandler,
viewport: &ViewportMessageHandler,
layer: LayerNodeIdentifier,
shape_tool_data: &mut ShapeToolData,
modifier: ShapeToolModifierKey,
responses: &mut VecDeque<Message>,
) {
let (center, lock_ratio) = (modifier[0], modifier[1]);
if let Some([start, end]) = shape_tool_data.data.calculate_points(document, ipp, center, lock_ratio) {
if let Some([start, end]) = shape_tool_data.data.calculate_points(document, ipp, viewport, center, lock_ratio) {
let Some(node_id) = graph_modification_utils::get_arc_id(layer, &document.network_interface) else {
return;
};
@@ -89,13 +89,14 @@ impl Circle {
pub fn update_shape(
document: &DocumentMessageHandler,
ipp: &InputPreprocessorMessageHandler,
viewport: &ViewportMessageHandler,
layer: LayerNodeIdentifier,
shape_tool_data: &mut ShapeToolData,
modifier: ShapeToolModifierKey,
responses: &mut VecDeque<Message>,
) {
let center = modifier[0];
let [start, end] = shape_tool_data.data.calculate_circle_points(document, ipp, center);
let [start, end] = shape_tool_data.data.calculate_circle_points(document, ipp, viewport, center);
let Some(node_id) = graph_modification_utils::get_circle_id(layer, &document.network_interface) else {
return;
};
@@ -23,6 +23,7 @@ impl Ellipse {
pub fn update_shape(
document: &DocumentMessageHandler,
ipp: &InputPreprocessorMessageHandler,
viewport: &ViewportMessageHandler,
layer: LayerNodeIdentifier,
shape_tool_data: &mut ShapeToolData,
modifier: ShapeToolModifierKey,
@@ -30,7 +31,7 @@ impl Ellipse {
) {
let [center, lock_ratio, _] = modifier;
if let Some([start, end]) = shape_tool_data.data.calculate_points(document, ipp, center, lock_ratio) {
if let Some([start, end]) = shape_tool_data.data.calculate_points(document, ipp, viewport, center, lock_ratio) {
let Some(node_id) = graph_modification_utils::get_ellipse_id(layer, &document.network_interface) else {
return;
};
@@ -48,6 +48,7 @@ impl Line {
pub fn update_shape(
document: &DocumentMessageHandler,
ipp: &InputPreprocessorMessageHandler,
viewport: &ViewportMessageHandler,
layer: LayerNodeIdentifier,
shape_tool_data: &mut ShapeToolData,
modifier: ShapeToolModifierKey,
@@ -59,7 +60,7 @@ impl Line {
let keyboard = &ipp.keyboard;
let ignore = [layer];
let snap_data = SnapData::ignore(document, ipp, &ignore);
let snap_data = SnapData::ignore(document, ipp, viewport, &ignore);
let mut document_points = generate_line(shape_tool_data, snap_data, keyboard.key(lock_angle), keyboard.key(snap_angle), keyboard.key(center));
if shape_tool_data.line_data.dragging_endpoint == Some(LineEnd::Start) {
@@ -58,13 +58,13 @@ impl ShapeGizmoHandler for PolygonGizmoHandler {
&self,
document: &DocumentMessageHandler,
selected_polygon_layer: Option<LayerNodeIdentifier>,
input: &InputPreprocessorMessageHandler,
_input: &InputPreprocessorMessageHandler,
shape_editor: &mut &mut ShapeState,
mouse_position: DVec2,
overlay_context: &mut OverlayContext,
) {
self.number_of_points_dial.overlays(document, selected_polygon_layer, shape_editor, mouse_position, overlay_context);
self.point_radius_handle.overlays(selected_polygon_layer, document, input, overlay_context);
self.point_radius_handle.overlays(selected_polygon_layer, document, overlay_context);
polygon_outline(selected_polygon_layer, document, overlay_context);
}
@@ -72,7 +72,7 @@ impl ShapeGizmoHandler for PolygonGizmoHandler {
fn dragging_overlays(
&self,
document: &DocumentMessageHandler,
input: &InputPreprocessorMessageHandler,
_input: &InputPreprocessorMessageHandler,
shape_editor: &mut &mut ShapeState,
mouse_position: DVec2,
overlay_context: &mut OverlayContext,
@@ -82,7 +82,7 @@ impl ShapeGizmoHandler for PolygonGizmoHandler {
}
if self.point_radius_handle.is_dragging_or_snapped() {
self.point_radius_handle.overlays(None, document, input, overlay_context);
self.point_radius_handle.overlays(None, document, overlay_context);
}
}
@@ -116,6 +116,7 @@ impl Polygon {
pub fn update_shape(
document: &DocumentMessageHandler,
ipp: &InputPreprocessorMessageHandler,
viewport: &ViewportMessageHandler,
layer: LayerNodeIdentifier,
shape_tool_data: &mut ShapeToolData,
modifier: ShapeToolModifierKey,
@@ -123,7 +124,7 @@ impl Polygon {
) {
let [center, lock_ratio, _] = modifier;
if let Some([start, end]) = shape_tool_data.data.calculate_points(document, ipp, center, lock_ratio) {
if let Some([start, end]) = shape_tool_data.data.calculate_points(document, ipp, viewport, center, lock_ratio) {
// TODO: We need to determine how to allow the polygon node to make irregular shapes
update_radius_sign(end, start, layer, document, responses);
@@ -23,6 +23,7 @@ impl Rectangle {
pub fn update_shape(
document: &DocumentMessageHandler,
ipp: &InputPreprocessorMessageHandler,
viewport: &ViewportMessageHandler,
layer: LayerNodeIdentifier,
shape_tool_data: &mut ShapeToolData,
modifier: ShapeToolModifierKey,
@@ -30,7 +31,7 @@ impl Rectangle {
) {
let [center, lock_ratio, _] = modifier;
if let Some([start, end]) = shape_tool_data.data.calculate_points(document, ipp, center, lock_ratio) {
if let Some([start, end]) = shape_tool_data.data.calculate_points(document, ipp, viewport, center, lock_ratio) {
let Some(node_id) = graph_modification_utils::get_rectangle_id(layer, &document.network_interface) else {
return;
};
@@ -36,13 +36,20 @@ impl Spiral {
])
}
pub fn update_shape(document: &DocumentMessageHandler, ipp: &InputPreprocessorMessageHandler, layer: LayerNodeIdentifier, shape_tool_data: &mut ShapeToolData, responses: &mut VecDeque<Message>) {
pub fn update_shape(
document: &DocumentMessageHandler,
ipp: &InputPreprocessorMessageHandler,
viewport: &ViewportMessageHandler,
layer: LayerNodeIdentifier,
shape_tool_data: &mut ShapeToolData,
responses: &mut VecDeque<Message>,
) {
use graphene_std::vector::generator_nodes::spiral::*;
let viewport_drag_start = shape_tool_data.data.viewport_drag_start(document);
let ignore = vec![layer];
let snap_data = SnapData::ignore(document, ipp, &ignore);
let snap_data = SnapData::ignore(document, ipp, viewport, &ignore);
let config = SnapTypeConfiguration::default();
let document_mouse = document.metadata().document_to_viewport.inverse().transform_point2(ipp.mouse.position);
let snapped = shape_tool_data.data.snap_manager.free_snap(&snap_data, &SnapCandidatePoint::handle(document_mouse), config);
@@ -58,13 +58,13 @@ impl ShapeGizmoHandler for StarGizmoHandler {
&self,
document: &DocumentMessageHandler,
selected_star_layer: Option<LayerNodeIdentifier>,
input: &InputPreprocessorMessageHandler,
_input: &InputPreprocessorMessageHandler,
shape_editor: &mut &mut ShapeState,
mouse_position: DVec2,
overlay_context: &mut OverlayContext,
) {
self.number_of_points_dial.overlays(document, selected_star_layer, shape_editor, mouse_position, overlay_context);
self.point_radius_handle.overlays(selected_star_layer, document, input, overlay_context);
self.point_radius_handle.overlays(selected_star_layer, document, overlay_context);
star_outline(selected_star_layer, document, overlay_context);
}
@@ -72,7 +72,7 @@ impl ShapeGizmoHandler for StarGizmoHandler {
fn dragging_overlays(
&self,
document: &DocumentMessageHandler,
input: &InputPreprocessorMessageHandler,
_input: &InputPreprocessorMessageHandler,
shape_editor: &mut &mut ShapeState,
mouse_position: DVec2,
overlay_context: &mut OverlayContext,
@@ -82,7 +82,7 @@ impl ShapeGizmoHandler for StarGizmoHandler {
}
if self.point_radius_handle.is_dragging_or_snapped() {
self.point_radius_handle.overlays(None, document, input, overlay_context);
self.point_radius_handle.overlays(None, document, overlay_context);
}
}
@@ -121,6 +121,7 @@ impl Star {
pub fn update_shape(
document: &DocumentMessageHandler,
ipp: &InputPreprocessorMessageHandler,
viewport: &ViewportMessageHandler,
layer: LayerNodeIdentifier,
shape_tool_data: &mut ShapeToolData,
modifier: ShapeToolModifierKey,
@@ -128,7 +129,7 @@ impl Star {
) {
let [center, lock_ratio, _] = modifier;
if let Some([start, end]) = shape_tool_data.data.calculate_points(document, ipp, center, lock_ratio) {
if let Some([start, end]) = shape_tool_data.data.calculate_points(document, ipp, viewport, center, lock_ratio) {
// TODO: We need to determine how to allow the polygon node to make irregular shapes
update_radius_sign(end, start, layer, document, responses);
@@ -206,29 +206,31 @@ pub struct SnapCache {
pub struct SnapData<'a> {
pub document: &'a DocumentMessageHandler,
pub input: &'a InputPreprocessorMessageHandler,
pub viewport: &'a ViewportMessageHandler,
pub ignore: &'a [LayerNodeIdentifier],
pub node_snap_cache: Option<&'a SnapCache>,
pub candidates: Option<&'a Vec<LayerNodeIdentifier>>,
pub alignment_candidates: Option<&'a Vec<LayerNodeIdentifier>>,
}
impl<'a> SnapData<'a> {
pub fn new(document: &'a DocumentMessageHandler, input: &'a InputPreprocessorMessageHandler) -> Self {
Self::ignore(document, input, &[])
pub fn new(document: &'a DocumentMessageHandler, input: &'a InputPreprocessorMessageHandler, viewport: &'a ViewportMessageHandler) -> Self {
Self::ignore(document, input, viewport, &[])
}
pub fn ignore(document: &'a DocumentMessageHandler, input: &'a InputPreprocessorMessageHandler, ignore: &'a [LayerNodeIdentifier]) -> Self {
pub fn ignore(document: &'a DocumentMessageHandler, input: &'a InputPreprocessorMessageHandler, viewport: &'a ViewportMessageHandler, ignore: &'a [LayerNodeIdentifier]) -> Self {
Self {
document,
input,
viewport,
ignore,
candidates: None,
alignment_candidates: None,
node_snap_cache: None,
}
}
pub fn new_snap_cache(document: &'a DocumentMessageHandler, input: &'a InputPreprocessorMessageHandler, snap_cache: &'a SnapCache) -> Self {
pub fn new_snap_cache(document: &'a DocumentMessageHandler, input: &'a InputPreprocessorMessageHandler, viewport: &'a ViewportMessageHandler, snap_cache: &'a SnapCache) -> Self {
Self {
node_snap_cache: Some(snap_cache),
..Self::new(document, input)
..Self::new(document, input, viewport)
}
}
fn get_candidates(&self) -> &[LayerNodeIdentifier] {
@@ -301,7 +303,7 @@ impl SnapManager {
for point in snapped_points {
let viewport_point = document.metadata().document_to_viewport.transform_point2(point.snapped_point_document);
let on_screen = viewport_point.cmpgt(DVec2::ZERO).all() && viewport_point.cmplt(snap_data.input.viewport_bounds.size()).all();
let on_screen = viewport_point.cmpgt(DVec2::ZERO).all() && viewport_point.cmplt(snap_data.viewport.size().into()).all();
if !on_screen && !off_screen {
continue;
}
@@ -337,7 +339,7 @@ impl SnapManager {
return;
};
let layer_bounds = document.metadata().transform_to_document(layer) * Quad::from_box(bounds);
let screen_bounds = document.metadata().document_to_viewport.inverse() * Quad::from_box([DVec2::ZERO, snap_data.input.viewport_bounds.size()]);
let screen_bounds = document.metadata().document_to_viewport.inverse() * Quad::from_box([DVec2::ZERO, snap_data.viewport.size().into()]);
if screen_bounds.intersects(layer_bounds) {
if self.alignment_candidates.as_ref().is_none_or(|candidates| candidates.len() <= 100) {
self.alignment_candidates.get_or_insert_with(Vec::new).push(layer);
@@ -76,7 +76,7 @@ impl DistributionSnapper {
self.down.clear();
self.up.clear();
let screen_bounds = (document.metadata().document_to_viewport.inverse() * Quad::from_box([DVec2::ZERO, snap_data.input.viewport_bounds.size()])).bounding_box();
let screen_bounds = (document.metadata().document_to_viewport.inverse() * Quad::from_box([DVec2::ZERO, snap_data.viewport.size().into()])).bounding_box();
let max_extent = (screen_bounds[1] - screen_bounds[0]).abs().max_element();
// Collect artboard bounds
@@ -1,8 +1,8 @@
use super::snapping::{self, SnapCandidatePoint, SnapConstraint, SnapData, SnapManager, SnappedPoint};
use crate::consts::{
BOUNDS_ROTATE_THRESHOLD, BOUNDS_SELECT_THRESHOLD, COLOR_OVERLAY_WHITE, MAX_LENGTH_FOR_NO_WIDTH_OR_HEIGHT, MAXIMUM_ALT_SCALE_FACTOR, MIN_LENGTH_FOR_CORNERS_VISIBILITY,
MIN_LENGTH_FOR_EDGE_RESIZE_PRIORITY_OVER_CORNERS, MIN_LENGTH_FOR_MIDPOINT_VISIBILITY, MIN_LENGTH_FOR_RESIZE_TO_INCLUDE_INTERIOR, MIN_LENGTH_FOR_SKEW_TRIANGLE_VISIBILITY, RESIZE_HANDLE_SIZE,
SELECTION_DRAG_ANGLE, SKEW_TRIANGLE_OFFSET, SKEW_TRIANGLE_SIZE,
BOUNDS_ROTATE_THRESHOLD, BOUNDS_SELECT_THRESHOLD, MAX_LENGTH_FOR_NO_WIDTH_OR_HEIGHT, MAXIMUM_ALT_SCALE_FACTOR, MIN_LENGTH_FOR_CORNERS_VISIBILITY, MIN_LENGTH_FOR_EDGE_RESIZE_PRIORITY_OVER_CORNERS,
MIN_LENGTH_FOR_MIDPOINT_VISIBILITY, MIN_LENGTH_FOR_RESIZE_TO_INCLUDE_INTERIOR, MIN_LENGTH_FOR_SKEW_TRIANGLE_VISIBILITY, RESIZE_HANDLE_SIZE, SELECTION_DRAG_ANGLE, SKEW_TRIANGLE_OFFSET,
SKEW_TRIANGLE_SIZE,
};
use crate::messages::frontend::utility_types::MouseCursorIcon;
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
@@ -489,13 +489,7 @@ impl BoundingBoxManager {
if (end - start).length() < MIN_LENGTH_FOR_SKEW_TRIANGLE_VISIBILITY {
return;
}
let edge_dir = (end - start).normalize();
let mid = end.midpoint(start);
for edge in [edge_dir, -edge_dir] {
overlay_context.draw_triangle(mid + edge * (3. + SKEW_TRIANGLE_OFFSET), edge, SKEW_TRIANGLE_SIZE, None, None);
}
overlay_context.skew_handles(start, end);
};
if let Some([start, end]) = self.edge_endpoints_vector_from_edge_bool(hover_edge) {
@@ -565,11 +559,6 @@ impl BoundingBoxManager {
self.render_quad(overlay_context);
}
let mut draw_handle = |point: DVec2, angle: f64| {
let quad = DAffine2::from_angle_translation(angle, point) * Quad::from_box([DVec2::splat(-RESIZE_HANDLE_SIZE / 2.), DVec2::splat(RESIZE_HANDLE_SIZE / 2.)]);
overlay_context.quad(quad, None, Some(COLOR_OVERLAY_WHITE));
};
let horizontal_angle = (quad.top_left() - quad.bottom_left()).to_angle();
let vertical_angle = (quad.top_left() - quad.top_right()).to_angle();
@@ -579,7 +568,7 @@ impl BoundingBoxManager {
TransformCageSizeCategory::Full | TransformCageSizeCategory::Narrow | TransformCageSizeCategory::ReducedLandscape
) {
for point in horizontal_edges {
draw_handle(point, horizontal_angle);
overlay_context.resize_handle(point, horizontal_angle);
}
}
@@ -589,7 +578,7 @@ impl BoundingBoxManager {
TransformCageSizeCategory::Full | TransformCageSizeCategory::Narrow | TransformCageSizeCategory::ReducedPortrait
) {
for point in vertical_edges {
draw_handle(point, vertical_angle);
overlay_context.resize_handle(point, vertical_angle);
}
}
@@ -606,14 +595,14 @@ impl BoundingBoxManager {
TransformCageSizeCategory::Full | TransformCageSizeCategory::ReducedBoth | TransformCageSizeCategory::ReducedLandscape | TransformCageSizeCategory::ReducedPortrait
) {
for point in quad.0 {
draw_handle(point, angle);
overlay_context.resize_handle(point, angle);
}
}
// Draw the flat line endpoint drag handles
if category == TransformCageSizeCategory::Flat {
draw_handle(self.transform.transform_point2(self.bounds[0]), angle);
draw_handle(self.transform.transform_point2(self.bounds[1]), angle);
overlay_context.resize_handle(self.transform.transform_point2(self.bounds[0]), angle);
overlay_context.resize_handle(self.transform.transform_point2(self.bounds[1]), angle);
}
}
@@ -262,6 +262,7 @@ pub fn resize_bounds(
snap_manager: &mut SnapManager,
snap_candidates: &mut Vec<SnapCandidatePoint>,
input: &InputPreprocessorMessageHandler,
viewport: &ViewportMessageHandler,
center: bool,
constrain: bool,
tool: ToolType,
@@ -271,7 +272,7 @@ pub fn resize_bounds(
let snap = Some(SizeSnapData {
manager: snap_manager,
points: snap_candidates,
snap_data: SnapData::ignore(document, input, dragging_layers),
snap_data: SnapData::ignore(document, input, viewport, dragging_layers),
});
let (position, size) = movement.new_size(input.mouse.position, bounds.original_bound_transform, center, constrain, snap);
let (delta, mut pivot) = movement.bounds_to_scale_transform(position, size);