Add handle visualization during point insertion in the Path tool (#2197)
* added_handle_overlays * changed color to yellow * Rename color parameter * Change the color to blue --------- Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
parent
0a496ee452
commit
5aedda0ce8
|
|
@ -41,16 +41,16 @@ pub fn path_overlays(document: &DocumentMessageHandler, shape_editor: &mut Shape
|
||||||
bezier_rs::BezierHandles::Quadratic { handle } if not_under_anchor(handle, bezier.start) && not_under_anchor(handle, bezier.end) => {
|
bezier_rs::BezierHandles::Quadratic { handle } if not_under_anchor(handle, bezier.start) && not_under_anchor(handle, bezier.end) => {
|
||||||
overlay_context.line(handle, bezier.start, None);
|
overlay_context.line(handle, bezier.start, None);
|
||||||
overlay_context.line(handle, bezier.end, None);
|
overlay_context.line(handle, bezier.end, None);
|
||||||
overlay_context.manipulator_handle(handle, is_selected(selected, ManipulatorPointId::PrimaryHandle(segment_id)));
|
overlay_context.manipulator_handle(handle, is_selected(selected, ManipulatorPointId::PrimaryHandle(segment_id)), None);
|
||||||
}
|
}
|
||||||
bezier_rs::BezierHandles::Cubic { handle_start, handle_end } => {
|
bezier_rs::BezierHandles::Cubic { handle_start, handle_end } => {
|
||||||
if not_under_anchor(handle_start, bezier.start) {
|
if not_under_anchor(handle_start, bezier.start) {
|
||||||
overlay_context.line(handle_start, bezier.start, None);
|
overlay_context.line(handle_start, bezier.start, None);
|
||||||
overlay_context.manipulator_handle(handle_start, is_selected(selected, ManipulatorPointId::PrimaryHandle(segment_id)));
|
overlay_context.manipulator_handle(handle_start, is_selected(selected, ManipulatorPointId::PrimaryHandle(segment_id)), None);
|
||||||
}
|
}
|
||||||
if not_under_anchor(handle_end, bezier.end) {
|
if not_under_anchor(handle_end, bezier.end) {
|
||||||
overlay_context.line(handle_end, bezier.end, None);
|
overlay_context.line(handle_end, bezier.end, None);
|
||||||
overlay_context.manipulator_handle(handle_end, is_selected(selected, ManipulatorPointId::EndHandle(segment_id)));
|
overlay_context.manipulator_handle(handle_end, is_selected(selected, ManipulatorPointId::EndHandle(segment_id)), None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
|
||||||
|
|
@ -127,7 +127,7 @@ impl OverlayContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn manipulator_handle(&mut self, position: DVec2, selected: bool) {
|
pub fn manipulator_handle(&mut self, position: DVec2, selected: bool, color: Option<&str>) {
|
||||||
let position = position.round() - DVec2::splat(0.5);
|
let position = position.round() - DVec2::splat(0.5);
|
||||||
|
|
||||||
self.render_context.begin_path();
|
self.render_context.begin_path();
|
||||||
|
|
@ -137,7 +137,7 @@ impl OverlayContext {
|
||||||
|
|
||||||
let fill = if selected { COLOR_OVERLAY_BLUE } else { COLOR_OVERLAY_WHITE };
|
let fill = if selected { COLOR_OVERLAY_BLUE } else { COLOR_OVERLAY_WHITE };
|
||||||
self.render_context.set_fill_style_str(fill);
|
self.render_context.set_fill_style_str(fill);
|
||||||
self.render_context.set_stroke_style_str(COLOR_OVERLAY_BLUE);
|
self.render_context.set_stroke_style_str(color.unwrap_or(COLOR_OVERLAY_BLUE));
|
||||||
self.render_context.fill();
|
self.render_context.fill();
|
||||||
self.render_context.stroke();
|
self.render_context.stroke();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -116,6 +116,20 @@ impl ClosestSegment {
|
||||||
(stroke_width_sq + tolerance_sq) < dist_sq
|
(stroke_width_sq + tolerance_sq) < dist_sq
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn handle_positions(&self, document_metadata: &DocumentMetadata) -> (Option<DVec2>, Option<DVec2>) {
|
||||||
|
// Transform to viewport space
|
||||||
|
let transform = document_metadata.transform_to_viewport(self.layer);
|
||||||
|
|
||||||
|
// Split the Bezier at the parameter `t`
|
||||||
|
let [first, second] = self.bezier.split(TValue::Parametric(self.t));
|
||||||
|
|
||||||
|
// Transform the handle positions to viewport space
|
||||||
|
let first_handle = first.handle_end().map(|handle| transform.transform_point2(handle));
|
||||||
|
let second_handle = second.handle_start().map(|handle| transform.transform_point2(handle));
|
||||||
|
|
||||||
|
(first_handle, second_handle)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn adjusted_insert(&self, responses: &mut VecDeque<Message>) -> PointId {
|
pub fn adjusted_insert(&self, responses: &mut VecDeque<Message>) -> PointId {
|
||||||
let layer = self.layer;
|
let layer = self.layer;
|
||||||
let [first, second] = self.bezier.split(TValue::Parametric(self.t));
|
let [first, second] = self.bezier.split(TValue::Parametric(self.t));
|
||||||
|
|
|
||||||
|
|
@ -461,10 +461,10 @@ impl SnapManager {
|
||||||
overlay_context.line(viewport, target, None);
|
overlay_context.line(viewport, target, None);
|
||||||
}
|
}
|
||||||
for &target in align.iter().flatten() {
|
for &target in align.iter().flatten() {
|
||||||
overlay_context.manipulator_handle(target, false);
|
overlay_context.manipulator_handle(target, false, None);
|
||||||
}
|
}
|
||||||
if any_align {
|
if any_align {
|
||||||
overlay_context.manipulator_handle(viewport, false);
|
overlay_context.manipulator_handle(viewport, false, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
if !any_align && ind.distribution_equal_distance_x.is_none() && ind.distribution_equal_distance_y.is_none() {
|
if !any_align && ind.distribution_equal_distance_x.is_none() && ind.distribution_equal_distance_y.is_none() {
|
||||||
|
|
|
||||||
|
|
@ -257,15 +257,15 @@ impl Fsm for GradientToolFsmState {
|
||||||
let (start, end) = (transform.transform_point2(start), transform.transform_point2(end));
|
let (start, end) = (transform.transform_point2(start), transform.transform_point2(end));
|
||||||
|
|
||||||
overlay_context.line(start, end, None);
|
overlay_context.line(start, end, None);
|
||||||
overlay_context.manipulator_handle(start, dragging == Some(GradientDragTarget::Start));
|
overlay_context.manipulator_handle(start, dragging == Some(GradientDragTarget::Start), None);
|
||||||
overlay_context.manipulator_handle(end, dragging == Some(GradientDragTarget::End));
|
overlay_context.manipulator_handle(end, dragging == Some(GradientDragTarget::End), None);
|
||||||
|
|
||||||
for (index, (position, _)) in stops.0.into_iter().enumerate() {
|
for (index, (position, _)) in stops.0.into_iter().enumerate() {
|
||||||
if position.abs() < f64::EPSILON * 1000. || (1. - position).abs() < f64::EPSILON * 1000. {
|
if position.abs() < f64::EPSILON * 1000. || (1. - position).abs() < f64::EPSILON * 1000. {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
overlay_context.manipulator_handle(start.lerp(end, position), dragging == Some(GradientDragTarget::Step(index)));
|
overlay_context.manipulator_handle(start.lerp(end, position), dragging == Some(GradientDragTarget::Step(index)), None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use super::tool_prelude::*;
|
use super::tool_prelude::*;
|
||||||
use crate::consts::{COLOR_OVERLAY_YELLOW, DRAG_THRESHOLD, HANDLE_ROTATE_SNAP_ANGLE, INSERT_POINT_ON_SEGMENT_TOO_FAR_DISTANCE, SELECTION_THRESHOLD, SELECTION_TOLERANCE};
|
use crate::consts::{COLOR_OVERLAY_BLUE, DRAG_THRESHOLD, HANDLE_ROTATE_SNAP_ANGLE, INSERT_POINT_ON_SEGMENT_TOO_FAR_DISTANCE, SELECTION_THRESHOLD, SELECTION_TOLERANCE};
|
||||||
use crate::messages::portfolio::document::overlays::utility_functions::path_overlays;
|
use crate::messages::portfolio::document::overlays::utility_functions::path_overlays;
|
||||||
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
|
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
|
||||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||||
|
|
@ -520,6 +520,7 @@ impl PathToolData {
|
||||||
handle_angle
|
handle_angle
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn apply_snapping(
|
fn apply_snapping(
|
||||||
&mut self,
|
&mut self,
|
||||||
handle_direction: DVec2,
|
handle_direction: DVec2,
|
||||||
|
|
@ -549,6 +550,7 @@ impl PathToolData {
|
||||||
document.metadata().document_to_viewport.transform_vector2(snap_result.snapped_point_document - handle_position)
|
document.metadata().document_to_viewport.transform_vector2(snap_result.snapped_point_document - handle_position)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn drag(
|
fn drag(
|
||||||
&mut self,
|
&mut self,
|
||||||
equidistant: bool,
|
equidistant: bool,
|
||||||
|
|
@ -622,7 +624,13 @@ impl Fsm for PathToolFsmState {
|
||||||
let state = tool_data.update_insertion(shape_editor, document, responses, input);
|
let state = tool_data.update_insertion(shape_editor, document, responses, input);
|
||||||
|
|
||||||
if let Some(closest_segment) = &tool_data.segment {
|
if let Some(closest_segment) = &tool_data.segment {
|
||||||
overlay_context.manipulator_anchor(closest_segment.closest_point_to_viewport(), false, Some(COLOR_OVERLAY_YELLOW));
|
overlay_context.manipulator_anchor(closest_segment.closest_point_to_viewport(), false, Some(COLOR_OVERLAY_BLUE));
|
||||||
|
if let (Some(handle1), Some(handle2)) = closest_segment.handle_positions(document.metadata()) {
|
||||||
|
overlay_context.line(closest_segment.closest_point_to_viewport(), handle1, Some(COLOR_OVERLAY_BLUE));
|
||||||
|
overlay_context.line(closest_segment.closest_point_to_viewport(), handle2, Some(COLOR_OVERLAY_BLUE));
|
||||||
|
overlay_context.manipulator_handle(handle1, false, Some(COLOR_OVERLAY_BLUE));
|
||||||
|
overlay_context.manipulator_handle(handle2, false, Some(COLOR_OVERLAY_BLUE));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
responses.add(PathToolMessage::SelectedPointUpdated);
|
responses.add(PathToolMessage::SelectedPointUpdated);
|
||||||
|
|
|
||||||
|
|
@ -602,12 +602,12 @@ impl Fsm for PenToolFsmState {
|
||||||
|
|
||||||
if self == PenToolFsmState::DraggingHandle && valid(next_anchor, handle_end) {
|
if self == PenToolFsmState::DraggingHandle && valid(next_anchor, handle_end) {
|
||||||
// Draw the handle circle for the currently-being-dragged-out incoming handle (opposite the one currently being dragged out)
|
// Draw the handle circle for the currently-being-dragged-out incoming handle (opposite the one currently being dragged out)
|
||||||
overlay_context.manipulator_handle(handle_end, false);
|
overlay_context.manipulator_handle(handle_end, false, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
if valid(anchor_start, handle_start) {
|
if valid(anchor_start, handle_start) {
|
||||||
// Draw the handle circle for the most recently placed anchor's outgoing handle (which is currently influencing the currently-being-placed segment)
|
// Draw the handle circle for the most recently placed anchor's outgoing handle (which is currently influencing the currently-being-placed segment)
|
||||||
overlay_context.manipulator_handle(handle_start, false);
|
overlay_context.manipulator_handle(handle_start, false, None);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Draw the whole path and its manipulators when the user is clicking-and-dragging out from the most recently placed anchor to set its outgoing handle, during which it would otherwise not have its overlays drawn
|
// Draw the whole path and its manipulators when the user is clicking-and-dragging out from the most recently placed anchor to set its outgoing handle, during which it would otherwise not have its overlays drawn
|
||||||
|
|
@ -616,7 +616,7 @@ impl Fsm for PenToolFsmState {
|
||||||
|
|
||||||
if self == PenToolFsmState::DraggingHandle && valid(next_anchor, next_handle_start) {
|
if self == PenToolFsmState::DraggingHandle && valid(next_anchor, next_handle_start) {
|
||||||
// Draw the handle circle for the currently-being-dragged-out outgoing handle (the one currently being dragged out, under the user's cursor)
|
// Draw the handle circle for the currently-being-dragged-out outgoing handle (the one currently being dragged out, under the user's cursor)
|
||||||
overlay_context.manipulator_handle(next_handle_start, false);
|
overlay_context.manipulator_handle(next_handle_start, false, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self == PenToolFsmState::DraggingHandle {
|
if self == PenToolFsmState::DraggingHandle {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue