Skip to content

Commit

Permalink
Merge branch 'master' into modify-import-export
Browse files Browse the repository at this point in the history
  • Loading branch information
Keavon authored Jan 15, 2025
2 parents 3594d79 + 5aedda0 commit c1fc86e
Show file tree
Hide file tree
Showing 12 changed files with 216 additions and 64 deletions.
2 changes: 2 additions & 0 deletions editor/src/messages/input_mapper/input_mappings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,8 @@ pub fn input_mappings() -> Mapping {
entry!(KeyDown(MouseRight); action_dispatch=PenToolMessage::Confirm),
entry!(KeyDown(Escape); action_dispatch=PenToolMessage::Confirm),
entry!(KeyDown(Enter); action_dispatch=PenToolMessage::Confirm),
entry!(KeyDown(Delete); action_dispatch=PenToolMessage::RemovePreviousHandle),
entry!(KeyDown(Backspace); action_dispatch=PenToolMessage::RemovePreviousHandle),
//
// FreehandToolMessage
entry!(PointerMove; action_dispatch=FreehandToolMessage::PointerMove),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
overlay_context.line(handle, bezier.start, 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 } => {
if not_under_anchor(handle_start, bezier.start) {
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) {
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);
}
}
_ => {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);

self.render_context.begin_path();
Expand All @@ -137,7 +137,7 @@ impl OverlayContext {

let fill = if selected { COLOR_OVERLAY_BLUE } else { COLOR_OVERLAY_WHITE };
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.stroke();
}
Expand Down
14 changes: 14 additions & 0 deletions editor/src/messages/tool/common_functionality/shape_editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,20 @@ impl ClosestSegment {
(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 {
let layer = self.layer;
let [first, second] = self.bezier.split(TValue::Parametric(self.t));
Expand Down
4 changes: 2 additions & 2 deletions editor/src/messages/tool/common_functionality/snapping.rs
Original file line number Diff line number Diff line change
Expand Up @@ -461,10 +461,10 @@ impl SnapManager {
overlay_context.line(viewport, target, None);
}
for &target in align.iter().flatten() {
overlay_context.manipulator_handle(target, false);
overlay_context.manipulator_handle(target, false, None);
}
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() {
Expand Down
13 changes: 9 additions & 4 deletions editor/src/messages/tool/tool_message_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ impl MessageHandler<ToolMessage, ToolMessageData<'_>> for ToolMessageHandler {
self.tool_is_active = true;

// Send the old and new tools a transition to their FSM Abort states
let mut send_abort_to_tool = |tool_type, update_hints_and_cursor: bool| {
if let Some(tool) = tool_data.tools.get_mut(&tool_type) {
let mut send_abort_to_tool = |old_tool: ToolType, new_tool: ToolType, update_hints_and_cursor: bool| {
if let Some(tool) = tool_data.tools.get_mut(&new_tool) {
let mut data = ToolActionHandlerData {
document,
document_id,
Expand All @@ -101,9 +101,14 @@ impl MessageHandler<ToolMessage, ToolMessageData<'_>> for ToolMessageHandler {
tool.process_message(ToolMessage::UpdateCursor, responses, &mut data);
}
}

if matches!(old_tool, ToolType::Path | ToolType::Select) {
responses.add(TransformLayerMessage::CancelTransformOperation);
}
};
send_abort_to_tool(tool_type, true);
send_abort_to_tool(old_tool, false);

send_abort_to_tool(old_tool, tool_type, true);
send_abort_to_tool(old_tool, old_tool, false);

// Unsubscribe old tool from the broadcaster
tool_data.tools.get(&tool_type).unwrap().deactivate(responses);
Expand Down
6 changes: 3 additions & 3 deletions editor/src/messages/tool/tool_messages/gradient_tool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,15 +257,15 @@ impl Fsm for GradientToolFsmState {
let (start, end) = (transform.transform_point2(start), transform.transform_point2(end));

overlay_context.line(start, end, None);
overlay_context.manipulator_handle(start, dragging == Some(GradientDragTarget::Start));
overlay_context.manipulator_handle(end, dragging == Some(GradientDragTarget::End));
overlay_context.manipulator_handle(start, dragging == Some(GradientDragTarget::Start), None);
overlay_context.manipulator_handle(end, dragging == Some(GradientDragTarget::End), None);

for (index, (position, _)) in stops.0.into_iter().enumerate() {
if position.abs() < f64::EPSILON * 1000. || (1. - position).abs() < f64::EPSILON * 1000. {
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);
}
}

Expand Down
26 changes: 11 additions & 15 deletions editor/src/messages/tool/tool_messages/path_tool.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
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_types::OverlayContext;
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
Expand Down Expand Up @@ -520,6 +520,7 @@ impl PathToolData {
handle_angle
}

#[allow(clippy::too_many_arguments)]
fn apply_snapping(
&mut self,
handle_direction: DVec2,
Expand Down Expand Up @@ -549,6 +550,7 @@ impl PathToolData {
document.metadata().document_to_viewport.transform_vector2(snap_result.snapped_point_document - handle_position)
}

#[allow(clippy::too_many_arguments)]
fn drag(
&mut self,
equidistant: bool,
Expand Down Expand Up @@ -622,7 +624,13 @@ impl Fsm for PathToolFsmState {
let state = tool_data.update_insertion(shape_editor, document, responses, input);

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);
Expand All @@ -648,19 +656,7 @@ impl Fsm for PathToolFsmState {
self
}
(Self::InsertPoint, PathToolMessage::Escape | PathToolMessage::Delete | PathToolMessage::RightClick) => tool_data.end_insertion(shape_editor, responses, InsertEndKind::Abort),
(Self::InsertPoint, PathToolMessage::GRS { key: propagate }) => {
// MAYBE: use `InputMapperMessage::KeyDown(..)` instead
match propagate {
// TODO: Don't use `Key::G` directly, instead take it as a variable from the input mappings list like in all other places
Key::KeyG => responses.add(TransformLayerMessage::BeginGrab),
// TODO: Don't use `Key::R` directly, instead take it as a variable from the input mappings list like in all other places
Key::KeyR => responses.add(TransformLayerMessage::BeginRotate),
// TODO: Don't use `Key::S` directly, instead take it as a variable from the input mappings list like in all other places
Key::KeyS => responses.add(TransformLayerMessage::BeginScale),
_ => warn!("Unexpected GRS key"),
}
tool_data.end_insertion(shape_editor, responses, InsertEndKind::Abort)
}
(Self::InsertPoint, PathToolMessage::GRS { key: _ }) => PathToolFsmState::InsertPoint,
// Mouse down
(
_,
Expand Down
17 changes: 14 additions & 3 deletions editor/src/messages/tool/tool_messages/pen_tool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ pub enum PenToolMessage {
Undo,
UpdateOptions(PenOptionsUpdate),
RecalculateLatestPointsPosition,
RemovePreviousHandle,
}

#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
Expand Down Expand Up @@ -175,6 +176,7 @@ impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for PenTool
PointerMove,
Confirm,
Abort,
RemovePreviousHandle,
),
}
}
Expand Down Expand Up @@ -600,12 +602,12 @@ impl Fsm for PenToolFsmState {

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)
overlay_context.manipulator_handle(handle_end, false);
overlay_context.manipulator_handle(handle_end, false, None);
}

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)
overlay_context.manipulator_handle(handle_start, false);
overlay_context.manipulator_handle(handle_start, false, None);
}
} 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
Expand All @@ -614,7 +616,7 @@ impl Fsm for PenToolFsmState {

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)
overlay_context.manipulator_handle(next_handle_start, false);
overlay_context.manipulator_handle(next_handle_start, false, None);
}

if self == PenToolFsmState::DraggingHandle {
Expand Down Expand Up @@ -685,6 +687,15 @@ impl Fsm for PenToolFsmState {
PenToolFsmState::PlacingAnchor
}
}
(PenToolFsmState::PlacingAnchor, PenToolMessage::RemovePreviousHandle) => {
if let Some(last_point) = tool_data.latest_points.last_mut() {
last_point.handle_start = last_point.pos;
responses.add(OverlaysMessage::Draw);
} else {
log::warn!("No latest point available to modify handle_start.");
}
self
}
(PenToolFsmState::DraggingHandle, PenToolMessage::DragStop) => tool_data
.finish_placing_handle(SnapData::new(document, input), transform, responses)
.unwrap_or(PenToolFsmState::PlacingAnchor),
Expand Down
78 changes: 60 additions & 18 deletions editor/src/messages/tool/tool_messages/spline_tool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ use crate::messages::tool::common_functionality::color_selector::{ToolColorOptio
use crate::messages::tool::common_functionality::graph_modification_utils;
use crate::messages::tool::common_functionality::snapping::SnapManager;

use graph_craft::document::{value::TaggedValue, NodeId, NodeInput};
use graph_craft::document::{NodeId, NodeInput};
use graphene_core::Color;
use graphene_std::vector::{PointId, SegmentId, VectorModificationType};

#[derive(Default)]
pub struct SplineTool {
Expand Down Expand Up @@ -177,8 +178,14 @@ impl ToolTransition for SplineTool {

#[derive(Clone, Debug, Default)]
struct SplineToolData {
points: Vec<DVec2>,
/// Points that are inserted.
points: Vec<(PointId, DVec2)>,
/// Point to be inserted.
next_point: DVec2,
/// Point that was inserted temporarily to show preview.
preview_point: Option<PointId>,
/// Segment that was inserted temporarily to show preview.
preview_segment: Option<SegmentId>,
weight: f64,
layer: Option<LayerNodeIdentifier>,
snap_manager: SnapManager,
Expand All @@ -205,9 +212,11 @@ impl Fsm for SplineToolFsmState {

tool_data.weight = tool_options.line_weight;

let node_type = resolve_document_node_type("Spline").expect("Spline node does not exist");
let node = node_type.node_template_input_override([None, Some(NodeInput::value(TaggedValue::VecDVec2(Vec::new()), false))]);
let nodes = vec![(NodeId(0), node)];
let path_node_type = resolve_document_node_type("Path").expect("Path node does not exist");
let path_node = path_node_type.default_node_template();
let spline_node_type = resolve_document_node_type("Splines from Points").expect("Spline from Points node does not exist");
let spline_node = spline_node_type.node_template_input_override([Some(NodeInput::node(NodeId(1), 0))]);
let nodes = vec![(NodeId(1), path_node), (NodeId(0), spline_node)];

let layer = graph_modification_utils::new_custom(NodeId::new(), nodes, parent, responses);
tool_options.fill.apply_fill(layer, responses);
Expand All @@ -228,12 +237,11 @@ impl Fsm for SplineToolFsmState {
let transform = document.metadata().transform_to_viewport(layer);
let pos = transform.inverse().transform_point2(snapped_position);

if tool_data.points.last().map_or(true, |last_pos| last_pos.distance(pos) > DRAG_THRESHOLD) {
tool_data.points.push(pos);
if tool_data.points.last().map_or(true, |last_pos| last_pos.1.distance(pos) > DRAG_THRESHOLD) {
tool_data.next_point = pos;
}

update_spline(document, tool_data, true, responses);
update_spline(tool_data, false, responses);

SplineToolFsmState::Drawing
}
Expand All @@ -246,7 +254,7 @@ impl Fsm for SplineToolFsmState {
let pos = transform.inverse().transform_point2(snapped_position);
tool_data.next_point = pos;

update_spline(document, tool_data, true, responses);
update_spline(tool_data, true, responses);

// Auto-panning
let messages = [SplineToolMessage::PointerOutsideViewport.into(), SplineToolMessage::PointerMove.into()];
Expand All @@ -269,13 +277,15 @@ impl Fsm for SplineToolFsmState {
}
(SplineToolFsmState::Drawing, SplineToolMessage::Confirm | SplineToolMessage::Abort) => {
if tool_data.points.len() >= 2 {
update_spline(document, tool_data, false, responses);
delete_preview(tool_data, responses);
responses.add(DocumentMessage::EndTransaction);
} else {
responses.add(DocumentMessage::AbortTransaction);
}

tool_data.layer = None;
tool_data.preview_point = None;
tool_data.preview_segment = None;
tool_data.points.clear();
tool_data.snap_manager.cleanup(responses);

Expand Down Expand Up @@ -310,17 +320,49 @@ impl Fsm for SplineToolFsmState {
}
}

fn update_spline(document: &DocumentMessageHandler, tool_data: &SplineToolData, show_preview: bool, responses: &mut VecDeque<Message>) {
let mut points = tool_data.points.clone();
fn update_spline(tool_data: &mut SplineToolData, show_preview: bool, responses: &mut VecDeque<Message>) {
delete_preview(tool_data, responses);

let Some(layer) = tool_data.layer else { return };

let next_point_pos = tool_data.next_point;
let next_point_id = PointId::generate();
let modification_type = VectorModificationType::InsertPoint {
id: next_point_id,
position: next_point_pos,
};
responses.add(GraphOperationMessage::Vector { layer, modification_type });

if let Some((last_point_id, _)) = tool_data.points.last() {
let points = [*last_point_id, next_point_id];
let id = SegmentId::generate();
let modification_type = VectorModificationType::InsertSegment { id, points, handles: [None, None] };
responses.add(GraphOperationMessage::Vector { layer, modification_type });

if show_preview {
tool_data.preview_segment = Some(id);
}
}

if show_preview {
points.push(tool_data.next_point)
tool_data.preview_point = Some(next_point_id);
} else {
tool_data.points.push((next_point_id, next_point_pos));
}
let value = TaggedValue::VecDVec2(points);
}

fn delete_preview(tool_data: &mut SplineToolData, responses: &mut VecDeque<Message>) {
let Some(layer) = tool_data.layer else { return };

let Some(node_id) = graph_modification_utils::NodeGraphLayer::new(layer, &document.network_interface).upstream_node_id_from_name("Spline") else {
return;
};
responses.add_front(NodeGraphMessage::SetInputValue { node_id, input_index: 1, value });
if let Some(id) = tool_data.preview_point {
let modification_type = VectorModificationType::RemovePoint { id };
responses.add(GraphOperationMessage::Vector { layer, modification_type });
}
if let Some(id) = tool_data.preview_segment {
let modification_type = VectorModificationType::RemoveSegment { id };
responses.add(GraphOperationMessage::Vector { layer, modification_type });
}

tool_data.preview_point = None;
tool_data.preview_segment = None;
}
Loading

0 comments on commit c1fc86e

Please sign in to comment.