Improve the Shape tool's arrow drawing controls (#3650)
* fixed the arrow's parameters Signed-off-by: krVatsal <kumarvatsal34@gmail.com> * shifted the arrow's origin to its tail Signed-off-by: krVatsal <kumarvatsal34@gmail.com> * modified arrow shapetype fucntion to be like other shapes * fixed rust formatting * Remove misleading part of comment referencing the origin --------- Signed-off-by: krVatsal <kumarvatsal34@gmail.com> Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
parent
87739ff877
commit
82f7dc7062
|
|
@ -15,16 +15,16 @@ use std::collections::VecDeque;
|
|||
pub struct Arrow;
|
||||
|
||||
impl Arrow {
|
||||
pub fn create_node(document: &DocumentMessageHandler, drag_start: DVec2) -> NodeTemplate {
|
||||
pub fn create_node(document: &DocumentMessageHandler, drag_start: DVec2, shaft_width: f64, head_width: f64, head_length: f64) -> NodeTemplate {
|
||||
let node_type = resolve_proto_node_type(graphene_std::vector_nodes::arrow::IDENTIFIER).expect("Arrow node does not exist");
|
||||
let viewport_pos = document.metadata().document_to_viewport.transform_point2(drag_start);
|
||||
node_type.node_template_input_override([
|
||||
None,
|
||||
Some(NodeInput::value(TaggedValue::DVec2(viewport_pos), false)), // start
|
||||
Some(NodeInput::value(TaggedValue::DVec2(viewport_pos), false)), // end
|
||||
Some(NodeInput::value(TaggedValue::F64(10.), false)), // shaft_width
|
||||
Some(NodeInput::value(TaggedValue::F64(30.), false)), // head_width
|
||||
Some(NodeInput::value(TaggedValue::F64(20.), false)), // head_length
|
||||
Some(NodeInput::value(TaggedValue::F64(shaft_width), false)), // shaft_width
|
||||
Some(NodeInput::value(TaggedValue::F64(head_width), false)), // head_width
|
||||
Some(NodeInput::value(TaggedValue::F64(head_length), false)), // head_length
|
||||
])
|
||||
}
|
||||
|
||||
|
|
@ -56,12 +56,7 @@ impl Arrow {
|
|||
return;
|
||||
};
|
||||
|
||||
// Calculate proportional dimensions based on arrow length
|
||||
let shaft_width = length_document * 0.1;
|
||||
let head_width = length_document * 0.3;
|
||||
let head_length = length_document * 0.2;
|
||||
|
||||
// Update Arrow node parameters with document space coordinates (like Line tool)
|
||||
// Update Arrow node start and end points with document space coordinates
|
||||
responses.add(NodeGraphMessage::SetInput {
|
||||
input_connector: InputConnector::node(node_id, 1),
|
||||
input: NodeInput::value(TaggedValue::DVec2(start_document), false),
|
||||
|
|
@ -70,18 +65,6 @@ impl Arrow {
|
|||
input_connector: InputConnector::node(node_id, 2),
|
||||
input: NodeInput::value(TaggedValue::DVec2(end_document), false),
|
||||
});
|
||||
responses.add(NodeGraphMessage::SetInput {
|
||||
input_connector: InputConnector::node(node_id, 3),
|
||||
input: NodeInput::value(TaggedValue::F64(shaft_width), false),
|
||||
});
|
||||
responses.add(NodeGraphMessage::SetInput {
|
||||
input_connector: InputConnector::node(node_id, 4),
|
||||
input: NodeInput::value(TaggedValue::F64(head_width), false),
|
||||
});
|
||||
responses.add(NodeGraphMessage::SetInput {
|
||||
input_connector: InputConnector::node(node_id, 5),
|
||||
input: NodeInput::value(TaggedValue::F64(head_length), false),
|
||||
});
|
||||
|
||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,6 +44,9 @@ pub struct ShapeToolOptions {
|
|||
grid_type: GridType,
|
||||
spiral_type: SpiralType,
|
||||
turns: f64,
|
||||
arrow_shaft_width: f64,
|
||||
arrow_head_width: f64,
|
||||
arrow_head_length: f64,
|
||||
}
|
||||
|
||||
impl Default for ShapeToolOptions {
|
||||
|
|
@ -58,6 +61,9 @@ impl Default for ShapeToolOptions {
|
|||
spiral_type: SpiralType::Archimedean,
|
||||
turns: 5.,
|
||||
grid_type: GridType::Rectangular,
|
||||
arrow_shaft_width: 14.,
|
||||
arrow_head_width: 32.,
|
||||
arrow_head_length: 28.,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -76,6 +82,9 @@ pub enum ShapeOptionsUpdate {
|
|||
SpiralType(SpiralType),
|
||||
Turns(f64),
|
||||
GridType(GridType),
|
||||
ArrowShaftWidth(f64),
|
||||
ArrowHeadWidth(f64),
|
||||
ArrowHeadLength(f64),
|
||||
}
|
||||
|
||||
#[impl_message(Message, ToolMessage, Shape)]
|
||||
|
|
@ -236,6 +245,51 @@ fn create_weight_widget(line_weight: f64) -> WidgetInstance {
|
|||
.widget_instance()
|
||||
}
|
||||
|
||||
fn create_arrow_shaft_width_widget(shaft_width: f64) -> WidgetInstance {
|
||||
NumberInput::new(Some(shaft_width))
|
||||
.unit(" px")
|
||||
.label("Shaft")
|
||||
.min(0.1)
|
||||
.max(1000.)
|
||||
.on_update(|number_input: &NumberInput| {
|
||||
ShapeToolMessage::UpdateOptions {
|
||||
options: ShapeOptionsUpdate::ArrowShaftWidth(number_input.value.unwrap()),
|
||||
}
|
||||
.into()
|
||||
})
|
||||
.widget_instance()
|
||||
}
|
||||
|
||||
fn create_arrow_head_width_widget(head_width: f64) -> WidgetInstance {
|
||||
NumberInput::new(Some(head_width))
|
||||
.unit(" px")
|
||||
.label("Head W")
|
||||
.min(0.1)
|
||||
.max(1000.)
|
||||
.on_update(|number_input: &NumberInput| {
|
||||
ShapeToolMessage::UpdateOptions {
|
||||
options: ShapeOptionsUpdate::ArrowHeadWidth(number_input.value.unwrap()),
|
||||
}
|
||||
.into()
|
||||
})
|
||||
.widget_instance()
|
||||
}
|
||||
|
||||
fn create_arrow_head_length_widget(head_length: f64) -> WidgetInstance {
|
||||
NumberInput::new(Some(head_length))
|
||||
.unit(" px")
|
||||
.label("Head L")
|
||||
.min(0.1)
|
||||
.max(1000.)
|
||||
.on_update(|number_input: &NumberInput| {
|
||||
ShapeToolMessage::UpdateOptions {
|
||||
options: ShapeOptionsUpdate::ArrowHeadLength(number_input.value.unwrap()),
|
||||
}
|
||||
.into()
|
||||
})
|
||||
.widget_instance()
|
||||
}
|
||||
|
||||
fn create_spiral_type_widget(spiral_type: SpiralType) -> WidgetInstance {
|
||||
let entries = vec![vec![
|
||||
MenuListEntry::new("Archimedean").label("Archimedean").on_commit(move |_| {
|
||||
|
|
@ -304,6 +358,15 @@ impl LayoutHolder for ShapeTool {
|
|||
widgets.push(Separator::new(SeparatorStyle::Unrelated).widget_instance());
|
||||
}
|
||||
|
||||
if self.options.shape_type == ShapeType::Arrow {
|
||||
widgets.push(create_arrow_shaft_width_widget(self.options.arrow_shaft_width));
|
||||
widgets.push(Separator::new(SeparatorStyle::Related).widget_instance());
|
||||
widgets.push(create_arrow_head_width_widget(self.options.arrow_head_width));
|
||||
widgets.push(Separator::new(SeparatorStyle::Related).widget_instance());
|
||||
widgets.push(create_arrow_head_length_widget(self.options.arrow_head_length));
|
||||
widgets.push(Separator::new(SeparatorStyle::Unrelated).widget_instance());
|
||||
}
|
||||
|
||||
if self.options.shape_type != ShapeType::Line {
|
||||
widgets.append(&mut self.options.fill.create_widgets(
|
||||
"Fill",
|
||||
|
|
@ -414,6 +477,15 @@ impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for Shap
|
|||
ShapeOptionsUpdate::GridType(grid_type) => {
|
||||
self.options.grid_type = grid_type;
|
||||
}
|
||||
ShapeOptionsUpdate::ArrowShaftWidth(shaft_width) => {
|
||||
self.options.arrow_shaft_width = shaft_width;
|
||||
}
|
||||
ShapeOptionsUpdate::ArrowHeadWidth(head_width) => {
|
||||
self.options.arrow_head_width = head_width;
|
||||
}
|
||||
ShapeOptionsUpdate::ArrowHeadLength(head_length) => {
|
||||
self.options.arrow_head_length = head_length;
|
||||
}
|
||||
}
|
||||
|
||||
update_dynamic_hints(&self.fsm_state, responses, &self.tool_data);
|
||||
|
|
@ -854,7 +926,13 @@ impl Fsm for ShapeToolFsmState {
|
|||
ShapeType::Grid => Grid::create_node(tool_options.grid_type),
|
||||
ShapeType::Rectangle => Rectangle::create_node(),
|
||||
ShapeType::Ellipse => Ellipse::create_node(),
|
||||
ShapeType::Arrow => Arrow::create_node(document, tool_data.data.drag_start),
|
||||
ShapeType::Arrow => Arrow::create_node(
|
||||
document,
|
||||
tool_data.data.drag_start,
|
||||
tool_options.arrow_shaft_width,
|
||||
tool_options.arrow_head_width,
|
||||
tool_options.arrow_head_length,
|
||||
),
|
||||
ShapeType::Line => Line::create_node(document, tool_data.data.drag_start),
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -330,14 +330,16 @@ impl<PointId: Identifier> Subpath<PointId> {
|
|||
let head_base_distance = (length - head_length).max(0.);
|
||||
let head_base = start + direction * head_base_distance;
|
||||
|
||||
// Arrow path starts at the tail, traces around the shape, and returns to the tail
|
||||
let anchors = [
|
||||
start - perpendicular * half_shaft, // Tail bottom
|
||||
head_base - perpendicular * half_shaft, // Head base bottom (shaft)
|
||||
head_base - perpendicular * half_head, // Head base bottom (wide)
|
||||
end, // Tip
|
||||
head_base + perpendicular * half_head, // Head base top (wide)
|
||||
head_base + perpendicular * half_shaft, // Head base top (shaft)
|
||||
start, // Tail center (origin)
|
||||
start + perpendicular * half_shaft, // Tail top
|
||||
head_base + perpendicular * half_shaft, // Head base top (shaft)
|
||||
head_base + perpendicular * half_head, // Head base top (wide)
|
||||
end, // Tip
|
||||
head_base - perpendicular * half_head, // Head base bottom (wide)
|
||||
head_base - perpendicular * half_shaft, // Head base bottom (shaft)
|
||||
start - perpendicular * half_shaft, // Tail bottom
|
||||
];
|
||||
|
||||
Self::from_anchors(anchors, true)
|
||||
|
|
|
|||
Loading…
Reference in New Issue