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::prelude::*;
use bezier_rs::{Subpath, TValue};
use bezier_rs::TValue;
use graphene_core::renderer::Quad;
use graphene_core::vector::PointId;
use graphene_std::renderer::Rect;
@ -151,7 +151,7 @@ fn get_closest_intersection(snap_to: DVec2, curves: &[SnappedCurve]) -> Option<S
distance,
target: SnapTarget::Path(PathSnapTarget::IntersectionPoint),
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,
at_intersection: true,
constrained: true,
@ -443,9 +443,9 @@ impl SnapManager {
pub fn draw_overlays(&mut self, snap_data: SnapData, overlay_context: &mut OverlayContext) {
let to_viewport = snap_data.document.metadata().document_to_viewport;
if let Some(ind) = &self.indicator {
for curve in &ind.curves {
let Some(curve) = curve else { continue };
overlay_context.outline([Subpath::from_bezier(curve)].iter(), to_viewport);
for layer in &ind.outline_layers {
let &Some(layer) = layer else { continue };
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 {
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 bezier_rs::Bezier;
use glam::DVec2;
use graphene_core::renderer::Quad;
@ -172,10 +171,6 @@ impl GridSnapper {
at_intersection: false,
constrained: true,
source_bounds: point.quad,
curves: [
Some(Bezier::from_linear_dvec2(projected - constraint_direction * tolerance, projected + constraint_direction * tolerance)),
None,
],
distance,
tolerance,
..Default::default()

View File

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

View File

@ -27,7 +27,8 @@ pub struct SnappedPoint {
pub fully_constrained: bool,
pub target_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 tolerance: f64,
pub distribution_boxes_x: VecDeque<Rect>,