Skip to content

Commit c899c13

Browse files
committed
piviot snapping
1 parent 2be7790 commit c899c13

1 file changed

Lines changed: 79 additions & 2 deletions

File tree

editor/src/messages/tool/tool_messages/select_tool.rs

Lines changed: 79 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::messages::portfolio::document::graph_operation::utility_types::Transf
77
use crate::messages::portfolio::document::node_graph::document_node_definitions::DefinitionIdentifier;
88
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
99
use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier};
10-
use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate, AlignAxis, FlipAxis, GroupFolderType};
10+
use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate, AlignAxis, BoundingBoxSnapTarget, FlipAxis, GroupFolderType, PathSnapSource, SnapSource, SnapTarget};
1111
use crate::messages::portfolio::document::utility_types::network_interface::{FlowType, NodeNetworkInterface, NodeTemplate};
1212
use crate::messages::portfolio::document::utility_types::nodes::SelectedNodes;
1313
use crate::messages::preferences::SelectionMode;
@@ -592,6 +592,68 @@ pub fn create_bounding_box_transform(document: &DocumentMessageHandler) -> DAffi
592592
.unwrap_or_default()
593593
}
594594

595+
fn snap_pivot_to_bounds(document: &DocumentMessageHandler, mouse_position: DVec2, selection_bounds: &Option<BoundingBoxManager>) -> Option<snapping::SnappedPoint> {
596+
let tolerance = snapping::snap_tolerance(document);
597+
let mut best_distance = f64::INFINITY;
598+
let mut best_snap_point: Option<DVec2> = None;
599+
let mut best_quad: Option<Quad> = None;
600+
let mut best_point_type: u8 = 0; // 0=corner, 1=midpoint, 2=center
601+
602+
let mut check_snap = |snap_doc: DVec2, quad: Quad, point_type: u8| {
603+
let snap_viewport = document.metadata().document_to_viewport.transform_point2(snap_doc);
604+
let distance = mouse_position.distance(snap_viewport);
605+
if distance < tolerance && distance < best_distance {
606+
best_distance = distance;
607+
best_snap_point = Some(snap_doc);
608+
best_quad = Some(quad);
609+
best_point_type = point_type;
610+
}
611+
};
612+
613+
// Snap to selection's combined bounding box
614+
if let Some(bounds) = selection_bounds {
615+
let quad = document.metadata().document_to_viewport.inverse() * bounds.transform * Quad::from_box(bounds.bounds);
616+
for i in 0..4 {
617+
check_snap(quad.0[i], quad, 0);
618+
check_snap((quad.0[i] + quad.0[(i + 1) % 4]) / 2.0, quad, 1);
619+
}
620+
check_snap(quad.center(), quad, 2);
621+
}
622+
623+
let selected: Vec<_> = document.network_interface.selected_nodes().selected_visible_and_unlocked_layers(&document.network_interface).collect();
624+
for layer in document.metadata().all_layers() {
625+
if selected.contains(&layer) || !document.network_interface.is_visible(&layer.to_node(), &[]) {
626+
continue;
627+
}
628+
let Some(bounds) = document.metadata().bounding_box_with_transform(layer, document.metadata().transform_to_document(layer)) else {
629+
continue;
630+
};
631+
let quad = Quad::from_box(bounds);
632+
for i in 0..4 {
633+
check_snap(quad.0[i], quad, 0);
634+
check_snap((quad.0[i] + quad.0[(i + 1) % 4]) / 2.0, quad, 1);
635+
}
636+
check_snap(quad.center(), quad, 2);
637+
}
638+
639+
best_snap_point.zip(best_quad).map(|(snap_point, quad)| {
640+
let target = match best_point_type {
641+
0 => SnapTarget::BoundingBox(BoundingBoxSnapTarget::CornerPoint),
642+
1 => SnapTarget::BoundingBox(BoundingBoxSnapTarget::EdgeMidpoint),
643+
_ => SnapTarget::BoundingBox(BoundingBoxSnapTarget::CenterPoint),
644+
};
645+
snapping::SnappedPoint {
646+
snapped_point_document: snap_point,
647+
source: SnapSource::Path(PathSnapSource::HandlePoint),
648+
target,
649+
distance: best_distance,
650+
tolerance,
651+
target_bounds: Some(quad),
652+
..Default::default()
653+
}
654+
})
655+
}
656+
595657
impl Fsm for SelectToolFsmState {
596658
type ToolData = SelectToolData;
597659
type ToolOptions = ();
@@ -1149,6 +1211,7 @@ impl Fsm for SelectToolFsmState {
11491211
}
11501212
(SelectToolFsmState::DraggingPivot, SelectToolMessage::Abort) => {
11511213
responses.add(DocumentMessage::AbortTransaction);
1214+
tool_data.snap_manager.cleanup(responses);
11521215

11531216
let selection = tool_data.nested_selection_behavior;
11541217
SelectToolFsmState::Ready { selection }
@@ -1274,10 +1337,24 @@ impl Fsm for SelectToolFsmState {
12741337
}
12751338
(SelectToolFsmState::DraggingPivot, SelectToolMessage::PointerMove { modifier_keys }) => {
12761339
let mouse_position = input.mouse.position;
1277-
let snapped_mouse_position = mouse_position;
1340+
let document_mouse = document.metadata().document_to_viewport.inverse().transform_point2(mouse_position);
12781341

1342+
let snap_data = SnapData::new(document, input, viewport);
1343+
let point = SnapCandidatePoint::handle(document_mouse);
1344+
let mut snapped = tool_data.snap_manager.free_snap(&snap_data, &point, snapping::SnapTypeConfiguration::default());
1345+
1346+
if let Some(pivot_snap) = snap_pivot_to_bounds(document, mouse_position, &tool_data.bounding_box_manager)
1347+
&& pivot_snap.distance < snapped.distance
1348+
{
1349+
snapped = pivot_snap;
1350+
}
1351+
1352+
tool_data.snap_manager.update_indicator(snapped.clone());
1353+
1354+
let snapped_mouse_position = document.metadata().document_to_viewport.transform_point2(snapped.snapped_point_document);
12791355
tool_data.pivot_gizmo.pivot.set_viewport_position(snapped_mouse_position);
12801356

1357+
responses.add(OverlaysMessage::Draw);
12811358
responses.add(NodeGraphMessage::RunDocumentGraph);
12821359

12831360
// Auto-panning

0 commit comments

Comments
 (0)