mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-08-04 13:30:48 +00:00
add: add all of the stuff for path tool
This commit is contained in:
parent
06e8e4e6e0
commit
7d46c7dcfd
4 changed files with 182 additions and 125 deletions
|
@ -9,7 +9,7 @@ use crate::messages::tool::tool_messages::path_tool::PathOptionsUpdate;
|
|||
use crate::messages::tool::tool_messages::select_tool::SelectOptionsUpdate;
|
||||
use crate::messages::tool::tool_messages::tool_prelude::*;
|
||||
use glam::{DAffine2, DVec2};
|
||||
use graphene_std::transform::ReferencePoint;
|
||||
use graphene_std::{transform::ReferencePoint, vector::ManipulatorPointId};
|
||||
use std::fmt;
|
||||
|
||||
pub fn pin_pivot_widget(disabled: bool, source: Source) -> WidgetHolder {
|
||||
|
@ -79,6 +79,7 @@ pub struct Dot {
|
|||
pub pivot: Pivot,
|
||||
pub state: DotState,
|
||||
pub layer: Option<LayerNodeIdentifier>,
|
||||
pub point: Option<ManipulatorPointId>,
|
||||
}
|
||||
|
||||
impl Dot {
|
||||
|
@ -223,6 +224,23 @@ impl Pivot {
|
|||
self.pivot = Some(self.transform_from_normalized.transform_point2(self.normalized_pivot));
|
||||
}
|
||||
|
||||
pub fn recalculate_pivot_for_layer(&mut self, document: &DocumentMessageHandler, layer: LayerNodeIdentifier, bounds: Option<[DVec2; 2]>) {
|
||||
if !self.active {
|
||||
return;
|
||||
}
|
||||
|
||||
let selected = document.network_interface.selected_nodes();
|
||||
if !selected.has_selected_nodes() {
|
||||
self.normalized_pivot = DVec2::splat(0.5);
|
||||
self.pivot = None;
|
||||
return;
|
||||
};
|
||||
|
||||
let [min, max] = bounds.unwrap_or([DVec2::ZERO, DVec2::ONE]);
|
||||
self.transform_from_normalized = DAffine2::from_translation(min) * DAffine2::from_scale(max - min);
|
||||
self.pivot = Some(self.transform_from_normalized.transform_point2(self.normalized_pivot));
|
||||
}
|
||||
|
||||
pub fn update(&mut self, document: &DocumentMessageHandler, overlay_context: &mut OverlayContext, draw_data: Option<(f64,)>, draw: bool) {
|
||||
if !overlay_context.visibility_settings.pivot() {
|
||||
self.active = false;
|
||||
|
|
|
@ -500,6 +500,7 @@ struct PathToolData {
|
|||
dragging_state: DraggingState,
|
||||
angle: f64,
|
||||
dot: Dot,
|
||||
ordered_points: Vec<ManipulatorPointId>,
|
||||
opposite_handle_position: Option<DVec2>,
|
||||
last_clicked_point_was_selected: bool,
|
||||
last_clicked_segment_was_selected: bool,
|
||||
|
@ -1377,6 +1378,12 @@ impl PathToolData {
|
|||
fn get_as_dot(&self) -> Dot {
|
||||
self.dot.clone()
|
||||
}
|
||||
|
||||
fn sync_history(&mut self, points: &Vec<ManipulatorPointId>) {
|
||||
self.ordered_points.retain(|layer| points.contains(layer));
|
||||
self.ordered_points.extend(points.iter().find(|&layer| !self.ordered_points.contains(layer)));
|
||||
self.dot.point = self.ordered_points.last().map(|x| *x)
|
||||
}
|
||||
}
|
||||
|
||||
impl Fsm for PathToolFsmState {
|
||||
|
@ -1389,9 +1396,6 @@ impl Fsm for PathToolFsmState {
|
|||
update_dynamic_hints(self, responses, shape_editor, document, tool_data, tool_options);
|
||||
|
||||
let ToolMessage::Path(event) = event else { return self };
|
||||
if !matches!(event, PathToolMessage::Overlays(_) | PathToolMessage::UpdateSelectedPointsStatus { .. }) {
|
||||
// debug!("{event:?}");
|
||||
}
|
||||
match (self, event) {
|
||||
(_, PathToolMessage::SelectionChanged) => {
|
||||
// Set the newly targeted layers to visible
|
||||
|
@ -1408,6 +1412,9 @@ impl Fsm for PathToolFsmState {
|
|||
shape_editor.update_selected_anchors_status(display_anchors);
|
||||
shape_editor.update_selected_handles_status(display_handles);
|
||||
|
||||
let new_points = shape_editor.selected_points().copied().collect::<Vec<_>>();
|
||||
tool_data.sync_history(&new_points);
|
||||
|
||||
self
|
||||
}
|
||||
(_, PathToolMessage::Overlays(mut overlay_context)) => {
|
||||
|
|
|
@ -361,7 +361,7 @@ struct SelectToolData {
|
|||
lasso_polygon: Vec<ViewportPosition>,
|
||||
selection_mode: Option<SelectionMode>,
|
||||
layers_dragging: Vec<LayerNodeIdentifier>, // Unordered, often used as temporary buffer
|
||||
orderer_layers: Vec<LayerNodeIdentifier>, // Ordered list of layers
|
||||
ordered_layers: Vec<LayerNodeIdentifier>, // Ordered list of layers
|
||||
layer_selected_on_start: Option<LayerNodeIdentifier>,
|
||||
select_single_layer: Option<LayerNodeIdentifier>,
|
||||
axis_align: bool,
|
||||
|
@ -548,9 +548,9 @@ impl SelectToolData {
|
|||
}
|
||||
|
||||
fn sync_history(&mut self) {
|
||||
self.orderer_layers.retain(|layer| self.layers_dragging.contains(layer));
|
||||
self.orderer_layers.extend(self.layers_dragging.iter().find(|&layer| !self.orderer_layers.contains(layer)));
|
||||
self.dot.layer = self.orderer_layers.last().map(|x| *x)
|
||||
self.ordered_layers.retain(|layer| self.layers_dragging.contains(layer));
|
||||
self.ordered_layers.extend(self.layers_dragging.iter().find(|&layer| !self.ordered_layers.contains(layer)));
|
||||
self.dot.layer = self.ordered_layers.last().map(|x| *x)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -38,6 +38,8 @@ pub struct TransformLayerMessageHandler {
|
|||
dot: Dot,
|
||||
pivot: ViewportPosition,
|
||||
|
||||
path_bounds: Option<[DVec2; 2]>,
|
||||
|
||||
local_pivot: DocumentPosition,
|
||||
local_mouse_start: DocumentPosition,
|
||||
grab_target: DocumentPosition,
|
||||
|
@ -64,43 +66,66 @@ impl TransformLayerMessageHandler {
|
|||
}
|
||||
|
||||
fn calculate_pivot(
|
||||
document: &DocumentMessageHandler,
|
||||
selected_points: &Vec<&ManipulatorPointId>,
|
||||
vector_data: &VectorData,
|
||||
viewspace: DAffine2,
|
||||
get_location: impl Fn(&ManipulatorPointId) -> Option<DVec2>,
|
||||
dot: &Dot,
|
||||
) -> Option<(DVec2, DVec2)> {
|
||||
dot: &mut Dot,
|
||||
layers: LayerNodeIdentifier,
|
||||
) -> (Option<(DVec2, DVec2)>, Option<[DVec2; 2]>) {
|
||||
let average_position = || {
|
||||
let mut point_count = 0;
|
||||
selected_points.iter().filter_map(|p| get_location(p)).inspect(|_| point_count += 1).sum::<DVec2>() / point_count as f64
|
||||
};
|
||||
let bounds = selected_points.iter().filter_map(|p| get_location(p)).fold(None, |acc: Option<[DVec2; 2]>, point| {
|
||||
if let Some([mut min, mut max]) = acc {
|
||||
min.x = min.x.min(point.x);
|
||||
min.y = min.y.min(point.y);
|
||||
max.x = max.x.max(point.x);
|
||||
max.y = max.y.max(point.y);
|
||||
Some([min, max])
|
||||
} else {
|
||||
Some([point, point])
|
||||
}
|
||||
});
|
||||
dot.pivot.recalculate_pivot_for_layer(document, layers, bounds);
|
||||
let position = || {
|
||||
if !dot.state.enabled {
|
||||
return average_position();
|
||||
}
|
||||
{
|
||||
if dot.state.enabled {
|
||||
match dot.state.dot {
|
||||
DotType::Average => average_position(),
|
||||
DotType::Active => selected_points.first().map(|p| get_location(p)).flatten().unwrap_or_else(average_position),
|
||||
DotType::Pivot => average_position(),
|
||||
DotType::Average => None,
|
||||
DotType::Active => dot.point.and_then(|p| get_location(&p)),
|
||||
DotType::Pivot => dot.pivot.position(),
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
.unwrap_or_else(average_position)
|
||||
};
|
||||
let [point] = selected_points.as_slice() else {
|
||||
// Handle the case where there are multiple points
|
||||
let position = position();
|
||||
return Some((position, position));
|
||||
return (Some((position, position)), bounds);
|
||||
};
|
||||
|
||||
match point {
|
||||
ManipulatorPointId::PrimaryHandle(_) | ManipulatorPointId::EndHandle(_) => {
|
||||
// Get the anchor position and transform it to the pivot
|
||||
let pivot_pos = point.get_anchor_position(vector_data).map(|anchor_position| viewspace.transform_point2(anchor_position))?;
|
||||
let target = viewspace.transform_point2(point.get_position(vector_data)?);
|
||||
Some((pivot_pos, target))
|
||||
let (Some(pivot_pos), Some(position)) = (
|
||||
point.get_anchor_position(vector_data).map(|anchor_position| viewspace.transform_point2(anchor_position)),
|
||||
point.get_position(vector_data),
|
||||
) else {
|
||||
return (None, None);
|
||||
};
|
||||
let target = viewspace.transform_point2(position);
|
||||
(Some((pivot_pos, target)), None)
|
||||
}
|
||||
_ => {
|
||||
// Calculate the average position of all selected points
|
||||
let position = position();
|
||||
Some((position, position))
|
||||
(Some((position, position)), bounds)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -222,8 +247,17 @@ impl MessageHandler<TransformLayerMessage, TransformData<'_>> for TransformLayer
|
|||
let affected_point_refs = affected_points.iter().collect();
|
||||
|
||||
let get_location = |point: &&ManipulatorPointId| point.get_position(&vector_data).map(|position| viewspace.transform_point2(position));
|
||||
if let Some((new_pivot, grab_target)) = calculate_pivot(&affected_point_refs, &vector_data, viewspace, |point: &ManipulatorPointId| get_location(&point), &self.dot) {
|
||||
if let (Some((new_pivot, grab_target)), bounds) = calculate_pivot(
|
||||
document,
|
||||
&affected_point_refs,
|
||||
&vector_data,
|
||||
viewspace,
|
||||
|point: &ManipulatorPointId| get_location(&point),
|
||||
&mut self.dot,
|
||||
selected_layers[0],
|
||||
) {
|
||||
*selected.pivot = new_pivot;
|
||||
self.path_bounds = bounds;
|
||||
|
||||
self.local_pivot = document_to_viewport.inverse().transform_point2(*selected.pivot);
|
||||
self.grab_target = document_to_viewport.inverse().transform_point2(grab_target);
|
||||
|
@ -249,11 +283,6 @@ impl MessageHandler<TransformLayerMessage, TransformData<'_>> for TransformLayer
|
|||
return;
|
||||
}
|
||||
|
||||
for layer in document.metadata().all_layers() {
|
||||
if !document.network_interface.is_artboard(&layer.to_node(), &[]) {
|
||||
continue;
|
||||
};
|
||||
|
||||
let viewport_box = input.viewport_bounds.size();
|
||||
let axis_constraint = self.transform_operation.axis_constraint();
|
||||
|
||||
|
@ -360,6 +389,9 @@ impl MessageHandler<TransformLayerMessage, TransformData<'_>> for TransformLayer
|
|||
overlay_context.text(&text, COLOR_OVERLAY_BLUE, None, transform, 16., [Pivot::Middle, Pivot::Middle]);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(bounds) = self.path_bounds {
|
||||
overlay_context.quad(Quad::from_box(bounds), None, None);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue