mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-21 20:38:12 +08:00
Add basic artboard snapping (#1734)
* Initial vector modify node * Initial extraction of data from monitor nodes * Migrate to point id * Start converting to modify node * Non destructive spline tool (tout le reste est cassé) * Fix unconnected modify node * Fix freehand tool * Pen tool * Migrate demo art * Select points * Fix the demo artwork * Fix the X and Y inputs for path tool * G1 continous toggle * Delete points * Fix test * Insert point * Improve robustness of handles * Fix GRS shortcuts on path * Dragging points * Fix build * Preserve opposing handle lengths * Update demo art and snapping * Fix polygon tool * Double click end anchor * Improve dragging * Fix text shifting * Select only connected verts * Colinear alt * Cleanup * Fix imports * first commit * changes in SnapData::ignore() * Bug fixes and cleanup * Code review --------- Co-authored-by: 0hypercube <0hypercube@gmail.com> Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
co-authored by
0hypercube
Keavon Chambers
parent
176ce314c7
commit
e66620dc5c
@@ -1,15 +1,15 @@
|
||||
use super::*;
|
||||
use crate::consts::HIDE_HANDLE_DISTANCE;
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::portfolio::document::utility_types::misc::{
|
||||
BoardSnapSource, BoardSnapTarget, BoundingBoxSnapSource, BoundingBoxSnapTarget, GeometrySnapSource, GeometrySnapTarget, SnapSource, SnapTarget,
|
||||
};
|
||||
use crate::messages::portfolio::document::utility_types::misc::*;
|
||||
use crate::messages::prelude::*;
|
||||
|
||||
use bezier_rs::{Bezier, Identifier, Subpath, TValue};
|
||||
use glam::{DAffine2, DVec2};
|
||||
use graphene_core::renderer::Quad;
|
||||
use graphene_core::vector::PointId;
|
||||
|
||||
use glam::{DAffine2, DVec2};
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct LayerSnapper {
|
||||
points_to_snap: Vec<SnapCandidatePoint>,
|
||||
@@ -21,13 +21,21 @@ impl LayerSnapper {
|
||||
if !document.snapping_state.target_enabled(target) {
|
||||
return;
|
||||
}
|
||||
let Some(bounds) = document.metadata.bounding_box_with_transform(layer, DAffine2::IDENTITY) else {
|
||||
return;
|
||||
|
||||
let bounds = if document.metadata.is_artboard(layer) {
|
||||
document.metadata.bounding_box_with_transform(layer, document.metadata.transform_to_document(layer)).map(Quad::from_box)
|
||||
} else {
|
||||
document
|
||||
.metadata
|
||||
.bounding_box_with_transform(layer, DAffine2::IDENTITY)
|
||||
.map(|bounds| document.metadata.transform_to_document(layer) * Quad::from_box(bounds))
|
||||
};
|
||||
let bounds = document.metadata.transform_to_document(layer) * Quad::from_box(bounds);
|
||||
let Some(bounds) = bounds else { return };
|
||||
|
||||
if bounds.0.iter().any(|point| !point.is_finite()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for document_curve in bounds.bezier_lines() {
|
||||
self.paths_to_snap.push(SnapCandidatePath {
|
||||
document_curve,
|
||||
@@ -46,7 +54,7 @@ impl LayerSnapper {
|
||||
self.paths_to_snap.clear();
|
||||
|
||||
for layer in document.metadata.all_layers() {
|
||||
if !document.metadata.is_artboard(layer) {
|
||||
if !document.metadata.is_artboard(layer) || snap_data.ignore.contains(&layer) {
|
||||
continue;
|
||||
}
|
||||
self.add_layer_bounds(document, layer, SnapTarget::Board(BoardSnapTarget::Edge));
|
||||
@@ -168,22 +176,16 @@ impl LayerSnapper {
|
||||
self.points_to_snap.clear();
|
||||
|
||||
for layer in document.metadata.all_layers() {
|
||||
if !document.metadata.is_artboard(layer) {
|
||||
if !document.metadata.is_artboard(layer) || snap_data.ignore.contains(&layer) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if document.snapping_state.target_enabled(SnapTarget::Board(BoardSnapTarget::Corner)) {
|
||||
let Some(bounds) = document.metadata.bounding_box_with_transform(layer, DAffine2::IDENTITY) else {
|
||||
let Some(bounds) = document.metadata.bounding_box_with_transform(layer, document.metadata.transform_to_document(layer)) else {
|
||||
continue;
|
||||
};
|
||||
let quad = document.metadata.transform_to_document(layer) * Quad::from_box(bounds);
|
||||
let values = BBoxSnapValues {
|
||||
corner_source: SnapSource::Board(BoardSnapSource::Corner),
|
||||
corner_target: SnapTarget::Board(BoardSnapTarget::Corner),
|
||||
center_source: SnapSource::Board(BoardSnapSource::Center),
|
||||
center_target: SnapTarget::Board(BoardSnapTarget::Center),
|
||||
..Default::default()
|
||||
};
|
||||
get_bbox_points(quad, &mut self.points_to_snap, values, document);
|
||||
|
||||
get_bbox_points(Quad::from_box(bounds), &mut self.points_to_snap, BBoxSnapValues::ARTBOARD, document);
|
||||
}
|
||||
}
|
||||
for &layer in snap_data.get_candidates() {
|
||||
@@ -351,6 +353,15 @@ impl BBoxSnapValues {
|
||||
center_source: SnapSource::BoundingBox(BoundingBoxSnapSource::Center),
|
||||
center_target: SnapTarget::BoundingBox(BoundingBoxSnapTarget::Center),
|
||||
};
|
||||
|
||||
pub const ARTBOARD: Self = Self {
|
||||
corner_source: SnapSource::Board(BoardSnapSource::Corner),
|
||||
corner_target: SnapTarget::Board(BoardSnapTarget::Corner),
|
||||
edge_source: SnapSource::None,
|
||||
edge_target: SnapTarget::None,
|
||||
center_source: SnapSource::Board(BoardSnapSource::Center),
|
||||
center_target: SnapTarget::Board(BoardSnapTarget::Center),
|
||||
};
|
||||
}
|
||||
pub fn get_bbox_points(quad: Quad, points: &mut Vec<SnapCandidatePoint>, values: BBoxSnapValues, document: &DocumentMessageHandler) {
|
||||
for index in 0..4 {
|
||||
|
||||
@@ -216,6 +216,43 @@ pub fn axis_align_drag(axis_align: bool, position: DVec2, start: DVec2) -> DVec2
|
||||
}
|
||||
}
|
||||
|
||||
/// Snaps a dragging event from the artboard or select tool
|
||||
pub fn snap_drag(start: DVec2, current: DVec2, axis_align: bool, snap_data: SnapData, snap_manager: &mut SnapManager, candidates: &Vec<SnapCandidatePoint>) -> DVec2 {
|
||||
let mouse_position = axis_align_drag(axis_align, snap_data.input.mouse.position, start);
|
||||
let document = snap_data.document;
|
||||
let total_mouse_delta_document = document.metadata.document_to_viewport.inverse().transform_vector2(mouse_position - start);
|
||||
let mouse_delta_document = document.metadata.document_to_viewport.inverse().transform_vector2(mouse_position - current);
|
||||
let mut offset = mouse_delta_document;
|
||||
let mut best_snap = SnappedPoint::infinite_snap(document.metadata.document_to_viewport.inverse().transform_point2(mouse_position));
|
||||
|
||||
for point in candidates {
|
||||
let origin = point.document_point + total_mouse_delta_document;
|
||||
|
||||
let snapped = if axis_align {
|
||||
snap_manager.constrained_snap(
|
||||
&snap_data,
|
||||
point,
|
||||
SnapConstraint::Line {
|
||||
origin,
|
||||
direction: total_mouse_delta_document.try_normalize().unwrap_or(DVec2::X),
|
||||
},
|
||||
None,
|
||||
)
|
||||
} else {
|
||||
snap_manager.free_snap(&snap_data, point, None, false)
|
||||
};
|
||||
|
||||
if best_snap.other_snap_better(&snapped) {
|
||||
offset = snapped.snapped_point_document - origin + mouse_delta_document;
|
||||
best_snap = snapped;
|
||||
}
|
||||
}
|
||||
|
||||
snap_manager.update_indicator(best_snap);
|
||||
|
||||
document.metadata.document_to_viewport.transform_vector2(offset)
|
||||
}
|
||||
|
||||
/// Contains info on the overlays for the bounding box and transform handles
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct BoundingBoxManager {
|
||||
|
||||
Reference in New Issue
Block a user