Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 102 additions & 0 deletions editor/src/messages/tool/common_functionality/shapes/arrow_shape.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
use super::shape_utility::ShapeToolModifierKey;
use super::*;
use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type;
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::network_interface::NodeTemplate;
use crate::messages::prelude::*;
use glam::DVec2;
use graphene_std::vector::{PointId, SegmentId, VectorModificationType};
use std::collections::VecDeque;

#[derive(Default)]
pub struct Arrow;

impl Arrow {
pub fn create_node() -> NodeTemplate {
let node_type = resolve_document_node_type("Path").expect("Path node does not exist");
node_type.default_node_template()
}

pub fn update_shape(
document: &DocumentMessageHandler,
input: &InputPreprocessorMessageHandler,
layer: LayerNodeIdentifier,
tool_data: &mut ShapeToolData,
modifier: ShapeToolModifierKey,
responses: &mut VecDeque<Message>,
) {
let [center, lock_ratio, _] = modifier;

// Work in viewport space like Line does
let start_viewport = tool_data.data.viewport_drag_start(document);
let end_viewport = input.mouse.position;

let delta = end_viewport - start_viewport;
let length = delta.length();
if length < 1e-6 {
return;
}

let direction = delta.normalize();
let perpendicular = DVec2::new(-direction.y, direction.x);

let shaft_thickness = length * 0.05;
let head_width = length * 0.15;
let head_length = length * 0.2;

// Build arrow in viewport space
let viewport_anchors = vec![
start_viewport,
start_viewport + direction * head_length - perpendicular * (head_width * 0.5),
start_viewport + direction * head_length - perpendicular * (shaft_thickness * 0.5),
end_viewport - perpendicular * (shaft_thickness * 0.5),
end_viewport + perpendicular * (shaft_thickness * 0.5),
start_viewport + direction * head_length + perpendicular * (shaft_thickness * 0.5),
start_viewport + direction * head_length + perpendicular * (head_width * 0.5),
];

let vector = document.network_interface.compute_modified_vector(layer);
let existing_point_ids: Vec<PointId> = vector.as_ref().map(|v| v.point_domain.ids().to_vec()).unwrap_or_default();
let existing_segment_ids: Vec<SegmentId> = vector.as_ref().map(|v| v.segment_domain.ids().to_vec()).unwrap_or_default();

for point_id in existing_point_ids {
responses.add(GraphOperationMessage::Vector {
layer,
modification_type: VectorModificationType::RemovePoint { id: point_id },
});
}

for segment_id in existing_segment_ids {
responses.add(GraphOperationMessage::Vector {
layer,
modification_type: VectorModificationType::RemoveSegment { id: segment_id },
});
}

let point_ids: Vec<PointId> = viewport_anchors
.iter()
.map(|&pos| {
let id = PointId::generate();
responses.add(GraphOperationMessage::Vector {
layer,
modification_type: VectorModificationType::InsertPoint { id, position: pos },
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that this inserts the point in layer space. You said above that you Build arrow in viewport space.

To convert between the viewport and the layer space, you can do something like:

document.metadata().transform_to_viewport(layer).inverse().transform_point2(pos)

Alternatively you can set the transform on the layer itself:

responses.add(GraphOperationMessage::TransformSet {
	layer,
	transform: DAffine2::IDENTITY,
	transform_in: TransformIn::Viewport,
	skip_rerender: false,
});

Note that the line tool is broken and produces offset lines when inside a transformed parent layer. I would recommend that you avoid implementing this bug into you new tool.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the help, i have modified it accordingly.

});
id
})
.collect();

for i in 0..point_ids.len() {
let id = SegmentId::generate();
let points = [point_ids[i], point_ids[(i + 1) % point_ids.len()]];
responses.add(GraphOperationMessage::Vector {
layer,
modification_type: VectorModificationType::InsertSegment { id, points, handles: [None, None] },
});
}

responses.add(NodeGraphMessage::RunDocumentGraph);
}

pub fn overlays(_document: &DocumentMessageHandler, _tool_data: &ShapeToolData, _overlay_context: &mut OverlayContext) {}
}
2 changes: 2 additions & 0 deletions editor/src/messages/tool/common_functionality/shapes/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod arc_shape;
pub mod arrow_shape;
pub mod circle_shape;
pub mod ellipse_shape;
pub mod grid_shape;
Expand All @@ -9,6 +10,7 @@ pub mod shape_utility;
pub mod spiral_shape;
pub mod star_shape;

pub use super::shapes::arrow_shape::Arrow;
pub use super::shapes::ellipse_shape::Ellipse;
pub use super::shapes::line_shape::{Line, LineEnd};
pub use super::shapes::rectangle_shape::Rectangle;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ pub enum ShapeType {
Grid,
Rectangle,
Ellipse,
Arrow,
Line,
}

Expand All @@ -47,6 +48,7 @@ impl ShapeType {
Self::Spiral => "Spiral",
Self::Rectangle => "Rectangle",
Self::Ellipse => "Ellipse",
Self::Arrow => "Arrow",
Self::Line => "Line",
})
.into()
Expand All @@ -57,6 +59,7 @@ impl ShapeType {
Self::Line => "Line Tool",
Self::Rectangle => "Rectangle Tool",
Self::Ellipse => "Ellipse Tool",
Self::Arrow => "Arrow Tool",
_ => "",
})
.into()
Expand All @@ -67,6 +70,7 @@ impl ShapeType {
Self::Line => "VectorLineTool",
Self::Rectangle => "VectorRectangleTool",
Self::Ellipse => "VectorEllipseTool",
Self::Arrow => "VectorArrowTool",
_ => "",
})
.into()
Expand All @@ -77,6 +81,7 @@ impl ShapeType {
Self::Line => ToolType::Line,
Self::Rectangle => ToolType::Rectangle,
Self::Ellipse => ToolType::Ellipse,
Self::Arrow => ToolType::Shape,
_ => ToolType::Shape,
}
}
Expand Down
33 changes: 31 additions & 2 deletions editor/src/messages/tool/tool_messages/shape_tool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use crate::messages::tool::common_functionality::gizmos::gizmo_manager::GizmoMan
use crate::messages::tool::common_functionality::graph_modification_utils;
use crate::messages::tool::common_functionality::resize::Resize;
use crate::messages::tool::common_functionality::shapes::arc_shape::Arc;
use crate::messages::tool::common_functionality::shapes::arrow_shape::Arrow;
use crate::messages::tool::common_functionality::shapes::circle_shape::Circle;
use crate::messages::tool::common_functionality::shapes::grid_shape::Grid;
use crate::messages::tool::common_functionality::shapes::line_shape::{LineToolData, clicked_on_line_endpoints};
Expand Down Expand Up @@ -168,6 +169,30 @@ fn create_shape_option_widget(shape_type: ShapeType) -> WidgetHolder {
}
.into()
}),
MenuListEntry::new("Rectangle").label("Rectangle").on_commit(move |_| {
ShapeToolMessage::UpdateOptions {
options: ShapeOptionsUpdate::ShapeType(ShapeType::Rectangle),
}
.into()
}),
MenuListEntry::new("Ellipse").label("Ellipse").on_commit(move |_| {
ShapeToolMessage::UpdateOptions {
options: ShapeOptionsUpdate::ShapeType(ShapeType::Ellipse),
}
.into()
}),
MenuListEntry::new("Arrow").label("Arrow").on_commit(move |_| {
ShapeToolMessage::UpdateOptions {
options: ShapeOptionsUpdate::ShapeType(ShapeType::Arrow),
}
.into()
}),
MenuListEntry::new("Line").label("Line").on_commit(move |_| {
ShapeToolMessage::UpdateOptions {
options: ShapeOptionsUpdate::ShapeType(ShapeType::Line),
}
.into()
}),
]];
DropdownInput::new(entries).selected_index(Some(shape_type as u32)).widget_holder()
}
Expand Down Expand Up @@ -805,7 +830,7 @@ impl Fsm for ShapeToolFsmState {
};

match tool_data.current_shape {
ShapeType::Polygon | ShapeType::Star | ShapeType::Circle | ShapeType::Arc | ShapeType::Spiral | ShapeType::Grid | ShapeType::Rectangle | ShapeType::Ellipse => {
ShapeType::Polygon | ShapeType::Star | ShapeType::Circle | ShapeType::Arc | ShapeType::Spiral | ShapeType::Grid | ShapeType::Rectangle | ShapeType::Ellipse | ShapeType::Arrow => {
tool_data.data.start(document, input)
}
ShapeType::Line => {
Expand All @@ -822,6 +847,7 @@ impl Fsm for ShapeToolFsmState {
ShapeType::Star => Star::create_node(tool_options.vertices),
ShapeType::Circle => Circle::create_node(),
ShapeType::Arc => Arc::create_node(tool_options.arc_type),
ShapeType::Arrow => Arrow::create_node(),
ShapeType::Spiral => Spiral::create_node(tool_options.spiral_type, tool_options.turns),
ShapeType::Grid => Grid::create_node(tool_options.grid_type),
ShapeType::Rectangle => Rectangle::create_node(),
Expand All @@ -835,7 +861,7 @@ impl Fsm for ShapeToolFsmState {
let defered_responses = &mut VecDeque::new();

match tool_data.current_shape {
ShapeType::Polygon | ShapeType::Star | ShapeType::Circle | ShapeType::Arc | ShapeType::Spiral | ShapeType::Grid | ShapeType::Rectangle | ShapeType::Ellipse => {
ShapeType::Arrow | ShapeType::Polygon | ShapeType::Star | ShapeType::Circle | ShapeType::Arc | ShapeType::Spiral | ShapeType::Grid | ShapeType::Rectangle | ShapeType::Ellipse => {
defered_responses.add(GraphOperationMessage::TransformSet {
layer,
transform: DAffine2::from_scale_angle_translation(DVec2::ONE, 0., input.mouse.position),
Expand Down Expand Up @@ -872,6 +898,7 @@ impl Fsm for ShapeToolFsmState {
ShapeType::Star => Star::update_shape(document, input, layer, tool_data, modifier, responses),
ShapeType::Circle => Circle::update_shape(document, input, layer, tool_data, modifier, responses),
ShapeType::Arc => Arc::update_shape(document, input, layer, tool_data, modifier, responses),
ShapeType::Arrow => Arrow::update_shape(document, input, layer, tool_data, modifier, responses),
ShapeType::Spiral => Spiral::update_shape(document, input, layer, tool_data, responses),
ShapeType::Grid => Grid::update_shape(document, input, layer, tool_options.grid_type, tool_data, modifier, responses),
ShapeType::Rectangle => Rectangle::update_shape(document, input, layer, tool_data, modifier, responses),
Expand Down Expand Up @@ -1127,6 +1154,7 @@ fn update_dynamic_hints(state: &ShapeToolFsmState, responses: &mut VecDeque<Mess
HintInfo::keys([Key::Shift], "Constrain Regular").prepend_plus(),
HintInfo::keys([Key::Alt], "From Center").prepend_plus(),
])],
ShapeType::Arrow => vec![HintGroup(vec![HintInfo::mouse(MouseMotion::LmbDrag, "Draw Arrow")])],
};
HintData(hint_groups)
}
Expand All @@ -1142,6 +1170,7 @@ fn update_dynamic_hints(state: &ShapeToolFsmState, responses: &mut VecDeque<Mess
HintInfo::keys([Key::Alt], "From Center"),
HintInfo::keys([Key::Control], "Lock Angle"),
]),
ShapeType::Arrow => HintGroup(vec![HintInfo::keys([Key::Shift], "Constrain Angle")]),
ShapeType::Circle => HintGroup(vec![HintInfo::keys([Key::Alt], "From Center")]),
ShapeType::Spiral => HintGroup(vec![]),
};
Expand Down
Loading