mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-20 11:28:30 +08:00
refactor click targets
This commit is contained in:
@@ -35,8 +35,11 @@ use graphene_std::raster::BlendMode;
|
||||
use graphene_std::raster_types::Raster;
|
||||
use graphene_std::table::Table;
|
||||
use graphene_std::vector::PointId;
|
||||
use graphene_std::vector::algorithms::intersection::bezpath_and_segment_intersections;
|
||||
use graphene_std::vector::click_target::{ClickTarget, ClickTargetType};
|
||||
use graphene_std::vector::misc::{dvec2_to_point, pathseg_to_points, point_to_dvec2, rect_from_minmax};
|
||||
use graphene_std::vector::style::ViewMode;
|
||||
use kurbo::{Affine, BezPath, CubicBez, Line, PathSeg, QuadBez, Rect, Shape};
|
||||
use std::path::PathBuf;
|
||||
use std::time::Duration;
|
||||
|
||||
@@ -973,6 +976,7 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
|
||||
|
||||
let viewport_size = ipp.viewport_bounds.size();
|
||||
let viewport_mid = ipp.viewport_bounds.center();
|
||||
let viewport_mid_rect = Rect::new(viewport_mid.x, viewport_mid.y, viewport_mid.x, viewport_mid.y);
|
||||
let [bounds1, bounds2] = if !self.graph_view_overlay_open {
|
||||
self.metadata().document_bounds_viewport_space().unwrap_or([viewport_mid; 2])
|
||||
} else {
|
||||
@@ -1627,24 +1631,29 @@ impl DocumentMessageHandler {
|
||||
layer_left >= quad_left && layer_right <= quad_right && layer_top <= quad_top && layer_bottom >= quad_bottom
|
||||
}
|
||||
|
||||
pub fn is_layer_fully_inside_polygon(&self, layer: &LayerNodeIdentifier, ipp: &InputPreprocessorMessageHandler, mut viewport_polygon: Subpath<PointId>) -> bool {
|
||||
pub fn is_layer_fully_inside_polygon(&self, layer: &LayerNodeIdentifier, ipp: &InputPreprocessorMessageHandler, mut viewport_polygon: BezPath) -> bool {
|
||||
let document_to_viewport = self.navigation_handler.calculate_offset_transform(ipp.viewport_bounds.center(), &self.document_ptz);
|
||||
viewport_polygon.apply_transform(document_to_viewport.inverse());
|
||||
viewport_polygon.apply_affine(Affine::new(document_to_viewport.to_cols_array()).inverse());
|
||||
|
||||
let layer_click_targets = self.network_interface.document_metadata().click_targets(*layer);
|
||||
let layer_transform = self.network_interface.document_metadata().transform_to_document(*layer);
|
||||
|
||||
layer_click_targets.is_some_and(|targets| {
|
||||
targets.iter().all(|target| match target.target_type() {
|
||||
ClickTargetType::Subpath(subpath) => {
|
||||
let mut subpath = subpath.clone();
|
||||
subpath.apply_transform(layer_transform);
|
||||
subpath.is_inside_subpath(&viewport_polygon, None, None)
|
||||
ClickTargetType::BezPath(bezpath) => {
|
||||
let mut bezpath = bezpath.clone();
|
||||
bezpath.apply_affine(Affine::new(layer_transform.to_cols_array()));
|
||||
|
||||
// TODO: Refactor this into function bezpath_is_inside_bepath()
|
||||
let inside = |segment: PathSeg| pathseg_to_points(segment).iter().filter_map(|point| *point).all(|point| viewport_polygon.contains(point));
|
||||
let intersects = |segment: PathSeg| !bezpath_and_segment_intersections(&viewport_polygon, segment, None, None).is_empty();
|
||||
|
||||
bezpath.segments().all(|segment| inside(segment)) && !bezpath.segments().all(|target_segment| intersects(target_segment))
|
||||
}
|
||||
ClickTargetType::FreePoint(point) => {
|
||||
let mut point = *point;
|
||||
point.apply_transform(layer_transform);
|
||||
viewport_polygon.contains_point(point.position)
|
||||
viewport_polygon.contains(dvec2_to_point(point.position))
|
||||
}
|
||||
})
|
||||
})
|
||||
@@ -2949,21 +2958,21 @@ fn quad_to_path_lib_segments(quad: Quad) -> Vec<path_bool_lib::PathSegment> {
|
||||
}
|
||||
|
||||
fn click_targets_to_path_lib_segments<'a>(click_targets: impl Iterator<Item = &'a ClickTarget>, transform: DAffine2) -> Vec<path_bool_lib::PathSegment> {
|
||||
let segment = |bezier: bezier_rs::Bezier| match bezier.handles {
|
||||
bezier_rs::BezierHandles::Linear => path_bool_lib::PathSegment::Line(bezier.start, bezier.end),
|
||||
bezier_rs::BezierHandles::Quadratic { handle } => path_bool_lib::PathSegment::Quadratic(bezier.start, handle, bezier.end),
|
||||
bezier_rs::BezierHandles::Cubic { handle_start, handle_end } => path_bool_lib::PathSegment::Cubic(bezier.start, handle_start, handle_end, bezier.end),
|
||||
let to_path_bool_segment = |segment: PathSeg| match segment {
|
||||
PathSeg::Line(line) => path_bool_lib::PathSegment::Line(point_to_dvec2(line.p0), point_to_dvec2(line.p1)),
|
||||
PathSeg::Quad(quad) => path_bool_lib::PathSegment::Quadratic(point_to_dvec2(quad.p0), point_to_dvec2(quad.p1), point_to_dvec2(quad.p2)),
|
||||
PathSeg::Cubic(cubic) => path_bool_lib::PathSegment::Cubic(point_to_dvec2(cubic.p0), point_to_dvec2(cubic.p1), point_to_dvec2(cubic.p2), point_to_dvec2(cubic.p3)),
|
||||
};
|
||||
click_targets
|
||||
.filter_map(|target| {
|
||||
if let ClickTargetType::Subpath(subpath) = target.target_type() {
|
||||
Some(subpath.iter())
|
||||
if let ClickTargetType::BezPath(subpath) = target.target_type() {
|
||||
Some(subpath.segments())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.flatten()
|
||||
.map(|bezier| segment(bezier.apply_transformation(|x| transform.transform_point2(x))))
|
||||
.map(|kurbo_segment| to_path_bool_segment(Affine::new(transform.to_cols_array()) * kurbo_segment))
|
||||
.collect()
|
||||
}
|
||||
|
||||
@@ -2988,14 +2997,15 @@ impl<'a> ClickXRayIter<'a> {
|
||||
fn check_layer_area_target(&mut self, click_targets: Option<&Vec<ClickTarget>>, clip: bool, layer: LayerNodeIdentifier, path: Vec<path_bool_lib::PathSegment>, transform: DAffine2) -> XRayResult {
|
||||
// Convert back to Bezier-rs types for intersections
|
||||
let segment = |bezier: &path_bool_lib::PathSegment| match *bezier {
|
||||
path_bool_lib::PathSegment::Line(start, end) => bezier_rs::Bezier::from_linear_dvec2(start, end),
|
||||
path_bool_lib::PathSegment::Cubic(start, h1, h2, end) => bezier_rs::Bezier::from_cubic_dvec2(start, h1, h2, end),
|
||||
path_bool_lib::PathSegment::Quadratic(start, h1, end) => bezier_rs::Bezier::from_quadratic_dvec2(start, h1, end),
|
||||
path_bool_lib::PathSegment::Line(start, end) => PathSeg::Line(Line::new(dvec2_to_point(start), dvec2_to_point(end))),
|
||||
path_bool_lib::PathSegment::Cubic(start, h1, h2, end) => PathSeg::Cubic(CubicBez::new(dvec2_to_point(start), dvec2_to_point(h1), dvec2_to_point(h2), dvec2_to_point(end))),
|
||||
path_bool_lib::PathSegment::Quadratic(start, h1, end) => PathSeg::Quad(QuadBez::new(dvec2_to_point(start), dvec2_to_point(h1), dvec2_to_point(end))),
|
||||
path_bool_lib::PathSegment::Arc(_, _, _, _, _, _, _) => unimplemented!(),
|
||||
};
|
||||
let get_clip = || path.iter().map(segment);
|
||||
let clip_bezpath = BezPath::from_path_segments(path.iter().map(segment));
|
||||
|
||||
let intersects = click_targets.is_some_and(|targets| targets.iter().any(|target| target.intersect_path(get_clip, transform)));
|
||||
// TODO: Avoid cloning bezpath.
|
||||
let intersects = click_targets.is_some_and(|targets| targets.iter().any(|target| target.intersect_path(clip_bezpath.clone(), transform)));
|
||||
let clicked = intersects;
|
||||
let mut use_children = !clip || intersects;
|
||||
|
||||
|
||||
@@ -24,11 +24,9 @@ use bezier_rs::Subpath;
|
||||
use glam::{DAffine2, DVec2, IVec2};
|
||||
use graph_craft::document::{DocumentNodeImplementation, NodeId, NodeInput};
|
||||
use graph_craft::proto::GraphErrors;
|
||||
use graphene_std::math::math_ext::QuadExt;
|
||||
use graphene_std::vector::misc::subpath_to_kurbo_bezpath;
|
||||
use graphene_std::*;
|
||||
use kurbo::{Line, Point};
|
||||
use renderer::Quad;
|
||||
use kurbo::{DEFAULT_ACCURACY, Line, Point, Rect, Shape};
|
||||
use std::cmp::Ordering;
|
||||
|
||||
#[derive(Debug, ExtractField)]
|
||||
@@ -1853,8 +1851,8 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
||||
log::error!("Could not get transient metadata for node {node_id}");
|
||||
continue;
|
||||
};
|
||||
let quad = Quad::from_box([box_selection_start, box_selection_end_graph]);
|
||||
if click_targets.node_click_target.intersect_path(|| quad.bezier_lines(), DAffine2::IDENTITY) {
|
||||
let quad = Rect::new(box_selection_start.x, box_selection_start.y, box_selection_end_graph.x, box_selection_end_graph.y).to_path(DEFAULT_ACCURACY);
|
||||
if click_targets.node_click_target.intersect_path(quad, DAffine2::IDENTITY) {
|
||||
nodes.insert(node_id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ pub fn path_overlays(document: &DocumentMessageHandler, draw_handles: DrawHandle
|
||||
}
|
||||
|
||||
// Get the selected segments and then add a bold line overlay on them
|
||||
for (segment_id, bezier, _, _) in vector.segment_bezier_iter() {
|
||||
for (segment_id, bezier, _, _) in vector.segment_iter() {
|
||||
let Some(selected_shape_state) = shape_editor.selected_shape_state.get_mut(&layer) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
@@ -13,6 +13,7 @@ use graphene_std::Color;
|
||||
use graphene_std::math::quad::Quad;
|
||||
use graphene_std::vector::click_target::ClickTargetType;
|
||||
use graphene_std::vector::{PointId, SegmentId, Vector};
|
||||
use kurbo::PathSeg;
|
||||
use std::collections::HashMap;
|
||||
use wasm_bindgen::{JsCast, JsValue};
|
||||
use web_sys::{OffscreenCanvas, OffscreenCanvasRenderingContext2d};
|
||||
@@ -788,7 +789,7 @@ impl OverlayContext {
|
||||
}
|
||||
|
||||
/// Used by the path tool segment mode in order to show the selected segments.
|
||||
pub fn outline_select_bezier(&mut self, bezier: Bezier, transform: DAffine2) {
|
||||
pub fn outline_select_bezier(&mut self, bezier: PathSeg, transform: DAffine2) {
|
||||
self.start_dpi_aware_transform();
|
||||
|
||||
self.render_context.begin_path();
|
||||
@@ -885,13 +886,13 @@ impl OverlayContext {
|
||||
|
||||
/// Used by the Select tool to outline a path or a free point when selected or hovered.
|
||||
pub fn outline(&mut self, target_types: impl Iterator<Item = impl Borrow<ClickTargetType>>, transform: DAffine2, color: Option<&str>) {
|
||||
let mut subpaths: Vec<bezier_rs::Subpath<PointId>> = vec![];
|
||||
let mut subpaths: Vec<Bezpath> = vec![];
|
||||
|
||||
target_types.for_each(|target_type| match target_type.borrow() {
|
||||
ClickTargetType::FreePoint(point) => {
|
||||
self.manipulator_anchor(transform.transform_point2(point.position), false, None);
|
||||
}
|
||||
ClickTargetType::Subpath(subpath) => subpaths.push(subpath.clone()),
|
||||
ClickTargetType::BezPath(subpath) => subpaths.push(subpath.clone()),
|
||||
});
|
||||
|
||||
if !subpaths.is_empty() {
|
||||
|
||||
@@ -4,14 +4,15 @@ use crate::consts::{
|
||||
PIVOT_CROSSHAIR_LENGTH, PIVOT_CROSSHAIR_THICKNESS, PIVOT_DIAMETER,
|
||||
};
|
||||
use crate::messages::prelude::Message;
|
||||
use bezier_rs::{Bezier, Subpath};
|
||||
use core::borrow::Borrow;
|
||||
use core::f64::consts::{FRAC_PI_2, PI, TAU};
|
||||
use glam::{DAffine2, DVec2};
|
||||
use graphene_std::Color;
|
||||
use graphene_std::math::quad::Quad;
|
||||
use graphene_std::vector::click_target::ClickTargetType;
|
||||
use graphene_std::vector::misc::{is_bezpath_closed, point_to_dvec2};
|
||||
use graphene_std::vector::{PointId, SegmentId, Vector};
|
||||
use kurbo::{Affine, ParamCurve, PathSeg};
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{Arc, Mutex, MutexGuard};
|
||||
use vello::Scene;
|
||||
@@ -343,17 +344,17 @@ impl OverlayContext {
|
||||
}
|
||||
|
||||
/// Used by the Pen tool in order to show how the bezier curve would look like.
|
||||
pub fn outline_bezier(&mut self, bezier: Bezier, transform: DAffine2) {
|
||||
self.internal().outline_bezier(bezier, transform);
|
||||
pub fn outline_bezier(&mut self, segment: PathSeg, transform: DAffine2) {
|
||||
self.internal().outline_bezier(segment, transform);
|
||||
}
|
||||
|
||||
/// Used by the path tool segment mode in order to show the selected segments.
|
||||
pub fn outline_select_bezier(&mut self, bezier: Bezier, transform: DAffine2) {
|
||||
self.internal().outline_select_bezier(bezier, transform);
|
||||
pub fn outline_select_bezier(&mut self, segment: PathSeg, transform: DAffine2) {
|
||||
self.internal().outline_select_bezier(segment, transform);
|
||||
}
|
||||
|
||||
pub fn outline_overlay_bezier(&mut self, bezier: Bezier, transform: DAffine2) {
|
||||
self.internal().outline_overlay_bezier(bezier, transform);
|
||||
pub fn outline_overlay_bezier(&mut self, segment: PathSeg, transform: DAffine2) {
|
||||
self.internal().outline_overlay_bezier(segment, transform);
|
||||
}
|
||||
|
||||
/// Used by the Select tool to outline a path or a free point when selected or hovered.
|
||||
@@ -363,14 +364,14 @@ impl OverlayContext {
|
||||
|
||||
/// Fills the area inside the path. Assumes `color` is in gamma space.
|
||||
/// Used by the Pen tool to show the path being closed.
|
||||
pub fn fill_path(&mut self, subpaths: impl Iterator<Item = impl Borrow<Subpath<PointId>>>, transform: DAffine2, color: &str) {
|
||||
self.internal().fill_path(subpaths, transform, color);
|
||||
pub fn fill_path(&mut self, bezpaths: impl Iterator<Item = impl Borrow<BezPath>>, transform: DAffine2, color: &str) {
|
||||
self.internal().fill_path(bezpaths, transform, color);
|
||||
}
|
||||
|
||||
/// Fills the area inside the path with a pattern. Assumes `color` is in gamma space.
|
||||
/// Used by the fill tool to show the area to be filled.
|
||||
pub fn fill_path_pattern(&mut self, subpaths: impl Iterator<Item = impl Borrow<Subpath<PointId>>>, transform: DAffine2, color: &Color) {
|
||||
self.internal().fill_path_pattern(subpaths, transform, color);
|
||||
pub fn fill_path_pattern(&mut self, bezpaths: impl Iterator<Item = impl Borrow<BezPath>>, transform: DAffine2, color: &Color) {
|
||||
self.internal().fill_path_pattern(bezpaths, transform, color);
|
||||
}
|
||||
|
||||
pub fn get_width(&self, text: &str) -> f64 {
|
||||
@@ -839,18 +840,18 @@ impl OverlayContextInternal {
|
||||
let mut path = BezPath::new();
|
||||
|
||||
let mut last_point = None;
|
||||
for (_, bezier, start_id, end_id) in vector.segment_bezier_iter() {
|
||||
for (_, segment, start_id, end_id) in vector.segment_iter() {
|
||||
let move_to = last_point != Some(start_id);
|
||||
last_point = Some(end_id);
|
||||
|
||||
self.bezier_to_path(bezier, transform, move_to, &mut path);
|
||||
self.bezier_to_path(segment, transform, move_to, &mut path);
|
||||
}
|
||||
|
||||
self.scene.stroke(&kurbo::Stroke::new(1.0), vello_transform, Self::parse_color(COLOR_OVERLAY_BLUE), None, &path);
|
||||
}
|
||||
|
||||
/// Used by the Pen tool in order to show how the bezier curve would look like.
|
||||
fn outline_bezier(&mut self, bezier: Bezier, transform: DAffine2) {
|
||||
fn outline_bezier(&mut self, bezier: PathSeg, transform: DAffine2) {
|
||||
let vello_transform = self.get_transform();
|
||||
let mut path = BezPath::new();
|
||||
self.bezier_to_path(bezier, transform, true, &mut path);
|
||||
@@ -859,7 +860,7 @@ impl OverlayContextInternal {
|
||||
}
|
||||
|
||||
/// Used by the path tool segment mode in order to show the selected segments.
|
||||
fn outline_select_bezier(&mut self, bezier: Bezier, transform: DAffine2) {
|
||||
fn outline_select_bezier(&mut self, bezier: PathSeg, transform: DAffine2) {
|
||||
let vello_transform = self.get_transform();
|
||||
let mut path = BezPath::new();
|
||||
self.bezier_to_path(bezier, transform, true, &mut path);
|
||||
@@ -867,7 +868,7 @@ impl OverlayContextInternal {
|
||||
self.scene.stroke(&kurbo::Stroke::new(4.0), vello_transform, Self::parse_color(COLOR_OVERLAY_BLUE), None, &path);
|
||||
}
|
||||
|
||||
fn outline_overlay_bezier(&mut self, bezier: Bezier, transform: DAffine2) {
|
||||
fn outline_overlay_bezier(&mut self, bezier: PathSeg, transform: DAffine2) {
|
||||
let vello_transform = self.get_transform();
|
||||
let mut path = BezPath::new();
|
||||
self.bezier_to_path(bezier, transform, true, &mut path);
|
||||
@@ -875,55 +876,46 @@ impl OverlayContextInternal {
|
||||
self.scene.stroke(&kurbo::Stroke::new(4.0), vello_transform, Self::parse_color(COLOR_OVERLAY_BLUE_50), None, &path);
|
||||
}
|
||||
|
||||
fn bezier_to_path(&self, bezier: Bezier, transform: DAffine2, move_to: bool, path: &mut BezPath) {
|
||||
let Bezier { start, end, handles } = bezier.apply_transformation(|point| transform.transform_point2(point));
|
||||
fn bezier_to_path(&self, bezier: PathSeg, transform: DAffine2, move_to: bool, path: &mut BezPath) {
|
||||
let segment = Affine::new(transform.to_cols_array()) * bezier;
|
||||
if move_to {
|
||||
path.move_to(kurbo::Point::new(start.x, start.y));
|
||||
}
|
||||
|
||||
match handles {
|
||||
bezier_rs::BezierHandles::Linear => path.line_to(kurbo::Point::new(end.x, end.y)),
|
||||
bezier_rs::BezierHandles::Quadratic { handle } => path.quad_to(kurbo::Point::new(handle.x, handle.y), kurbo::Point::new(end.x, end.y)),
|
||||
bezier_rs::BezierHandles::Cubic { handle_start, handle_end } => path.curve_to(
|
||||
kurbo::Point::new(handle_start.x, handle_start.y),
|
||||
kurbo::Point::new(handle_end.x, handle_end.y),
|
||||
kurbo::Point::new(end.x, end.y),
|
||||
),
|
||||
path.move_to(segment.start());
|
||||
}
|
||||
path.push(segment.as_path_el());
|
||||
}
|
||||
|
||||
fn push_path(&mut self, subpaths: impl Iterator<Item = impl Borrow<Subpath<PointId>>>, transform: DAffine2) -> BezPath {
|
||||
fn push_path(&mut self, bezpaths: impl Iterator<Item = impl Borrow<BezPath>>, transform: DAffine2) -> BezPath {
|
||||
let mut path = BezPath::new();
|
||||
|
||||
for subpath in subpaths {
|
||||
let subpath = subpath.borrow();
|
||||
let mut curves = subpath.iter().peekable();
|
||||
for bezpath in bezpaths {
|
||||
let bezpath = bezpath.borrow();
|
||||
let mut segments = bezpath.segments().peekable();
|
||||
|
||||
let Some(first) = curves.peek() else {
|
||||
let Some(first) = segments.peek() else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let start_point = transform.transform_point2(first.start());
|
||||
let start_point = transform.transform_point2(point_to_dvec2(first.start()));
|
||||
path.move_to(kurbo::Point::new(start_point.x, start_point.y));
|
||||
|
||||
for curve in curves {
|
||||
match curve.handles {
|
||||
bezier_rs::BezierHandles::Linear => {
|
||||
let a = transform.transform_point2(curve.end());
|
||||
for segment in segments {
|
||||
match segment {
|
||||
PathSeg::Line(line) => {
|
||||
let a = transform.transform_point2(point_to_dvec2(line.p1));
|
||||
let a = a.round() - DVec2::splat(0.5);
|
||||
path.line_to(kurbo::Point::new(a.x, a.y));
|
||||
}
|
||||
bezier_rs::BezierHandles::Quadratic { handle } => {
|
||||
let a = transform.transform_point2(handle);
|
||||
let b = transform.transform_point2(curve.end());
|
||||
PathSeg::Quad(quad_bez) => {
|
||||
let a = transform.transform_point2(point_to_dvec2(quad_bez.p1));
|
||||
let b = transform.transform_point2(point_to_dvec2(quad_bez.p2));
|
||||
let a = a.round() - DVec2::splat(0.5);
|
||||
let b = b.round() - DVec2::splat(0.5);
|
||||
path.quad_to(kurbo::Point::new(a.x, a.y), kurbo::Point::new(b.x, b.y));
|
||||
}
|
||||
bezier_rs::BezierHandles::Cubic { handle_start, handle_end } => {
|
||||
let a = transform.transform_point2(handle_start);
|
||||
let b = transform.transform_point2(handle_end);
|
||||
let c = transform.transform_point2(curve.end());
|
||||
PathSeg::Cubic(cubic_bez) => {
|
||||
let a = transform.transform_point2(point_to_dvec2(cubic_bez.p1));
|
||||
let b = transform.transform_point2(point_to_dvec2(cubic_bez.p2));
|
||||
let c = transform.transform_point2(point_to_dvec2(cubic_bez.p3));
|
||||
let a = a.round() - DVec2::splat(0.5);
|
||||
let b = b.round() - DVec2::splat(0.5);
|
||||
let c = c.round() - DVec2::splat(0.5);
|
||||
@@ -932,7 +924,7 @@ impl OverlayContextInternal {
|
||||
}
|
||||
}
|
||||
|
||||
if subpath.closed() {
|
||||
if is_bezpath_closed(bezpath) {
|
||||
path.close_path();
|
||||
}
|
||||
}
|
||||
@@ -942,14 +934,14 @@ impl OverlayContextInternal {
|
||||
|
||||
/// Used by the Select tool to outline a path or a free point when selected or hovered.
|
||||
fn outline(&mut self, target_types: impl Iterator<Item = impl Borrow<ClickTargetType>>, transform: DAffine2, color: Option<&str>) {
|
||||
let mut subpaths: Vec<bezier_rs::Subpath<PointId>> = vec![];
|
||||
let mut subpaths: Vec<BezPath> = vec![];
|
||||
|
||||
for target_type in target_types {
|
||||
match target_type.borrow() {
|
||||
ClickTargetType::FreePoint(point) => {
|
||||
self.manipulator_anchor(transform.transform_point2(point.position), false, None);
|
||||
}
|
||||
ClickTargetType::Subpath(subpath) => subpaths.push(subpath.clone()),
|
||||
ClickTargetType::BezPath(subpath) => subpaths.push(subpath.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -963,18 +955,18 @@ impl OverlayContextInternal {
|
||||
|
||||
/// Fills the area inside the path. Assumes `color` is in gamma space.
|
||||
/// Used by the Pen tool to show the path being closed.
|
||||
fn fill_path(&mut self, subpaths: impl Iterator<Item = impl Borrow<Subpath<PointId>>>, transform: DAffine2, color: &str) {
|
||||
let path = self.push_path(subpaths, transform);
|
||||
fn fill_path(&mut self, bezpaths: impl Iterator<Item = impl Borrow<BezPath>>, transform: DAffine2, color: &str) {
|
||||
let path = self.push_path(bezpaths, transform);
|
||||
|
||||
self.scene.fill(peniko::Fill::NonZero, self.get_transform(), Self::parse_color(color), None, &path);
|
||||
}
|
||||
|
||||
/// Fills the area inside the path with a pattern. Assumes `color` is in gamma space.
|
||||
/// Used by the fill tool to show the area to be filled.
|
||||
fn fill_path_pattern(&mut self, subpaths: impl Iterator<Item = impl Borrow<Subpath<PointId>>>, transform: DAffine2, color: &Color) {
|
||||
fn fill_path_pattern(&mut self, bezpaths: impl Iterator<Item = impl Borrow<BezPath>>, transform: DAffine2, color: &Color) {
|
||||
// TODO: Implement pattern fill in Vello
|
||||
// For now, just fill with a semi-transparent version of the color
|
||||
let path = self.push_path(subpaths, transform);
|
||||
let path = self.push_path(bezpaths, transform);
|
||||
let semi_transparent_color = color.with_alpha(0.5);
|
||||
|
||||
self.scene.fill(
|
||||
|
||||
@@ -5,10 +5,12 @@ use crate::messages::portfolio::document::utility_types::network_interface::Flow
|
||||
use crate::messages::tool::common_functionality::graph_modification_utils;
|
||||
use glam::{DAffine2, DVec2};
|
||||
use graph_craft::document::NodeId;
|
||||
use graphene_std::math::quad::Quad;
|
||||
use graphene_std::renderer::Quad;
|
||||
use graphene_std::transform::Footprint;
|
||||
use graphene_std::vector::Vector;
|
||||
use graphene_std::vector::click_target::{ClickTarget, ClickTargetType};
|
||||
use graphene_std::vector::{PointId, Vector};
|
||||
use graphene_std::vector::misc::{rect_to_minmax, transform_rect};
|
||||
use kurbo::{BezPath, Shape};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::num::NonZeroU64;
|
||||
|
||||
@@ -154,7 +156,7 @@ impl DocumentMetadata {
|
||||
self.click_targets(layer)?
|
||||
.iter()
|
||||
.filter_map(|click_target| match click_target.target_type() {
|
||||
ClickTargetType::Subpath(subpath) => subpath.bounding_box_with_transform(transform),
|
||||
ClickTargetType::BezPath(bezpath) => Some(rect_to_minmax(transform_rect(bezpath.bounding_box(), transform))),
|
||||
ClickTargetType::FreePoint(_) => click_target.bounding_box_with_transform(transform),
|
||||
})
|
||||
.reduce(Quad::combine_bounds)
|
||||
@@ -196,11 +198,11 @@ impl DocumentMetadata {
|
||||
self.all_layers().filter_map(|layer| self.bounding_box_viewport(layer)).reduce(Quad::combine_bounds)
|
||||
}
|
||||
|
||||
pub fn layer_outline(&self, layer: LayerNodeIdentifier) -> impl Iterator<Item = &bezier_rs::Subpath<PointId>> {
|
||||
pub fn layer_outline(&self, layer: LayerNodeIdentifier) -> impl Iterator<Item = &BezPath> {
|
||||
static EMPTY: Vec<ClickTarget> = Vec::new();
|
||||
let click_targets = self.click_targets.get(&layer).unwrap_or(&EMPTY);
|
||||
click_targets.iter().filter_map(|target| match target.target_type() {
|
||||
ClickTargetType::Subpath(subpath) => Some(subpath),
|
||||
ClickTargetType::BezPath(subpath) => Some(subpath),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -18,9 +18,11 @@ use graphene_std::math::quad::Quad;
|
||||
use graphene_std::table::Table;
|
||||
use graphene_std::transform::Footprint;
|
||||
use graphene_std::vector::click_target::{ClickTarget, ClickTargetType};
|
||||
use graphene_std::vector::misc::{combine_rect, rect_from_minmax, rect_to_minmax};
|
||||
use graphene_std::vector::{PointId, Vector, VectorModificationType};
|
||||
use interpreted_executor::dynamic_executor::ResolvedDocumentNodeTypes;
|
||||
use interpreted_executor::node_registry::NODE_REGISTRY;
|
||||
use kurbo::{DEFAULT_ACCURACY, Ellipse, Rect, Shape};
|
||||
use serde_json::{Value, json};
|
||||
use std::collections::{HashMap, HashSet, VecDeque};
|
||||
use std::hash::{DefaultHasher, Hash, Hasher};
|
||||
@@ -2095,10 +2097,12 @@ impl NodeNetworkInterface {
|
||||
let bounding_box_top_right = DVec2::new((all_nodes_bounding_box[1].x / 24. + 0.5).floor() * 24., (all_nodes_bounding_box[0].y / 24. + 0.5).floor() * 24.) + offset_from_top_right;
|
||||
let export_top_right: DVec2 = DVec2::new(viewport_top_right.x.max(bounding_box_top_right.x), viewport_top_right.y.min(bounding_box_top_right.y));
|
||||
let add_export_center = export_top_right + DVec2::new(0., network.exports.len() as f64 * 24.);
|
||||
let add_export = ClickTarget::new_with_subpath(
|
||||
Subpath::new_rounded_rect(add_export_center - DVec2::new(12., 12.), add_export_center + DVec2::new(12., 12.), [3.; 4]),
|
||||
0.,
|
||||
);
|
||||
|
||||
let (corner1, corner2, radii) = (add_export_center - DVec2::new(12., 12.), add_export_center + DVec2::new(12., 12.), 3.);
|
||||
let rounded_rect = Rect::new(corner1.x, corner1.y, corner2.x, corner2.y).to_rounded_rect(radii).to_path(DEFAULT_ACCURACY);
|
||||
|
||||
let add_export = ClickTarget::new_with_bezpath(rounded_rect, 0.);
|
||||
|
||||
add_import_export.insert_custom_input_port(0, add_export);
|
||||
|
||||
let viewport_top_left = network_metadata
|
||||
@@ -2121,10 +2125,11 @@ impl NodeNetworkInterface {
|
||||
let bounding_box_top_left = DVec2::new((all_nodes_bounding_box[0].x / 24. + 0.5).floor() * 24., (all_nodes_bounding_box[0].y / 24. + 0.5).floor() * 24.) + offset_from_top_left;
|
||||
let import_top_left = DVec2::new(viewport_top_left.x.min(bounding_box_top_left.x), viewport_top_left.y.min(bounding_box_top_left.y));
|
||||
let add_import_center = import_top_left + DVec2::new(0., self.number_of_displayed_imports(network_path) as f64 * 24.);
|
||||
let add_import = ClickTarget::new_with_subpath(
|
||||
Subpath::new_rounded_rect(add_import_center - DVec2::new(12., 12.), add_import_center + DVec2::new(12., 12.), [3.; 4]),
|
||||
0.,
|
||||
);
|
||||
|
||||
let (corner1, corner2, radii) = (add_import_center - DVec2::new(12., 12.), add_import_center + DVec2::new(12., 12.), 3.);
|
||||
let rounded_rect = Rect::new(corner1.x, corner1.y, corner2.x, corner2.y).to_rounded_rect(radii).to_path(DEFAULT_ACCURACY);
|
||||
|
||||
let add_import = ClickTarget::new_with_bezpath(rounded_rect, 0.);
|
||||
add_import_export.insert_custom_output_port(0, add_import);
|
||||
|
||||
let Some(import_exports) = self.import_export_ports(network_path) else {
|
||||
@@ -2140,8 +2145,17 @@ impl NodeNetworkInterface {
|
||||
let reorder_import_center = (import_bounding_box[0] + import_bounding_box[1]) / 2. + DVec2::new(-12., 0.);
|
||||
let remove_import_center = reorder_import_center + DVec2::new(-12., 0.);
|
||||
|
||||
let reorder_import = ClickTarget::new_with_subpath(Subpath::new_rect(reorder_import_center - DVec2::new(3., 4.), reorder_import_center + DVec2::new(3., 4.)), 0.);
|
||||
let remove_import = ClickTarget::new_with_subpath(Subpath::new_rect(remove_import_center - DVec2::new(8., 8.), remove_import_center + DVec2::new(8., 8.)), 0.);
|
||||
let corner1 = reorder_import_center - DVec2::new(3., 4.);
|
||||
let corner2 = reorder_import_center + DVec2::new(3., 4.);
|
||||
let rect = Rect::new(corner1.x, corner1.y, corner2.x, corner2.y).to_path(DEFAULT_ACCURACY);
|
||||
|
||||
let reorder_import = ClickTarget::new_with_bezpath(rect, 0.);
|
||||
|
||||
let corner1 = remove_import_center - DVec2::new(8., 8.);
|
||||
let corner2 = remove_import_center + DVec2::new(8., 8.);
|
||||
let rect = Rect::new(corner1.x, corner1.y, corner2.x, corner2.y).to_path(DEFAULT_ACCURACY);
|
||||
|
||||
let remove_import = ClickTarget::new_with_bezpath(rect, 0.);
|
||||
|
||||
reorder_imports_exports.insert_custom_output_port(*import_index, reorder_import);
|
||||
remove_imports_exports.insert_custom_output_port(*import_index, remove_import);
|
||||
@@ -2155,8 +2169,17 @@ impl NodeNetworkInterface {
|
||||
let reorder_export_center = (export_bounding_box[0] + export_bounding_box[1]) / 2. + DVec2::new(12., 0.);
|
||||
let remove_export_center = reorder_export_center + DVec2::new(12., 0.);
|
||||
|
||||
let reorder_export = ClickTarget::new_with_subpath(Subpath::new_rect(reorder_export_center - DVec2::new(3., 4.), reorder_export_center + DVec2::new(3., 4.)), 0.);
|
||||
let remove_export = ClickTarget::new_with_subpath(Subpath::new_rect(remove_export_center - DVec2::new(8., 8.), remove_export_center + DVec2::new(8., 8.)), 0.);
|
||||
let corner1 = reorder_export_center - DVec2::new(3., 4.);
|
||||
let corner2 = reorder_export_center + DVec2::new(3., 4.);
|
||||
let reorder_rect = Rect::new(corner1.x, corner1.y, corner2.x, corner2.y).to_path(DEFAULT_ACCURACY);
|
||||
|
||||
let reorder_export = ClickTarget::new_with_bezpath(reorder_rect, 0.);
|
||||
|
||||
let corner1 = remove_export_center - DVec2::new(8., 8.);
|
||||
let corner2 = remove_export_center + DVec2::new(8., 8.);
|
||||
let remove_rect = Rect::new(corner1.x, corner1.y, corner2.x, corner2.y).to_path(DEFAULT_ACCURACY);
|
||||
|
||||
let remove_export = ClickTarget::new_with_bezpath(remove_rect, 0.);
|
||||
|
||||
reorder_imports_exports.insert_custom_input_port(*export_index, reorder_export);
|
||||
remove_imports_exports.insert_custom_input_port(*export_index, remove_export);
|
||||
@@ -2787,6 +2810,7 @@ impl NodeNetworkInterface {
|
||||
Some(click_target)
|
||||
}
|
||||
|
||||
// REFACTOR
|
||||
pub fn load_node_click_targets(&mut self, node_id: &NodeId, network_path: &[NodeId]) {
|
||||
let Some(node_position) = self.position_from_downstream_node(node_id, network_path) else {
|
||||
log::error!("Could not get node position in load_node_click_targets for node {node_id}");
|
||||
@@ -2833,8 +2857,16 @@ impl NodeNetworkInterface {
|
||||
let node_click_target_bottom_right = node_click_target_top_left + DVec2::new(width as f64, height as f64);
|
||||
|
||||
let radius = 3.;
|
||||
let subpath = bezier_rs::Subpath::new_rounded_rect(node_click_target_top_left, node_click_target_bottom_right, [radius; 4]);
|
||||
let node_click_target = ClickTarget::new_with_subpath(subpath, 0.);
|
||||
let rounded_rect = Rect::new(
|
||||
node_click_target_top_left.x,
|
||||
node_click_target_top_left.y,
|
||||
node_click_target_bottom_right.x,
|
||||
node_click_target_bottom_right.y,
|
||||
)
|
||||
.to_rounded_rect(radius)
|
||||
.to_path(DEFAULT_ACCURACY);
|
||||
|
||||
let node_click_target = ClickTarget::new_with_bezpath(rounded_rect, 0.);
|
||||
|
||||
DocumentNodeClickTargets {
|
||||
node_click_target,
|
||||
@@ -2858,13 +2890,21 @@ impl NodeNetworkInterface {
|
||||
|
||||
// Update visibility button click target
|
||||
let visibility_offset = node_top_left + DVec2::new(width as f64, 24.);
|
||||
let subpath = Subpath::new_rounded_rect(DVec2::new(-12., -12.) + visibility_offset, DVec2::new(12., 12.) + visibility_offset, [3.; 4]);
|
||||
let visibility_click_target = ClickTarget::new_with_subpath(subpath, 0.);
|
||||
|
||||
let corner1 = DVec2::new(-12., -12.) + visibility_offset;
|
||||
let corner2 = DVec2::new(12., 12.) + visibility_offset;
|
||||
let rounded_rect = Rect::new(corner1.x, corner1.y, corner2.x, corner2.y).to_rounded_rect(3.).to_path(DEFAULT_ACCURACY);
|
||||
|
||||
let visibility_click_target = ClickTarget::new_with_bezpath(rounded_rect, 0.);
|
||||
|
||||
// Update grip button click target, which is positioned to the left of the left most icon
|
||||
let grip_offset_right_edge = node_top_left + DVec2::new(width as f64 - (GRID_SIZE as f64) / 2., 24.);
|
||||
let subpath = Subpath::new_rounded_rect(DVec2::new(-8., -12.) + grip_offset_right_edge, DVec2::new(0., 12.) + grip_offset_right_edge, [0.; 4]);
|
||||
let grip_click_target = ClickTarget::new_with_subpath(subpath, 0.);
|
||||
|
||||
let corner1 = DVec2::new(-8., -12.) + grip_offset_right_edge;
|
||||
let corner2 = DVec2::new(0., 12.) + grip_offset_right_edge;
|
||||
let rounded_rect = Rect::new(corner1.x, corner1.y, corner2.x, corner2.y).to_rounded_rect(0.).to_path(DEFAULT_ACCURACY);
|
||||
|
||||
let grip_click_target = ClickTarget::new_with_bezpath(rounded_rect, 0.);
|
||||
|
||||
// Create layer click target, which is contains the layer and the chain background
|
||||
let chain_width_grid_spaces = self.chain_width(node_id, network_path);
|
||||
@@ -2872,8 +2912,12 @@ impl NodeNetworkInterface {
|
||||
let node_bottom_right = node_top_left + DVec2::new(width as f64, height as f64);
|
||||
let chain_top_left = node_top_left - DVec2::new((chain_width_grid_spaces * crate::consts::GRID_SIZE) as f64, 0.);
|
||||
let radius = 10.;
|
||||
let subpath = bezier_rs::Subpath::new_rounded_rect(chain_top_left, node_bottom_right, [radius; 4]);
|
||||
let node_click_target = ClickTarget::new_with_subpath(subpath, 0.);
|
||||
|
||||
let rounded_rect = Rect::new(chain_top_left.x, chain_top_left.y, node_bottom_right.x, node_bottom_right.y)
|
||||
.to_rounded_rect(radius)
|
||||
.to_path(DEFAULT_ACCURACY);
|
||||
|
||||
let node_click_target = ClickTarget::new_with_bezpath(rounded_rect, 0.);
|
||||
|
||||
DocumentNodeClickTargets {
|
||||
node_click_target,
|
||||
@@ -3059,28 +3103,22 @@ impl NodeNetworkInterface {
|
||||
if let (Some(import_export_click_targets), Some(node_click_targets)) = (self.import_export_ports(network_path).cloned(), self.node_click_targets(&node_id, network_path)) {
|
||||
let mut node_path = String::new();
|
||||
|
||||
if let ClickTargetType::Subpath(subpath) = node_click_targets.node_click_target.target_type() {
|
||||
let _ = subpath.subpath_to_svg(&mut node_path, DAffine2::IDENTITY);
|
||||
if let ClickTargetType::BezPath(subpath) = node_click_targets.node_click_target.target_type() {
|
||||
node_path.push_str(&subpath.to_svg());
|
||||
}
|
||||
all_node_click_targets.push((node_id, node_path));
|
||||
for port in node_click_targets.port_click_targets.click_targets().chain(import_export_click_targets.click_targets()) {
|
||||
if let ClickTargetType::Subpath(subpath) = port.target_type() {
|
||||
let mut port_path = String::new();
|
||||
let _ = subpath.subpath_to_svg(&mut port_path, DAffine2::IDENTITY);
|
||||
port_click_targets.push(port_path);
|
||||
if let ClickTargetType::BezPath(subpath) = port.target_type() {
|
||||
port_click_targets.push(subpath.to_svg());
|
||||
}
|
||||
}
|
||||
if let NodeTypeClickTargets::Layer(layer_metadata) = &node_click_targets.node_type_metadata {
|
||||
if let ClickTargetType::Subpath(subpath) = layer_metadata.visibility_click_target.target_type() {
|
||||
let mut port_path = String::new();
|
||||
let _ = subpath.subpath_to_svg(&mut port_path, DAffine2::IDENTITY);
|
||||
icon_click_targets.push(port_path);
|
||||
if let ClickTargetType::BezPath(subpath) = layer_metadata.visibility_click_target.target_type() {
|
||||
icon_click_targets.push(subpath.to_svg());
|
||||
}
|
||||
|
||||
if let ClickTargetType::Subpath(subpath) = layer_metadata.grip_click_target.target_type() {
|
||||
let mut port_path = String::new();
|
||||
let _ = subpath.subpath_to_svg(&mut port_path, DAffine2::IDENTITY);
|
||||
icon_click_targets.push(port_path);
|
||||
if let ClickTargetType::BezPath(subpath) = layer_metadata.grip_click_target.target_type() {
|
||||
icon_click_targets.push(subpath.to_svg());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3136,10 +3174,8 @@ impl NodeNetworkInterface {
|
||||
.chain(modify_import_export_click_targets.remove_imports_exports.click_targets())
|
||||
.chain(modify_import_export_click_targets.reorder_imports_exports.click_targets())
|
||||
{
|
||||
if let ClickTargetType::Subpath(subpath) = click_target.target_type() {
|
||||
let mut remove_string = String::new();
|
||||
let _ = subpath.subpath_to_svg(&mut remove_string, DAffine2::IDENTITY);
|
||||
modify_import_export.push(remove_string);
|
||||
if let ClickTargetType::BezPath(bezpath) = click_target.target_type() {
|
||||
modify_import_export.push(bezpath.to_svg());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6217,8 +6253,10 @@ impl Ports {
|
||||
}
|
||||
|
||||
fn insert_input_port_at_center(&mut self, input_index: usize, center: DVec2) {
|
||||
let subpath = Subpath::new_ellipse(center - DVec2::new(8., 8.), center + DVec2::new(8., 8.));
|
||||
self.insert_custom_input_port(input_index, ClickTarget::new_with_subpath(subpath, 0.));
|
||||
let corner1 = center - DVec2::new(8., 8.);
|
||||
let corner2 = center + DVec2::new(8., 8.);
|
||||
let bezpath = Ellipse::from_rect(Rect::new(corner1.x, corner1.y, corner2.x, corner2.y)).to_path(DEFAULT_ACCURACY);
|
||||
self.insert_custom_input_port(input_index, ClickTarget::new_with_bezpath(bezpath, 0.));
|
||||
}
|
||||
|
||||
fn insert_custom_input_port(&mut self, input_index: usize, click_target: ClickTarget) {
|
||||
@@ -6226,8 +6264,10 @@ impl Ports {
|
||||
}
|
||||
|
||||
fn insert_output_port_at_center(&mut self, output_index: usize, center: DVec2) {
|
||||
let subpath = Subpath::new_ellipse(center - DVec2::new(8., 8.), center + DVec2::new(8., 8.));
|
||||
self.insert_custom_output_port(output_index, ClickTarget::new_with_subpath(subpath, 0.));
|
||||
let corner1 = center - DVec2::new(8., 8.);
|
||||
let corner2 = center + DVec2::new(8., 8.);
|
||||
let bezpath = Ellipse::from_rect(Rect::new(corner1.x, corner1.y, corner2.x, corner2.y)).to_path(DEFAULT_ACCURACY);
|
||||
self.insert_custom_output_port(output_index, ClickTarget::new_with_bezpath(bezpath, 0.));
|
||||
}
|
||||
|
||||
fn insert_custom_output_port(&mut self, output_index: usize, click_target: ClickTarget) {
|
||||
|
||||
@@ -8,8 +8,9 @@ use crate::messages::tool::common_functionality::shape_editor::ShapeState;
|
||||
use crate::messages::tool::utility_types::ToolType;
|
||||
use glam::{DAffine2, DMat2, DVec2};
|
||||
use graphene_std::renderer::Quad;
|
||||
use graphene_std::vector::misc::{HandleId, ManipulatorPointId};
|
||||
use graphene_std::vector::misc::{HandleId, ManipulatorPointId, combine_rect, point_to_dvec2, transform_rect};
|
||||
use graphene_std::vector::{HandleExt, PointId, VectorModificationType};
|
||||
use kurbo::Rect;
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
use std::f64::consts::PI;
|
||||
|
||||
|
||||
@@ -13,8 +13,9 @@ use crate::messages::tool::common_functionality::utility_functions::{is_intersec
|
||||
use crate::messages::tool::tool_messages::path_tool::{PathOverlayMode, PointSelectState};
|
||||
use bezier_rs::{Bezier, BezierHandles, Subpath, TValue};
|
||||
use glam::{DAffine2, DVec2};
|
||||
use graphene_std::vector::misc::{HandleId, ManipulatorPointId};
|
||||
use graphene_std::vector::misc::{HandleId, ManipulatorPointId, handles_to_segment};
|
||||
use graphene_std::vector::{HandleExt, PointId, SegmentId, Vector, VectorModificationType};
|
||||
use kurbo::PathSeg;
|
||||
use std::f64::consts::TAU;
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
@@ -209,6 +210,10 @@ impl ClosestSegment {
|
||||
self.bezier
|
||||
}
|
||||
|
||||
pub fn to_pathseg(&self) -> PathSeg {
|
||||
handles_to_segment(self.bezier.start, self.bezier.handles, self.bezier.end)
|
||||
}
|
||||
|
||||
pub fn closest_point_document(&self) -> DVec2 {
|
||||
self.bezier.evaluate(TValue::Parametric(self.t))
|
||||
}
|
||||
|
||||
@@ -328,7 +328,7 @@ pub fn star_outline(layer: Option<LayerNodeIdentifier>, document: &DocumentMessa
|
||||
let diameter: f64 = radius1 * 2.;
|
||||
let inner_diameter = radius2 * 2.;
|
||||
|
||||
let subpath: Vec<ClickTargetType> = vec![ClickTargetType::Subpath(Subpath::new_star_polygon(DVec2::splat(-diameter), points, diameter, inner_diameter))];
|
||||
let subpath: Vec<ClickTargetType> = vec![ClickTargetType::BezPath(Subpath::new_star_polygon(DVec2::splat(-diameter), points, diameter, inner_diameter))];
|
||||
|
||||
overlay_context.outline(subpath.iter(), viewport, None);
|
||||
}
|
||||
@@ -345,7 +345,7 @@ pub fn polygon_outline(layer: Option<LayerNodeIdentifier>, document: &DocumentMe
|
||||
let points = sides as u64;
|
||||
let radius: f64 = radius * 2.;
|
||||
|
||||
let subpath: Vec<ClickTargetType> = vec![ClickTargetType::Subpath(Subpath::new_regular_polygon(DVec2::splat(-radius), points, radius))];
|
||||
let subpath: Vec<ClickTargetType> = vec![ClickTargetType::BezPath(Subpath::new_regular_polygon(DVec2::splat(-radius), points, radius))];
|
||||
|
||||
overlay_context.outline(subpath.iter(), viewport, None);
|
||||
}
|
||||
@@ -358,7 +358,7 @@ pub fn arc_outline(layer: Option<LayerNodeIdentifier>, document: &DocumentMessag
|
||||
return;
|
||||
};
|
||||
|
||||
let subpath: Vec<ClickTargetType> = vec![ClickTargetType::Subpath(Subpath::new_arc(
|
||||
let subpath: Vec<ClickTargetType> = vec![ClickTargetType::BezPath(Subpath::new_arc(
|
||||
radius,
|
||||
start_angle / 360. * std::f64::consts::TAU,
|
||||
sweep_angle / 360. * std::f64::consts::TAU,
|
||||
|
||||
@@ -48,6 +48,7 @@ impl LayerSnapper {
|
||||
}
|
||||
}
|
||||
|
||||
///////// Find why
|
||||
pub fn collect_paths(&mut self, snap_data: &mut SnapData, first_point: bool) {
|
||||
if !first_point {
|
||||
return;
|
||||
@@ -69,9 +70,9 @@ impl LayerSnapper {
|
||||
|
||||
if document.snapping_state.target_enabled(SnapTarget::Path(PathSnapTarget::IntersectionPoint)) || document.snapping_state.target_enabled(SnapTarget::Path(PathSnapTarget::AlongPath)) {
|
||||
for subpath in document.metadata().layer_outline(layer) {
|
||||
for (start_index, curve) in subpath.iter().enumerate() {
|
||||
let document_curve = curve.apply_transformation(|p| transform.transform_point2(p));
|
||||
let start = subpath.manipulator_groups()[start_index].id;
|
||||
for (start_index, curve) in subpath.segments().enumerate() {
|
||||
let document_curve = curve.app(|p| transform.transform_point2(p));
|
||||
let start = 0;
|
||||
if snap_data.ignore_manipulator(layer, start) || snap_data.ignore_manipulator(layer, subpath.manipulator_groups()[(start_index + 1) % subpath.len()].id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1737,7 +1737,7 @@ impl Fsm for PathToolFsmState {
|
||||
if tool_options.path_editing_mode.segment_editing_mode && !tool_data.segment_editing_modifier {
|
||||
let transform = document.metadata().transform_to_viewport_if_feeds(closest_segment.layer(), &document.network_interface);
|
||||
|
||||
overlay_context.outline_overlay_bezier(closest_segment.bezier(), transform);
|
||||
overlay_context.outline_overlay_bezier(closest_segment.to_pathseg(), transform);
|
||||
|
||||
// Draw the anchors again
|
||||
let display_anchors = overlay_context.visibility_settings.anchors();
|
||||
@@ -1865,9 +1865,9 @@ impl Fsm for PathToolFsmState {
|
||||
|
||||
let transform = document.metadata().transform_to_viewport_if_feeds(layer, &document.network_interface);
|
||||
|
||||
for (segment, bezier, _, _) in vector.segment_bezier_iter() {
|
||||
if segments.contains(&segment) {
|
||||
overlay_context.outline_overlay_bezier(bezier, transform);
|
||||
for (segment_id, segment, _, _) in vector.segment_iter() {
|
||||
if segments.contains(&segment_id) {
|
||||
overlay_context.outline_overlay_bezier(segment, transform);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ use crate::messages::tool::common_functionality::utility_functions::{calculate_s
|
||||
use bezier_rs::{Bezier, BezierHandles};
|
||||
use graph_craft::document::NodeId;
|
||||
use graphene_std::Color;
|
||||
use graphene_std::vector::misc::{HandleId, ManipulatorPointId};
|
||||
use graphene_std::vector::misc::{HandleId, ManipulatorPointId, bezpath_from_manipulator_groups, handles_to_segment};
|
||||
use graphene_std::vector::{NoHashBuilder, PointId, SegmentId, StrokeId, Vector, VectorModificationType};
|
||||
|
||||
#[derive(Default, ExtractField)]
|
||||
@@ -1603,7 +1603,7 @@ impl Fsm for PenToolFsmState {
|
||||
let bezier = Bezier { start, handles, end };
|
||||
if (end - start).length_squared() > f64::EPSILON {
|
||||
// Draw the curve for the currently-being-placed segment
|
||||
overlay_context.outline_bezier(bezier, transform);
|
||||
overlay_context.outline_bezier(handles_to_segment(start, handles, end), transform);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1738,6 +1738,7 @@ impl Fsm for PenToolFsmState {
|
||||
});
|
||||
vector.subpath_from_segments_ignore_discontinuities(segments)
|
||||
})
|
||||
.map(|subpath| bezpath_from_manipulator_groups(subpath.manipulator_groups(), subpath.closed))
|
||||
.collect();
|
||||
|
||||
let mut fill_color = graphene_std::Color::from_rgb_str(COLOR_OVERLAY_BLUE.strip_prefix('#').unwrap())
|
||||
|
||||
@@ -27,6 +27,7 @@ use graphene_std::path_bool::BooleanOperation;
|
||||
use graphene_std::renderer::Quad;
|
||||
use graphene_std::renderer::Rect;
|
||||
use graphene_std::transform::ReferencePoint;
|
||||
use graphene_std::vector::misc::bezpath_from_manipulator_groups;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Default, ExtractField)]
|
||||
@@ -463,6 +464,7 @@ impl SelectToolData {
|
||||
return false;
|
||||
}
|
||||
let polygon = Subpath::from_anchors_linear(self.lasso_polygon.clone(), true);
|
||||
let polygon = bezpath_from_manipulator_groups(polygon.manipulator_groups(), polygon.closed);
|
||||
document.is_layer_fully_inside_polygon(layer, input, polygon)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user