Fix freehand and spline tool

This commit is contained in:
0hypercube 2023-08-20 13:43:53 +01:00 committed by Keavon Chambers
parent 76d7b6256d
commit 6173662a40
15 changed files with 89 additions and 85 deletions

View File

@ -94,4 +94,5 @@ pub enum VectorDataModification {
SetManipulatorHandleMirroring { id: ManipulatorGroupId, mirror_angle: bool },
SetManipulatorPosition { point: ManipulatorPointId, position: DVec2 },
ToggleManipulatorHandleMirroring { id: ManipulatorGroupId },
UpdateSubpaths { subpaths: Vec<Subpath<ManipulatorGroupId>> },
}

View File

@ -378,6 +378,11 @@ impl<'a> ModifyInputsContext<'a> {
}
fn delete_layer(&mut self, id: NodeId) {
if !self.network.nodes.contains_key(&id) {
warn!("Deleting layer node that does not exist");
return;
}
let mut new_input = None;
let post_node = self.outwards_links.get(&id).and_then(|links| links.first().copied());
let mut delete_nodes = vec![id];

View File

@ -316,6 +316,7 @@ impl<'a> VectorModificationState<'a> {
VectorDataModification::SetManipulatorHandleMirroring { id, mirror_angle } => self.set_mirror(id, mirror_angle),
VectorDataModification::SetManipulatorPosition { point, position } => self.set_position(point, position),
VectorDataModification::ToggleManipulatorHandleMirroring { id } => self.toggle_mirror(id),
VectorDataModification::UpdateSubpaths { subpaths } => *self.subpaths = subpaths,
}
}
}

View File

@ -712,7 +712,7 @@ impl PortfolioMessageHandler {
}
pub fn poll_node_graph_evaluation(&mut self, responses: &mut VecDeque<Message>) {
let Some(active_document) = self.active_document_id.and_then(|id| self.documents.get_mut(&id)) else {
let Some(active_document) = self.active_document_id.and_then(|id| self.documents.get_mut(&id)) else {
warn!("Polling node graph with no document");
return;
};

View File

@ -28,7 +28,7 @@ pub fn new_custom_layer(network: NodeNetwork, layer_path: Vec<LayerId>, response
responses.add(DocumentMessage::InputFrameRasterizeRegionBelowLayer { layer_path });
}
pub fn set_manipulator_mirror_angle(manipulator_groups: &Vec<ManipulatorGroup<ManipulatorGroupId>>, layer_path: &[u64], mirror_angle: bool, responses: &mut VecDeque<Message>) {
pub fn set_manipulator_mirror_angle(manipulator_groups: &[ManipulatorGroup<ManipulatorGroupId>], layer_path: &[u64], mirror_angle: bool, responses: &mut VecDeque<Message>) {
for manipulator_group in manipulator_groups {
responses.add(GraphOperationMessage::Vector {
layer: layer_path.to_owned(),

View File

@ -153,7 +153,7 @@ impl ShapeState {
// Sets the selected points to all points for the corresponding intersection
pub fn select_all_anchors(&mut self, document: &Document, layer: LayerNodeIdentifier) {
let Some(subpaths) = get_subpaths(layer, document) else { return };
let Some(subpaths) = get_subpaths(layer, document) else { return };
let Some(state) = self.selected_shape_state.get_mut(&layer) else { return };
for manipulator in get_manipulator_groups(subpaths) {
state.select_point(ManipulatorPointId::new(manipulator.id, SelectedType::Anchor))
@ -375,7 +375,7 @@ impl ShapeState {
continue;
}
let Some(group) =get_manipulator_from_id(subpaths,point.group) else { continue };
let Some(group) = get_manipulator_from_id(subpaths, point.group) else { continue };
let mut move_point = |point: ManipulatorPointId| {
let Some(previous_position) = point.manipulator_type.get_position(group) else { return };
@ -430,7 +430,7 @@ impl ShapeState {
/// Delete selected and mirrored handles with zero length when the drag stops.
pub fn delete_selected_handles_with_zero_length(&self, document: &Document, opposing_handle_lengths: &Option<OpposingHandleLengths>, responses: &mut VecDeque<Message>) {
for (&layer, state) in &self.selected_shape_state {
let Some(subpaths) = get_subpaths(layer, document) else { continue };
let Some(subpaths) = get_subpaths(layer, document) else { continue };
let Some(mirror_angle) = get_mirror_handles(layer, document) else { continue };
let opposing_handle_lengths = opposing_handle_lengths.as_ref().and_then(|lengths| lengths.get(&layer));
@ -443,7 +443,7 @@ impl ShapeState {
continue;
}
let Some(group) = get_manipulator_from_id(subpaths,point.group) else { continue };
let Some(group) = get_manipulator_from_id(subpaths, point.group) else { continue };
let anchor_position = transform.transform_point2(group.anchor);
@ -521,7 +521,7 @@ impl ShapeState {
/// Reset the opposing handle lengths.
pub fn reset_opposing_handle_lengths(&self, document: &Document, opposing_handle_lengths: &OpposingHandleLengths, responses: &mut VecDeque<Message>) {
for (&layer, state) in &self.selected_shape_state {
let Some(subpaths) = get_subpaths(layer, document) else { continue };
let Some(subpaths) = get_subpaths(layer, document) else { continue };
let Some(mirror_angle) = get_mirror_handles(layer, document) else { continue };
let Some(opposing_handle_lengths) = opposing_handle_lengths.get(&layer) else { continue };

View File

@ -219,7 +219,7 @@ impl LayoutHolder for BrushTool {
impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for BrushTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, tool_data: &mut ToolActionHandlerData<'a>) {
let ToolMessage::Brush(BrushToolMessage::UpdateOptions(action)) = message else{
let ToolMessage::Brush(BrushToolMessage::UpdateOptions(action)) = message else {
self.fsm_state.process_event(message, &mut self.data, tool_data, &self.options, responses, true);
return;
};

View File

@ -112,7 +112,7 @@ impl LayoutHolder for EllipseTool {
impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for EllipseTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, tool_data: &mut ToolActionHandlerData<'a>) {
let ToolMessage::Ellipse(EllipseToolMessage::UpdateOptions(action)) = message else{
let ToolMessage::Ellipse(EllipseToolMessage::UpdateOptions(action)) = message else {
self.fsm_state.process_event(message, &mut self.data, tool_data, &self.options, responses, true);
return;
};

View File

@ -84,7 +84,7 @@ impl Fsm for EyedropperToolFsmState {
fn transition(self, event: ToolMessage, _tool_data: &mut Self::ToolData, tool_action_data: &mut ToolActionHandlerData, _tool_options: &(), responses: &mut VecDeque<Message>) -> Self {
let ToolActionHandlerData { global_tool_data, input, .. } = tool_action_data;
let ToolMessage::Eyedropper(event) = event else{
let ToolMessage::Eyedropper(event) = event else {
return self;
};
match (self, event) {

View File

@ -69,8 +69,8 @@ impl Fsm for FillToolFsmState {
return self;
};
let Some((layer_identifier, _)) = document.document_legacy.metadata.click(input.mouse.position) else {
return self;
};
return self;
};
let layer = layer_identifier.to_path();
let color = match event {

View File

@ -1,4 +1,5 @@
use super::tool_prelude::*;
use crate::messages::portfolio::document::node_graph::VectorDataModification;
use crate::messages::tool::common_functionality::color_selector::{ToolColorOptions, ToolColorType};
use crate::messages::tool::common_functionality::graph_modification_utils;
@ -6,6 +7,7 @@ use document_legacy::LayerId;
use graphene_core::vector::style::{Fill, Stroke};
use graphene_core::Color;
use bezier_rs::ManipulatorGroup;
use glam::DVec2;
use serde::{Deserialize, Serialize};
@ -117,7 +119,7 @@ impl LayoutHolder for FreehandTool {
impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for FreehandTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, tool_data: &mut ToolActionHandlerData<'a>) {
let ToolMessage::Freehand(FreehandToolMessage::UpdateOptions(action)) = message else{
let ToolMessage::Freehand(FreehandToolMessage::UpdateOptions(action)) = message else {
self.fsm_state.process_event(message, &mut self.data, tool_data, &self.options, responses, true);
return;
};
@ -174,9 +176,10 @@ impl ToolTransition for FreehandTool {
#[derive(Clone, Debug, Default)]
struct FreehandToolData {
points: Vec<DVec2>,
last_point: DVec2,
dragged: bool,
weight: f64,
path: Option<Vec<LayerId>>,
layer_path: Option<Vec<LayerId>>,
}
impl Fsm for FreehandToolFsmState {
@ -197,40 +200,42 @@ impl Fsm for FreehandToolFsmState {
(FreehandToolFsmState::Ready, FreehandToolMessage::DragStart) => {
responses.add(DocumentMessage::StartTransaction);
responses.add(DocumentMessage::DeselectAllLayers);
tool_data.path = Some(document.get_path_for_new_layer());
tool_data.layer_path = Some(document.get_path_for_new_layer());
let pos = transform.inverse().transform_point2(input.mouse.position);
tool_data.points.push(pos);
tool_data.dragged = false;
tool_data.last_point = pos;
tool_data.weight = tool_options.line_weight;
add_polyline(tool_data, tool_options.stroke.active_color(), tool_options.fill.active_color(), responses);
add_polyline([pos], tool_data, tool_options.stroke.active_color(), tool_options.fill.active_color(), responses);
FreehandToolFsmState::Drawing
}
(FreehandToolFsmState::Drawing, FreehandToolMessage::PointerMove) => {
let pos = transform.inverse().transform_point2(input.mouse.position);
if tool_data.points.last() != Some(&pos) {
tool_data.points.push(pos);
if tool_data.last_point != pos {
if let Some(layer) = tool_data.layer_path.clone() {
let manipulator_group = ManipulatorGroup::new_anchor(pos);
let modification = VectorDataModification::AddEndManipulatorGroup { subpath_index: 0, manipulator_group };
responses.add(GraphOperationMessage::Vector { layer, modification });
tool_data.dragged = true;
tool_data.last_point = pos;
}
}
add_polyline(tool_data, tool_options.stroke.active_color(), tool_options.fill.active_color(), responses);
FreehandToolFsmState::Drawing
}
(FreehandToolFsmState::Drawing, FreehandToolMessage::DragStop | FreehandToolMessage::Abort) => {
if tool_data.points.len() >= 2 {
responses.add(remove_preview(tool_data));
add_polyline(tool_data, tool_options.stroke.active_color(), tool_options.fill.active_color(), responses);
if tool_data.dragged {
responses.add(DocumentMessage::CommitTransaction);
} else {
responses.add(DocumentMessage::AbortTransaction);
}
tool_data.path = None;
tool_data.points.clear();
tool_data.layer_path = None;
FreehandToolFsmState::Ready
}
@ -259,14 +264,10 @@ impl Fsm for FreehandToolFsmState {
}
}
fn remove_preview(data: &FreehandToolData) -> Message {
GraphOperationMessage::DeleteLayer { id: data.path.clone().unwrap()[0] }.into()
}
fn add_polyline(anchors: impl IntoIterator<Item = DVec2>, data: &FreehandToolData, stroke_color: Option<Color>, fill_color: Option<Color>, responses: &mut VecDeque<Message>) {
let subpath = bezier_rs::Subpath::from_anchors(anchors, false);
fn add_polyline(data: &FreehandToolData, stroke_color: Option<Color>, fill_color: Option<Color>, responses: &mut VecDeque<Message>) {
let subpath = bezier_rs::Subpath::from_anchors(data.points.iter().copied(), false);
let layer_path = data.path.clone().unwrap();
let layer_path = data.layer_path.clone().unwrap();
graph_modification_utils::new_vector_layer(vec![subpath], layer_path.clone(), responses);
responses.add(GraphOperationMessage::FillSet {

View File

@ -112,7 +112,7 @@ impl Fsm for ImaginateToolFsmState {
) -> Self {
let shape_data = &mut tool_data.data;
let ToolMessage::Imaginate(event) = event else{
let ToolMessage::Imaginate(event) = event else {
return self;
};
match (self, event) {

View File

@ -104,7 +104,7 @@ impl Fsm for NavigateToolFsmState {
_tool_options: &Self::ToolOptions,
responses: &mut VecDeque<Message>,
) -> Self {
let ToolMessage::Navigate(navigate) = message else{
let ToolMessage::Navigate(navigate) = message else {
return self;
};

View File

@ -218,7 +218,9 @@ impl PenToolData {
self.subpath_index = subpath_index;
// Stop the handles on the first point from mirroring
let Some(subpaths) = get_subpaths (LayerNodeIdentifier::from_path(layer, document.network()), &document.document_legacy) else { return };
let Some(subpaths) = get_subpaths(LayerNodeIdentifier::from_path(layer, document.network()), &document.document_legacy) else {
return;
};
let manipulator_groups = subpaths[subpath_index].manipulator_groups();
let Some(last_handle) = (if from_start { manipulator_groups.first() } else { manipulator_groups.last() }) else {
return;

View File

@ -1,5 +1,6 @@
use super::tool_prelude::*;
use crate::consts::DRAG_THRESHOLD;
use crate::messages::portfolio::document::node_graph::VectorDataModification;
use crate::messages::tool::common_functionality::color_selector::{ToolColorOptions, ToolColorType};
use crate::messages::tool::common_functionality::graph_modification_utils;
use crate::messages::tool::common_functionality::snapping::SnapManager;
@ -192,22 +193,14 @@ impl Fsm for SplineToolFsmState {
type ToolData = SplineToolData;
type ToolOptions = SplineOptions;
fn transition(
self,
event: ToolMessage,
tool_data: &mut Self::ToolData,
ToolActionHandlerData {
fn transition(self, event: ToolMessage, tool_data: &mut Self::ToolData, tool_action_data: &mut ToolActionHandlerData, tool_options: &Self::ToolOptions, responses: &mut VecDeque<Message>) -> Self {
let ToolActionHandlerData {
document,
global_tool_data,
input,
render_data,
..
}: &mut ToolActionHandlerData,
tool_options: &Self::ToolOptions,
responses: &mut VecDeque<Message>,
) -> Self {
use SplineToolFsmState::*;
use SplineToolMessage::*;
} = tool_action_data;
let transform = document.document_legacy.metadata.document_to_viewport;
@ -215,11 +208,11 @@ impl Fsm for SplineToolFsmState {
return self;
};
match (self, event) {
(_, CanvasTransformed) => {
(_, SplineToolMessage::CanvasTransformed) => {
tool_data.snap_manager.start_snap(document, input, document.bounding_boxes(None, None, render_data), true, true);
self
}
(Ready, DragStart) => {
(SplineToolFsmState::Ready, SplineToolMessage::DragStart) => {
responses.add(DocumentMessage::StartTransaction);
responses.add(DocumentMessage::DeselectAllLayers);
tool_data.path = Some(document.get_path_for_new_layer());
@ -235,11 +228,11 @@ impl Fsm for SplineToolFsmState {
tool_data.weight = tool_options.line_weight;
add_spline(tool_data, true, tool_options.fill.active_color(), tool_options.stroke.active_color(), responses);
add_spline(tool_data, tool_options.fill.active_color(), tool_options.stroke.active_color(), responses);
Drawing
SplineToolFsmState::Drawing
}
(Drawing, DragStop) => {
(SplineToolFsmState::Drawing, SplineToolMessage::DragStop) => {
let snapped_position = tool_data.snap_manager.snap_position(responses, document, input.mouse.position);
let pos = transform.inverse().transform_point2(snapped_position);
@ -250,25 +243,22 @@ impl Fsm for SplineToolFsmState {
}
}
responses.add(remove_preview(tool_data));
add_spline(tool_data, true, tool_options.fill.active_color(), tool_options.stroke.active_color(), responses);
update_spline(tool_data, true, responses);
Drawing
SplineToolFsmState::Drawing
}
(Drawing, PointerMove) => {
(SplineToolFsmState::Drawing, SplineToolMessage::PointerMove) => {
let snapped_position = tool_data.snap_manager.snap_position(responses, document, input.mouse.position);
let pos = transform.inverse().transform_point2(snapped_position);
tool_data.next_point = pos;
responses.add(remove_preview(tool_data));
add_spline(tool_data, true, tool_options.fill.active_color(), tool_options.stroke.active_color(), responses);
update_spline(tool_data, true, responses);
Drawing
SplineToolFsmState::Drawing
}
(Drawing, Confirm) | (Drawing, Abort) => {
(SplineToolFsmState::Drawing, SplineToolMessage::Confirm | SplineToolMessage::Abort) => {
if tool_data.points.len() >= 2 {
responses.add(remove_preview(tool_data));
add_spline(tool_data, false, tool_options.fill.active_color(), tool_options.stroke.active_color(), responses);
update_spline(tool_data, false, responses);
responses.add(DocumentMessage::CommitTransaction);
} else {
responses.add(DocumentMessage::AbortTransaction);
@ -278,9 +268,9 @@ impl Fsm for SplineToolFsmState {
tool_data.points.clear();
tool_data.snap_manager.cleanup(responses);
Ready
SplineToolFsmState::Ready
}
(_, WorkingColorChanged) => {
(_, SplineToolMessage::WorkingColorChanged) => {
responses.add(SplineToolMessage::UpdateOptions(SplineOptionsUpdate::WorkingColors(
Some(global_tool_data.primary_color),
Some(global_tool_data.secondary_color),
@ -308,25 +298,11 @@ impl Fsm for SplineToolFsmState {
}
}
fn remove_preview(tool_data: &SplineToolData) -> Message {
Operation::DeleteLayer {
path: tool_data.path.clone().unwrap(),
}
.into()
}
fn add_spline(tool_data: &SplineToolData, show_preview: bool, fill_color: Option<Color>, stroke_color: Option<Color>, responses: &mut VecDeque<Message>) {
let mut points = tool_data.points.clone();
if show_preview {
points.push(tool_data.next_point)
}
let subpath = bezier_rs::Subpath::new_cubic_spline(points);
let layer_path = tool_data.path.clone().unwrap();
let manipulator_groups = subpath.manipulator_groups().to_vec();
graph_modification_utils::new_vector_layer(vec![subpath], layer_path.clone(), responses);
graph_modification_utils::set_manipulator_mirror_angle(&manipulator_groups, &layer_path, true, responses);
fn add_spline(tool_data: &SplineToolData, fill_color: Option<Color>, stroke_color: Option<Color>, responses: &mut VecDeque<Message>) {
let Some(layer_path) = tool_data.path.clone() else {
return;
};
graph_modification_utils::new_vector_layer(vec![], layer_path.clone(), responses);
responses.add(GraphOperationMessage::FillSet {
layer: layer_path.clone(),
@ -334,7 +310,25 @@ fn add_spline(tool_data: &SplineToolData, show_preview: bool, fill_color: Option
});
responses.add(GraphOperationMessage::StrokeSet {
layer: layer_path.clone(),
layer: layer_path,
stroke: Stroke::new(stroke_color, tool_data.weight),
});
}
fn update_spline(tool_data: &SplineToolData, show_preview: bool, responses: &mut VecDeque<Message>) {
let mut points = tool_data.points.clone();
if show_preview {
points.push(tool_data.next_point)
}
let subpath = bezier_rs::Subpath::new_cubic_spline(points);
let Some(layer) = tool_data.path.clone() else {
return;
};
graph_modification_utils::set_manipulator_mirror_angle(subpath.manipulator_groups(), &layer, true, responses);
let subpaths = vec![subpath];
let modification = VectorDataModification::UpdateSubpaths { subpaths };
responses.add(GraphOperationMessage::Vector { layer, modification });
}