Skip to content

Commit 989f4ba

Browse files
committed
add arrow shape feature in editor
Signed-off-by: krVatsal <[email protected]>
1 parent 52e98ea commit 989f4ba

File tree

4 files changed

+140
-2
lines changed

4 files changed

+140
-2
lines changed
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
use super::shape_utility::ShapeToolModifierKey;
2+
use super::*;
3+
use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type;
4+
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
5+
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
6+
use crate::messages::portfolio::document::utility_types::network_interface::NodeTemplate;
7+
use crate::messages::prelude::*;
8+
use glam::DVec2;
9+
use graphene_std::vector::{PointId, SegmentId, VectorModificationType};
10+
use std::collections::VecDeque;
11+
12+
#[derive(Default)]
13+
pub struct Arrow;
14+
15+
impl Arrow {
16+
pub fn create_node() -> NodeTemplate {
17+
let node_type = resolve_document_node_type("Path").expect("Path node does not exist");
18+
node_type.default_node_template()
19+
}
20+
21+
pub fn update_shape(
22+
document: &DocumentMessageHandler,
23+
input: &InputPreprocessorMessageHandler,
24+
layer: LayerNodeIdentifier,
25+
tool_data: &mut ShapeToolData,
26+
modifier: ShapeToolModifierKey,
27+
responses: &mut VecDeque<Message>,
28+
) {
29+
let [center, lock_ratio, _] = modifier;
30+
31+
// Work in viewport space like Line does
32+
let start_viewport = tool_data.data.viewport_drag_start(document);
33+
let end_viewport = input.mouse.position;
34+
35+
let delta = end_viewport - start_viewport;
36+
let length = delta.length();
37+
if length < 1e-6 {
38+
return;
39+
}
40+
41+
let direction = delta.normalize();
42+
let perpendicular = DVec2::new(-direction.y, direction.x);
43+
44+
let shaft_thickness = length * 0.05;
45+
let head_width = length * 0.15;
46+
let head_length = length * 0.2;
47+
48+
// Build arrow in viewport space
49+
let viewport_anchors = vec![
50+
start_viewport,
51+
start_viewport + direction * head_length - perpendicular * (head_width * 0.5),
52+
start_viewport + direction * head_length - perpendicular * (shaft_thickness * 0.5),
53+
end_viewport - perpendicular * (shaft_thickness * 0.5),
54+
end_viewport + perpendicular * (shaft_thickness * 0.5),
55+
start_viewport + direction * head_length + perpendicular * (shaft_thickness * 0.5),
56+
start_viewport + direction * head_length + perpendicular * (head_width * 0.5),
57+
];
58+
59+
let vector = document.network_interface.compute_modified_vector(layer);
60+
let existing_point_ids: Vec<PointId> = vector.as_ref().map(|v| v.point_domain.ids().to_vec()).unwrap_or_default();
61+
let existing_segment_ids: Vec<SegmentId> = vector.as_ref().map(|v| v.segment_domain.ids().to_vec()).unwrap_or_default();
62+
63+
for point_id in existing_point_ids {
64+
responses.add(GraphOperationMessage::Vector {
65+
layer,
66+
modification_type: VectorModificationType::RemovePoint { id: point_id },
67+
});
68+
}
69+
70+
for segment_id in existing_segment_ids {
71+
responses.add(GraphOperationMessage::Vector {
72+
layer,
73+
modification_type: VectorModificationType::RemoveSegment { id: segment_id },
74+
});
75+
}
76+
77+
let point_ids: Vec<PointId> = viewport_anchors
78+
.iter()
79+
.map(|&pos| {
80+
let id = PointId::generate();
81+
responses.add(GraphOperationMessage::Vector {
82+
layer,
83+
modification_type: VectorModificationType::InsertPoint { id, position: pos },
84+
});
85+
id
86+
})
87+
.collect();
88+
89+
for i in 0..point_ids.len() {
90+
let id = SegmentId::generate();
91+
let points = [point_ids[i], point_ids[(i + 1) % point_ids.len()]];
92+
responses.add(GraphOperationMessage::Vector {
93+
layer,
94+
modification_type: VectorModificationType::InsertSegment { id, points, handles: [None, None] },
95+
});
96+
}
97+
98+
responses.add(NodeGraphMessage::RunDocumentGraph);
99+
}
100+
101+
pub fn overlays(_document: &DocumentMessageHandler, _tool_data: &ShapeToolData, _overlay_context: &mut OverlayContext) {}
102+
}

editor/src/messages/tool/common_functionality/shapes/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
pub mod arc_shape;
2+
pub mod arrow_shape;
23
pub mod circle_shape;
34
pub mod ellipse_shape;
45
pub mod grid_shape;
@@ -9,6 +10,7 @@ pub mod shape_utility;
910
pub mod spiral_shape;
1011
pub mod star_shape;
1112

13+
pub use super::shapes::arrow_shape::Arrow;
1214
pub use super::shapes::ellipse_shape::Ellipse;
1315
pub use super::shapes::line_shape::{Line, LineEnd};
1416
pub use super::shapes::rectangle_shape::Rectangle;

editor/src/messages/tool/common_functionality/shapes/shape_utility.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ pub enum ShapeType {
3333
Grid,
3434
Rectangle,
3535
Ellipse,
36+
Arrow,
3637
Line,
3738
}
3839

@@ -47,6 +48,7 @@ impl ShapeType {
4748
Self::Spiral => "Spiral",
4849
Self::Rectangle => "Rectangle",
4950
Self::Ellipse => "Ellipse",
51+
Self::Arrow => "Arrow",
5052
Self::Line => "Line",
5153
})
5254
.into()
@@ -57,6 +59,7 @@ impl ShapeType {
5759
Self::Line => "Line Tool",
5860
Self::Rectangle => "Rectangle Tool",
5961
Self::Ellipse => "Ellipse Tool",
62+
Self::Arrow => "Arrow Tool",
6063
_ => "",
6164
})
6265
.into()
@@ -67,6 +70,7 @@ impl ShapeType {
6770
Self::Line => "VectorLineTool",
6871
Self::Rectangle => "VectorRectangleTool",
6972
Self::Ellipse => "VectorEllipseTool",
73+
Self::Arrow => "VectorArrowTool",
7074
_ => "",
7175
})
7276
.into()
@@ -77,6 +81,7 @@ impl ShapeType {
7781
Self::Line => ToolType::Line,
7882
Self::Rectangle => ToolType::Rectangle,
7983
Self::Ellipse => ToolType::Ellipse,
84+
Self::Arrow => ToolType::Shape,
8085
_ => ToolType::Shape,
8186
}
8287
}

editor/src/messages/tool/tool_messages/shape_tool.rs

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use crate::messages::tool::common_functionality::gizmos::gizmo_manager::GizmoMan
99
use crate::messages::tool::common_functionality::graph_modification_utils;
1010
use crate::messages::tool::common_functionality::resize::Resize;
1111
use crate::messages::tool::common_functionality::shapes::arc_shape::Arc;
12+
use crate::messages::tool::common_functionality::shapes::arrow_shape::Arrow;
1213
use crate::messages::tool::common_functionality::shapes::circle_shape::Circle;
1314
use crate::messages::tool::common_functionality::shapes::grid_shape::Grid;
1415
use crate::messages::tool::common_functionality::shapes::line_shape::{LineToolData, clicked_on_line_endpoints};
@@ -168,6 +169,30 @@ fn create_shape_option_widget(shape_type: ShapeType) -> WidgetHolder {
168169
}
169170
.into()
170171
}),
172+
MenuListEntry::new("Rectangle").label("Rectangle").on_commit(move |_| {
173+
ShapeToolMessage::UpdateOptions {
174+
options: ShapeOptionsUpdate::ShapeType(ShapeType::Rectangle),
175+
}
176+
.into()
177+
}),
178+
MenuListEntry::new("Ellipse").label("Ellipse").on_commit(move |_| {
179+
ShapeToolMessage::UpdateOptions {
180+
options: ShapeOptionsUpdate::ShapeType(ShapeType::Ellipse),
181+
}
182+
.into()
183+
}),
184+
MenuListEntry::new("Arrow").label("Arrow").on_commit(move |_| {
185+
ShapeToolMessage::UpdateOptions {
186+
options: ShapeOptionsUpdate::ShapeType(ShapeType::Arrow),
187+
}
188+
.into()
189+
}),
190+
MenuListEntry::new("Line").label("Line").on_commit(move |_| {
191+
ShapeToolMessage::UpdateOptions {
192+
options: ShapeOptionsUpdate::ShapeType(ShapeType::Line),
193+
}
194+
.into()
195+
}),
171196
]];
172197
DropdownInput::new(entries).selected_index(Some(shape_type as u32)).widget_holder()
173198
}
@@ -805,7 +830,7 @@ impl Fsm for ShapeToolFsmState {
805830
};
806831

807832
match tool_data.current_shape {
808-
ShapeType::Polygon | ShapeType::Star | ShapeType::Circle | ShapeType::Arc | ShapeType::Spiral | ShapeType::Grid | ShapeType::Rectangle | ShapeType::Ellipse => {
833+
ShapeType::Polygon | ShapeType::Star | ShapeType::Circle | ShapeType::Arc | ShapeType::Spiral | ShapeType::Grid | ShapeType::Rectangle | ShapeType::Ellipse | ShapeType::Arrow => {
809834
tool_data.data.start(document, input)
810835
}
811836
ShapeType::Line => {
@@ -822,6 +847,7 @@ impl Fsm for ShapeToolFsmState {
822847
ShapeType::Star => Star::create_node(tool_options.vertices),
823848
ShapeType::Circle => Circle::create_node(),
824849
ShapeType::Arc => Arc::create_node(tool_options.arc_type),
850+
ShapeType::Arrow => Arrow::create_node(),
825851
ShapeType::Spiral => Spiral::create_node(tool_options.spiral_type, tool_options.turns),
826852
ShapeType::Grid => Grid::create_node(tool_options.grid_type),
827853
ShapeType::Rectangle => Rectangle::create_node(),
@@ -835,7 +861,7 @@ impl Fsm for ShapeToolFsmState {
835861
let defered_responses = &mut VecDeque::new();
836862

837863
match tool_data.current_shape {
838-
ShapeType::Polygon | ShapeType::Star | ShapeType::Circle | ShapeType::Arc | ShapeType::Spiral | ShapeType::Grid | ShapeType::Rectangle | ShapeType::Ellipse => {
864+
ShapeType::Arrow | ShapeType::Polygon | ShapeType::Star | ShapeType::Circle | ShapeType::Arc | ShapeType::Spiral | ShapeType::Grid | ShapeType::Rectangle | ShapeType::Ellipse => {
839865
defered_responses.add(GraphOperationMessage::TransformSet {
840866
layer,
841867
transform: DAffine2::from_scale_angle_translation(DVec2::ONE, 0., input.mouse.position),
@@ -872,6 +898,7 @@ impl Fsm for ShapeToolFsmState {
872898
ShapeType::Star => Star::update_shape(document, input, layer, tool_data, modifier, responses),
873899
ShapeType::Circle => Circle::update_shape(document, input, layer, tool_data, modifier, responses),
874900
ShapeType::Arc => Arc::update_shape(document, input, layer, tool_data, modifier, responses),
901+
ShapeType::Arrow => Arrow::update_shape(document, input, layer, tool_data, modifier, responses),
875902
ShapeType::Spiral => Spiral::update_shape(document, input, layer, tool_data, responses),
876903
ShapeType::Grid => Grid::update_shape(document, input, layer, tool_options.grid_type, tool_data, modifier, responses),
877904
ShapeType::Rectangle => Rectangle::update_shape(document, input, layer, tool_data, modifier, responses),
@@ -1127,6 +1154,7 @@ fn update_dynamic_hints(state: &ShapeToolFsmState, responses: &mut VecDeque<Mess
11271154
HintInfo::keys([Key::Shift], "Constrain Regular").prepend_plus(),
11281155
HintInfo::keys([Key::Alt], "From Center").prepend_plus(),
11291156
])],
1157+
ShapeType::Arrow => vec![HintGroup(vec![HintInfo::mouse(MouseMotion::LmbDrag, "Draw Arrow")])],
11301158
};
11311159
HintData(hint_groups)
11321160
}
@@ -1142,6 +1170,7 @@ fn update_dynamic_hints(state: &ShapeToolFsmState, responses: &mut VecDeque<Mess
11421170
HintInfo::keys([Key::Alt], "From Center"),
11431171
HintInfo::keys([Key::Control], "Lock Angle"),
11441172
]),
1173+
ShapeType::Arrow => HintGroup(vec![HintInfo::keys([Key::Shift], "Constrain Angle")]),
11451174
ShapeType::Circle => HintGroup(vec![HintInfo::keys([Key::Alt], "From Center")]),
11461175
ShapeType::Spiral => HintGroup(vec![]),
11471176
};

0 commit comments

Comments
 (0)