Give the current snapping target layer(s) an outline (#2224)

* Outline layer when snapping

* Outline layers when snapping to anchors
This commit is contained in:
James Lindsay 2025-01-25 21:00:01 +00:00 committed by GitHub
parent eada1eba54
commit 26d66298cf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 25 additions and 22 deletions

View File

@ -11,7 +11,7 @@ use crate::messages::portfolio::document::utility_types::document_metadata::Laye
use crate::messages::portfolio::document::utility_types::misc::{GridSnapTarget, PathSnapTarget, SnapTarget}; use crate::messages::portfolio::document::utility_types::misc::{GridSnapTarget, PathSnapTarget, SnapTarget};
use crate::messages::prelude::*; use crate::messages::prelude::*;
use bezier_rs::{Subpath, TValue}; use bezier_rs::TValue;
use graphene_core::renderer::Quad; use graphene_core::renderer::Quad;
use graphene_core::vector::PointId; use graphene_core::vector::PointId;
use graphene_std::renderer::Rect; use graphene_std::renderer::Rect;
@ -151,7 +151,7 @@ fn get_closest_intersection(snap_to: DVec2, curves: &[SnappedCurve]) -> Option<S
distance, distance,
target: SnapTarget::Path(PathSnapTarget::IntersectionPoint), target: SnapTarget::Path(PathSnapTarget::IntersectionPoint),
tolerance: close.point.tolerance, tolerance: close.point.tolerance,
curves: [Some(close.document_curve), Some(far.document_curve)], outline_layers: [Some(close.layer), Some(far.layer)],
source: close.point.source, source: close.point.source,
at_intersection: true, at_intersection: true,
constrained: true, constrained: true,
@ -443,9 +443,9 @@ impl SnapManager {
pub fn draw_overlays(&mut self, snap_data: SnapData, overlay_context: &mut OverlayContext) { pub fn draw_overlays(&mut self, snap_data: SnapData, overlay_context: &mut OverlayContext) {
let to_viewport = snap_data.document.metadata().document_to_viewport; let to_viewport = snap_data.document.metadata().document_to_viewport;
if let Some(ind) = &self.indicator { if let Some(ind) = &self.indicator {
for curve in &ind.curves { for layer in &ind.outline_layers {
let Some(curve) = curve else { continue }; let &Some(layer) = layer else { continue };
overlay_context.outline([Subpath::from_bezier(curve)].iter(), to_viewport); overlay_context.outline(snap_data.document.metadata().layer_outline(layer), snap_data.document.metadata().transform_to_viewport(layer));
} }
if let Some(quad) = ind.target_bounds { if let Some(quad) = ind.target_bounds {
overlay_context.quad(to_viewport * quad, None); overlay_context.quad(to_viewport * quad, None);

View File

@ -2,7 +2,6 @@ use super::*;
use crate::messages::portfolio::document::utility_types::misc::{GridSnapTarget, GridSnapping, GridType, SnapTarget}; use crate::messages::portfolio::document::utility_types::misc::{GridSnapTarget, GridSnapping, GridType, SnapTarget};
use bezier_rs::Bezier;
use glam::DVec2; use glam::DVec2;
use graphene_core::renderer::Quad; use graphene_core::renderer::Quad;
@ -172,10 +171,6 @@ impl GridSnapper {
at_intersection: false, at_intersection: false,
constrained: true, constrained: true,
source_bounds: point.quad, source_bounds: point.quad,
curves: [
Some(Bezier::from_linear_dvec2(projected - constraint_direction * tolerance, projected + constraint_direction * tolerance)),
None,
],
distance, distance,
tolerance, tolerance,
..Default::default() ..Default::default()

View File

@ -117,7 +117,7 @@ impl LayerSnapper {
target: path.target, target: path.target,
distance, distance,
tolerance, tolerance,
curves: [path.bounds.is_none().then_some(path.document_curve), None], outline_layers: [path.bounds.is_none().then_some(path.layer), None],
source: point.source, source: point.source,
target_bounds: path.bounds, target_bounds: path.bounds,
..Default::default() ..Default::default()
@ -156,7 +156,7 @@ impl LayerSnapper {
target: path.target, target: path.target,
distance, distance,
tolerance, tolerance,
curves: [path.bounds.is_none().then_some(path.document_curve), None], outline_layers: [path.bounds.is_none().then_some(path.layer), None],
source: point.source, source: point.source,
target_bounds: path.bounds, target_bounds: path.bounds,
at_intersection: true, at_intersection: true,
@ -241,6 +241,7 @@ impl LayerSnapper {
tolerance, tolerance,
constrained: true, constrained: true,
target_bounds: candidate.quad, target_bounds: candidate.quad,
outline_layers: [candidate.outline_layer, None],
..Default::default() ..Default::default()
}); });
} }
@ -277,7 +278,7 @@ fn normals_and_tangents(path: &SnapCandidatePath, normals: bool, tangents: bool,
target: SnapTarget::Path(PathSnapTarget::NormalToPath), target: SnapTarget::Path(PathSnapTarget::NormalToPath),
distance, distance,
tolerance, tolerance,
curves: [Some(path.document_curve), None], outline_layers: [Some(path.layer), None],
source: point.source, source: point.source,
constrained: true, constrained: true,
..Default::default() ..Default::default()
@ -298,7 +299,7 @@ fn normals_and_tangents(path: &SnapCandidatePath, normals: bool, tangents: bool,
target: SnapTarget::Path(PathSnapTarget::TangentToPath), target: SnapTarget::Path(PathSnapTarget::TangentToPath),
distance, distance,
tolerance, tolerance,
curves: [Some(path.document_curve), None], outline_layers: [Some(path.layer), None],
source: point.source, source: point.source,
constrained: true, constrained: true,
..Default::default() ..Default::default()
@ -323,27 +324,30 @@ pub struct SnapCandidatePoint {
pub source: SnapSource, pub source: SnapSource,
pub target: SnapTarget, pub target: SnapTarget,
pub quad: Option<Quad>, pub quad: Option<Quad>,
/// This layer is outlined if the snap candidate is used.
pub outline_layer: Option<LayerNodeIdentifier>,
pub neighbors: Vec<DVec2>, pub neighbors: Vec<DVec2>,
pub alignment: bool, pub alignment: bool,
} }
impl SnapCandidatePoint { impl SnapCandidatePoint {
pub fn new(document_point: DVec2, source: SnapSource, target: SnapTarget) -> Self { pub fn new(document_point: DVec2, source: SnapSource, target: SnapTarget, outline_layer: Option<LayerNodeIdentifier>) -> Self {
Self::new_quad(document_point, source, target, None, true) Self::new_quad(document_point, source, target, None, outline_layer, true)
} }
pub fn new_quad(document_point: DVec2, source: SnapSource, target: SnapTarget, quad: Option<Quad>, alignment: bool) -> Self { pub fn new_quad(document_point: DVec2, source: SnapSource, target: SnapTarget, quad: Option<Quad>, outline_layer: Option<LayerNodeIdentifier>, alignment: bool) -> Self {
Self { Self {
document_point, document_point,
source, source,
target, target,
quad, quad,
outline_layer,
alignment, alignment,
..Default::default() ..Default::default()
} }
} }
pub fn new_source(document_point: DVec2, source: SnapSource) -> Self { pub fn new_source(document_point: DVec2, source: SnapSource) -> Self {
Self::new(document_point, source, SnapTarget::None) Self::new(document_point, source, SnapTarget::None, None)
} }
pub fn handle(document_point: DVec2) -> Self { pub fn handle(document_point: DVec2) -> Self {
@ -409,15 +413,15 @@ pub fn get_bbox_points(quad: Quad, points: &mut Vec<SnapCandidatePoint>, values:
let start = quad.0[index]; let start = quad.0[index];
let end = quad.0[(index + 1) % 4]; let end = quad.0[(index + 1) % 4];
if document.snapping_state.target_enabled(values.corner_target) { if document.snapping_state.target_enabled(values.corner_target) {
points.push(SnapCandidatePoint::new_quad(start, values.corner_source, values.corner_target, Some(quad), false)); points.push(SnapCandidatePoint::new_quad(start, values.corner_source, values.corner_target, Some(quad), None, false));
} }
if document.snapping_state.target_enabled(values.edge_target) { if document.snapping_state.target_enabled(values.edge_target) {
points.push(SnapCandidatePoint::new_quad((start + end) / 2., values.edge_source, values.edge_target, Some(quad), false)); points.push(SnapCandidatePoint::new_quad((start + end) / 2., values.edge_source, values.edge_target, Some(quad), None, false));
} }
} }
if document.snapping_state.target_enabled(values.center_target) { if document.snapping_state.target_enabled(values.center_target) {
points.push(SnapCandidatePoint::new_quad(quad.center(), values.center_source, values.center_target, Some(quad), false)); points.push(SnapCandidatePoint::new_quad(quad.center(), values.center_source, values.center_target, Some(quad), None, false));
} }
} }
@ -445,6 +449,7 @@ fn subpath_anchor_snap_points(layer: LayerNodeIdentifier, subpath: &Subpath<Poin
to_document.transform_point2(curve.start() * 0.5 + curve.end * 0.5), to_document.transform_point2(curve.start() * 0.5 + curve.end * 0.5),
SnapSource::Path(PathSnapSource::LineMidpoint), SnapSource::Path(PathSnapSource::LineMidpoint),
SnapTarget::Path(PathSnapTarget::LineMidpoint), SnapTarget::Path(PathSnapTarget::LineMidpoint),
Some(layer),
)); ));
} }
} }
@ -468,6 +473,7 @@ fn subpath_anchor_snap_points(layer: LayerNodeIdentifier, subpath: &Subpath<Poin
to_document.transform_point2(group.anchor), to_document.transform_point2(group.anchor),
SnapSource::Path(PathSnapSource::AnchorPointWithColinearHandles), SnapSource::Path(PathSnapSource::AnchorPointWithColinearHandles),
SnapTarget::Path(PathSnapTarget::AnchorPointWithColinearHandles), SnapTarget::Path(PathSnapTarget::AnchorPointWithColinearHandles),
Some(layer),
)); ));
} }
// Free handles // Free handles
@ -476,6 +482,7 @@ fn subpath_anchor_snap_points(layer: LayerNodeIdentifier, subpath: &Subpath<Poin
to_document.transform_point2(group.anchor), to_document.transform_point2(group.anchor),
SnapSource::Path(PathSnapSource::AnchorPointWithFreeHandles), SnapSource::Path(PathSnapSource::AnchorPointWithFreeHandles),
SnapTarget::Path(PathSnapTarget::AnchorPointWithFreeHandles), SnapTarget::Path(PathSnapTarget::AnchorPointWithFreeHandles),
Some(layer),
)); ));
} }
} }

View File

@ -27,7 +27,8 @@ pub struct SnappedPoint {
pub fully_constrained: bool, pub fully_constrained: bool,
pub target_bounds: Option<Quad>, pub target_bounds: Option<Quad>,
pub source_bounds: Option<Quad>, pub source_bounds: Option<Quad>,
pub curves: [Option<Bezier>; 2], /// These layer(s) are outlined in the overlays when the snap is used.
pub outline_layers: [Option<LayerNodeIdentifier>; 2],
pub distance: f64, pub distance: f64,
pub tolerance: f64, pub tolerance: f64,
pub distribution_boxes_x: VecDeque<Rect>, pub distribution_boxes_x: VecDeque<Rect>,