Split out viewport handling into its own message handler (#3331)

* extract viewport handeling

* fix web overlays

* some cleanup

* remove some physical conversions

* fix resize snapping

* fixup

* apply some review feedback

* make viewport api more ergonomic

* fix

* fix web overlay canvas clear size

* clear workaround for canvas

* rename trigger message

---------

Co-authored-by: Dennis Kobert <dennis@kobert.dev>
This commit is contained in:
Timon
2025-11-08 08:59:38 +00:00
committed by GitHub
co-authored by Dennis Kobert
parent 3490111b96
commit 881ec0b193
60 changed files with 1326 additions and 607 deletions
@@ -145,12 +145,12 @@ impl ArtboardToolData {
}
}
fn hovered_artboard(document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler) -> Option<LayerNodeIdentifier> {
document.click_xray(input).find(|&layer| document.network_interface.is_artboard(&layer.to_node(), &[]))
fn hovered_artboard(document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, viewport: &ViewportMessageHandler) -> Option<LayerNodeIdentifier> {
document.click_xray(input, viewport).find(|&layer| document.network_interface.is_artboard(&layer.to_node(), &[]))
}
fn select_artboard(&mut self, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, responses: &mut VecDeque<Message>) -> bool {
if let Some(intersection) = Self::hovered_artboard(document, input) {
fn select_artboard(&mut self, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, viewport: &ViewportMessageHandler, responses: &mut VecDeque<Message>) -> bool {
if let Some(intersection) = Self::hovered_artboard(document, input, viewport) {
self.selected_artboard = Some(intersection);
if let Some(bounds) = document.metadata().bounding_box_document(intersection) {
@@ -171,7 +171,15 @@ impl ArtboardToolData {
}
}
fn resize_artboard(&mut self, responses: &mut VecDeque<Message>, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, from_center: bool, constrain_square: bool) {
fn resize_artboard(
&mut self,
responses: &mut VecDeque<Message>,
document: &DocumentMessageHandler,
input: &InputPreprocessorMessageHandler,
viewport: &ViewportMessageHandler,
from_center: bool,
constrain_square: bool,
) {
let Some(bounds) = &self.bounding_box_manager else {
return;
};
@@ -193,7 +201,7 @@ impl ArtboardToolData {
let snap = Some(SizeSnapData {
manager: &mut self.draw.snap_manager,
points: &mut self.snap_candidates,
snap_data: SnapData::ignore(document, input, &ignore),
snap_data: SnapData::ignore(document, input, viewport, &ignore),
});
let (min, size) = movement.new_size(input.mouse.position, bounds.transform, center, constrain_square, snap);
let max = min + size;
@@ -225,9 +233,9 @@ impl Fsm for ArtboardToolFsmState {
type ToolOptions = ();
fn transition(self, event: ToolMessage, tool_data: &mut Self::ToolData, tool_action_data: &mut ToolActionMessageContext, _tool_options: &(), responses: &mut VecDeque<Message>) -> Self {
let ToolActionMessageContext { document, input, .. } = tool_action_data;
let ToolActionMessageContext { document, input, viewport, .. } = tool_action_data;
let hovered = ArtboardToolData::hovered_artboard(document, input).is_some();
let hovered = ArtboardToolData::hovered_artboard(document, input, viewport).is_some();
let ToolMessage::Artboard(event) = event else { return self };
match (self, event) {
@@ -259,8 +267,8 @@ impl Fsm for ArtboardToolFsmState {
let selected_artboard_bounds = tool_data.selected_artboard.and_then(|layer| document.metadata().bounding_box_document(layer)).map(Rect::from_box);
// Find hovered artboard or regular layer
let hovered_artboard = ArtboardToolData::hovered_artboard(document, input);
let hovered_layer = document.click_xray(input).find(|&layer| !document.network_interface.is_artboard(&layer.to_node(), &[]));
let hovered_artboard = ArtboardToolData::hovered_artboard(document, input, viewport);
let hovered_layer = document.click_xray(input, viewport).find(|&layer| !document.network_interface.is_artboard(&layer.to_node(), &[]));
// Get bounds for the hovered object (prioritize artboards)
let hovered_bounds = if let Some(artboard) = hovered_artboard {
@@ -281,7 +289,7 @@ impl Fsm for ArtboardToolFsmState {
}
}
tool_data.draw.snap_manager.draw_overlays(SnapData::new(document, input), &mut overlay_context);
tool_data.draw.snap_manager.draw_overlays(SnapData::new(document, input, viewport), &mut overlay_context);
self
}
@@ -295,11 +303,11 @@ impl Fsm for ArtboardToolFsmState {
tool_data.start_resizing(selected_edges, document, input);
tool_data.get_snap_candidates(document, input);
ArtboardToolFsmState::ResizingBounds
} else if tool_data.select_artboard(document, input, responses) {
} else if tool_data.select_artboard(document, input, viewport, responses) {
tool_data.get_snap_candidates(document, input);
ArtboardToolFsmState::Dragging
} else {
tool_data.draw.start(document, input);
tool_data.draw.start(document, input, viewport);
ArtboardToolFsmState::Drawing
};
@@ -309,14 +317,14 @@ impl Fsm for ArtboardToolFsmState {
(ArtboardToolFsmState::ResizingBounds, ArtboardToolMessage::PointerMove { constrain_axis_or_aspect, center }) => {
let from_center = input.keyboard.get(center as usize);
let constrain_square = input.keyboard.get(constrain_axis_or_aspect as usize);
tool_data.resize_artboard(responses, document, input, from_center, constrain_square);
tool_data.resize_artboard(responses, document, input, viewport, from_center, constrain_square);
// Auto-panning
let messages = [
ArtboardToolMessage::PointerOutsideViewport { constrain_axis_or_aspect, center }.into(),
ArtboardToolMessage::PointerMove { constrain_axis_or_aspect, center }.into(),
];
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
tool_data.auto_panning.setup_by_mouse_position(input, viewport, &messages, responses);
ArtboardToolFsmState::ResizingBounds
}
@@ -325,7 +333,7 @@ impl Fsm for ArtboardToolFsmState {
let axis_align = input.keyboard.get(constrain_axis_or_aspect as usize);
let ignore = tool_data.selected_artboard.map_or(Vec::new(), |layer| vec![layer]);
let snap_data = SnapData::ignore(document, input, &ignore);
let snap_data = SnapData::ignore(document, input, viewport, &ignore);
let document_to_viewport = document.metadata().document_to_viewport;
let [start, current] = [tool_data.drag_start, tool_data.drag_current].map(|point| document_to_viewport.transform_point2(point));
let mouse_delta = snap_drag(start, current, axis_align, Axis::None, snap_data, &mut tool_data.draw.snap_manager, &tool_data.snap_candidates);
@@ -355,14 +363,14 @@ impl Fsm for ArtboardToolFsmState {
ArtboardToolMessage::PointerOutsideViewport { constrain_axis_or_aspect, center }.into(),
ArtboardToolMessage::PointerMove { constrain_axis_or_aspect, center }.into(),
];
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
tool_data.auto_panning.setup_by_mouse_position(input, viewport, &messages, responses);
}
ArtboardToolFsmState::Dragging
}
(ArtboardToolFsmState::Drawing, ArtboardToolMessage::PointerMove { constrain_axis_or_aspect, center }) => {
// The draw.calculate_points_ignore_layer uses this value to avoid snapping to itself.
tool_data.draw.layer = tool_data.selected_artboard;
let [start, end] = tool_data.draw.calculate_points_ignore_layer(document, input, center, constrain_axis_or_aspect, true);
let [start, end] = tool_data.draw.calculate_points_ignore_layer(document, input, viewport, center, constrain_axis_or_aspect, true);
let viewport_to_document = document.metadata().document_to_viewport.inverse();
let [start, end] = [start, end].map(|point| viewport_to_document.transform_point2(point));
if let Some(artboard) = tool_data.selected_artboard {
@@ -396,7 +404,7 @@ impl Fsm for ArtboardToolFsmState {
ArtboardToolMessage::PointerOutsideViewport { constrain_axis_or_aspect, center }.into(),
ArtboardToolMessage::PointerMove { constrain_axis_or_aspect, center }.into(),
];
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
tool_data.auto_panning.setup_by_mouse_position(input, viewport, &messages, responses);
ArtboardToolFsmState::Drawing
}
@@ -408,7 +416,7 @@ impl Fsm for ArtboardToolFsmState {
.map_or(MouseCursorIcon::Default, |bounds| bounds.get_cursor(input, false, false, None));
if cursor == MouseCursorIcon::Default && !hovered {
tool_data.draw.snap_manager.preview_draw(&SnapData::new(document, input), input.mouse.position);
tool_data.draw.snap_manager.preview_draw(&SnapData::new(document, input, viewport), input.mouse.position);
responses.add(OverlaysMessage::Draw);
cursor = MouseCursorIcon::Crosshair;
} else {
@@ -424,19 +432,19 @@ impl Fsm for ArtboardToolFsmState {
}
(ArtboardToolFsmState::ResizingBounds, ArtboardToolMessage::PointerOutsideViewport { .. }) => {
// Auto-panning
let _ = tool_data.auto_panning.shift_viewport(input, responses);
let _ = tool_data.auto_panning.shift_viewport(input, viewport, responses);
ArtboardToolFsmState::ResizingBounds
}
(ArtboardToolFsmState::Dragging, ArtboardToolMessage::PointerOutsideViewport { .. }) => {
// Auto-panning
tool_data.auto_panning.shift_viewport(input, responses);
tool_data.auto_panning.shift_viewport(input, viewport, responses);
ArtboardToolFsmState::Dragging
}
(ArtboardToolFsmState::Drawing, ArtboardToolMessage::PointerOutsideViewport { .. }) => {
// Auto-panning
tool_data.auto_panning.shift_viewport(input, responses);
tool_data.auto_panning.shift_viewport(input, viewport, responses);
ArtboardToolFsmState::Drawing
}
@@ -545,7 +553,9 @@ impl Fsm for ArtboardToolFsmState {
let scale = DAffine2::from_scale(enlargement_factor);
let pivot = DAffine2::from_translation(pivot);
let transformation = pivot * scale * pivot.inverse();
let document_to_viewport = document.navigation_handler.calculate_offset_transform(input.viewport_bounds.center(), &document.document_ptz);
let document_to_viewport = document
.navigation_handler
.calculate_offset_transform(viewport.center_in_viewport_space().into(), &document.document_ptz);
let to = document_to_viewport.inverse() * document.metadata().downstream_transform_to_viewport(selected_artboard);
let original_transform = document.metadata().upstream_transform(selected_artboard.to_node());
let new = to.inverse() * transformation * to * original_transform;
@@ -81,7 +81,9 @@ impl Fsm for EyedropperToolFsmState {
type ToolOptions = ();
fn transition(self, event: ToolMessage, _tool_data: &mut Self::ToolData, tool_action_data: &mut ToolActionMessageContext, _tool_options: &(), responses: &mut VecDeque<Message>) -> Self {
let ToolActionMessageContext { global_tool_data, input, .. } = tool_action_data;
let ToolActionMessageContext {
global_tool_data, input, viewport, ..
} = tool_action_data;
let ToolMessage::Eyedropper(event) = event else { return self };
match (self, event) {
@@ -97,7 +99,8 @@ impl Fsm for EyedropperToolFsmState {
}
// Sampling -> Sampling
(EyedropperToolFsmState::SamplingPrimary | EyedropperToolFsmState::SamplingSecondary, EyedropperToolMessage::PointerMove) => {
if input.viewport_bounds.in_bounds(input.mouse.position) {
let mouse_position = viewport.logical(input.mouse.position);
if viewport.is_in_bounds(mouse_position) {
update_cursor_preview(responses, input, global_tool_data, None);
} else {
disable_cursor_preview(responses);
@@ -94,7 +94,11 @@ impl Fsm for FillToolFsmState {
responses: &mut VecDeque<Message>,
) -> Self {
let ToolActionMessageContext {
document, global_tool_data, input, ..
document,
global_tool_data,
input,
viewport,
..
} = handler_data;
let ToolMessage::Fill(event) = event else { return self };
@@ -105,7 +109,7 @@ impl Fsm for FillToolFsmState {
let preview_color = if use_secondary { global_tool_data.secondary_color } else { global_tool_data.primary_color };
// Get the layer the user is hovering over
if let Some(layer) = document.click(input) {
if let Some(layer) = document.click(input, viewport) {
overlay_context.fill_path_pattern(document.metadata().layer_outline(layer), document.metadata().transform_to_viewport(layer), &preview_color);
}
@@ -117,7 +121,7 @@ impl Fsm for FillToolFsmState {
self
}
(FillToolFsmState::Ready, color_event) => {
let Some(layer_identifier) = document.click(input) else {
let Some(layer_identifier) = document.click(input, viewport) else {
return self;
};
// If the layer is a raster layer, don't fill it, wait till the flood fill tool is implemented
@@ -237,6 +237,7 @@ impl Fsm for FreehandToolFsmState {
input,
shape_editor,
preferences,
viewport,
..
} = tool_action_data;
@@ -283,7 +284,7 @@ impl Fsm for FreehandToolFsmState {
responses.add(DocumentMessage::DeselectAllLayers);
let parent = document.new_layer_bounding_artboard(input);
let parent = document.new_layer_bounding_artboard(input, viewport);
let node_type = resolve_document_node_type("Path").expect("Path node does not exist");
let node = node_type.default_node_template();
@@ -255,7 +255,11 @@ impl Fsm for GradientToolFsmState {
responses: &mut VecDeque<Message>,
) -> Self {
let ToolActionMessageContext {
document, global_tool_data, input, ..
document,
global_tool_data,
input,
viewport,
..
} = tool_action_data;
let ToolMessage::Gradient(event) = event else { return self };
@@ -420,7 +424,7 @@ impl Fsm for GradientToolFsmState {
let gradient_state = if dragging {
GradientToolFsmState::Drawing
} else {
let selected_layer = document.click(input);
let selected_layer = document.click(input, viewport);
// Apply the gradient to the selected layer
if let Some(layer) = selected_layer {
@@ -464,13 +468,13 @@ impl Fsm for GradientToolFsmState {
GradientToolMessage::PointerOutsideViewport { constrain_axis }.into(),
GradientToolMessage::PointerMove { constrain_axis }.into(),
];
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
tool_data.auto_panning.setup_by_mouse_position(input, viewport, &messages, responses);
GradientToolFsmState::Drawing
}
(GradientToolFsmState::Drawing, GradientToolMessage::PointerOutsideViewport { .. }) => {
// Auto-panning
if let Some(shift) = tool_data.auto_panning.shift_viewport(input, responses) {
if let Some(shift) = tool_data.auto_panning.shift_viewport(input, viewport, responses) {
if let Some(selected_gradient) = &mut tool_data.selected_gradient {
selected_gradient.transform.translation += shift;
}
@@ -494,7 +498,7 @@ impl Fsm for GradientToolFsmState {
let was_dragging = tool_data.selected_gradient.is_some();
if !was_dragging {
if let Some(selected_layer) = document.click(input) {
if let Some(selected_layer) = document.click(input, viewport) {
if let Some(gradient) = get_gradient(selected_layer, &document.network_interface) {
tool_data.selected_gradient = Some(SelectedGradient::new(gradient, selected_layer, document));
}
@@ -701,6 +701,7 @@ impl PathToolData {
shape_editor: &mut ShapeState,
document: &DocumentMessageHandler,
input: &InputPreprocessorMessageHandler,
viewport: &ViewportMessageHandler,
responses: &mut VecDeque<Message>,
extend_selection: bool,
lasso_select: bool,
@@ -871,7 +872,7 @@ impl PathToolData {
}
}
// If no other layers are selected and this is a single-click, then also select the layer (exception)
else if let Some(layer) = document.click(input) {
else if let Some(layer) = document.click(input, viewport) {
if shape_editor.selected_shape_state.is_empty() {
self.first_selected_with_single_click = true;
// This ensures we don't need to double click a second time to get the drill through to work
@@ -1109,8 +1110,9 @@ impl PathToolData {
handle_position: DVec2,
document: &DocumentMessageHandler,
input: &InputPreprocessorMessageHandler,
viewport: &ViewportMessageHandler,
) -> DVec2 {
let snap_data = SnapData::new(document, input);
let snap_data = SnapData::new(document, input, viewport);
let snap_point = SnapCandidatePoint::handle_neighbors(new_handle_position, [anchor_position]);
let snap_result = match using_angle_constraints {
@@ -1380,6 +1382,7 @@ impl PathToolData {
shape_editor: &mut ShapeState,
document: &DocumentMessageHandler,
input: &InputPreprocessorMessageHandler,
viewport: &ViewportMessageHandler,
responses: &mut VecDeque<Message>,
) {
// First check if selection is not just a single handle point
@@ -1430,9 +1433,10 @@ impl PathToolData {
handle_position,
document,
input,
viewport,
)
} else {
shape_editor.snap(&mut self.snap_manager, &self.snap_cache, document, input, previous_mouse)
shape_editor.snap(&mut self.snap_manager, &self.snap_cache, document, input, viewport, previous_mouse)
};
let handle_lengths = if equidistant { None } else { self.opposing_handle_lengths.take() };
@@ -1538,7 +1542,13 @@ impl Fsm for PathToolFsmState {
tool_options: &Self::ToolOptions,
responses: &mut VecDeque<Message>,
) -> Self {
let ToolActionMessageContext { document, input, shape_editor, .. } = tool_action_data;
let ToolActionMessageContext {
document,
input,
viewport,
shape_editor,
..
} = tool_action_data;
update_dynamic_hints(self, responses, shape_editor, document, tool_data, tool_options, input.mouse.position);
@@ -1939,13 +1949,13 @@ impl Fsm for PathToolFsmState {
}
}
Self::Dragging(_) => {
tool_data.snap_manager.draw_overlays(SnapData::new(document, input), &mut overlay_context);
tool_data.snap_manager.draw_overlays(SnapData::new(document, input, viewport), &mut overlay_context);
// Draw the snapping axis lines
if tool_data.snapping_axis.is_some() {
let Some(axis) = tool_data.snapping_axis else { return self };
let origin = tool_data.drag_start_pos;
let viewport_diagonal = input.viewport_bounds.size().length();
let viewport_diagonal = viewport.size().into_dvec2().length();
let faded = |color: &str| {
let mut color = graphene_std::Color::from_rgb_str(color.strip_prefix('#').unwrap()).unwrap().with_alpha(0.25).to_rgba_hex_srgb();
@@ -1996,6 +2006,7 @@ impl Fsm for PathToolFsmState {
shape_editor,
document,
input,
viewport,
responses,
extend_selection,
lasso_select,
@@ -2056,7 +2067,7 @@ impl Fsm for PathToolFsmState {
}
.into(),
];
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
tool_data.auto_panning.setup_by_mouse_position(input, viewport, &messages, responses);
PathToolFsmState::Drawing { selection_shape }
}
@@ -2144,6 +2155,7 @@ impl Fsm for PathToolFsmState {
tool_action_data.shape_editor,
tool_action_data.document,
input,
viewport,
responses,
);
}
@@ -2173,7 +2185,7 @@ impl Fsm for PathToolFsmState {
}
.into(),
];
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
tool_data.auto_panning.setup_by_mouse_position(input, viewport, &messages, responses);
PathToolFsmState::Dragging(tool_data.dragging_state)
}
@@ -2203,7 +2215,7 @@ impl Fsm for PathToolFsmState {
// When moving the cursor around we want to update the hovered layers
let new_hovered_layers: Vec<LayerNodeIdentifier> = document
.click_list_no_parents(input)
.click_list_no_parents(input, viewport)
.filter(|&layer| {
// Filter out artboards and parent holders, and already selected layers
!document.network_interface.is_artboard(&layer.to_node(), &[])
@@ -2220,7 +2232,7 @@ impl Fsm for PathToolFsmState {
}
(PathToolFsmState::Drawing { selection_shape: selection_type }, PathToolMessage::PointerOutsideViewport { .. }) => {
// Auto-panning
if let Some(offset) = tool_data.auto_panning.shift_viewport(input, responses) {
if let Some(offset) = tool_data.auto_panning.shift_viewport(input, viewport, responses) {
tool_data.drag_start_pos += offset;
}
@@ -2228,7 +2240,7 @@ impl Fsm for PathToolFsmState {
}
(PathToolFsmState::Dragging(dragging_state), PathToolMessage::PointerOutsideViewport { .. }) => {
// Auto-panning
if let Some(offset) = tool_data.auto_panning.shift_viewport(input, responses) {
if let Some(offset) = tool_data.auto_panning.shift_viewport(input, viewport, responses) {
tool_data.drag_start_pos += offset;
}
@@ -2388,7 +2400,7 @@ impl Fsm for PathToolFsmState {
if tool_data.drag_start_pos.distance(previous_mouse) < 1e-8 {
// Clicked inside or outside the shape then deselect all of the points/segments
if document.click(input).is_some() && tool_data.stored_selection.is_none() {
if document.click(input, viewport).is_some() && tool_data.stored_selection.is_none() {
tool_data.stored_selection = Some(shape_editor.selected_shape_state.clone());
}
@@ -2941,7 +2953,7 @@ impl Fsm for PathToolFsmState {
let nearest_point = shape_editor.find_nearest_point_indices(&document.network_interface, input.mouse.position, SELECTION_THRESHOLD);
let mut get_drill_through_layer = || -> Option<LayerNodeIdentifier> {
let drill_through_layers = document.click_list_no_parents(input).collect::<Vec<LayerNodeIdentifier>>();
let drill_through_layers = document.click_list_no_parents(input, viewport).collect::<Vec<LayerNodeIdentifier>>();
if drill_through_layers.is_empty() {
tool_data.reset_drill_through_cycle();
None
@@ -612,7 +612,7 @@ impl PenToolData {
self.handle_end = None;
self.handle_mode = HandleMode::Free;
self.store_clicked_endpoint(document, &transform, snap_data.input, preferences);
self.store_clicked_endpoint(document, &transform, snap_data.input, snap_data.viewport, preferences);
if self.modifiers.lock_angle {
self.set_lock_angle(&vector, id, self.prior_segment);
@@ -668,7 +668,7 @@ impl PenToolData {
self.handle_end_offset = None;
self.path_closed = true;
self.next_handle_start = self.next_point;
self.store_clicked_endpoint(document, transform, snap_data.input, preferences);
self.store_clicked_endpoint(document, transform, snap_data.input, snap_data.viewport, preferences);
self.handle_mode = HandleMode::Free;
if let (true, Some(prior_endpoint)) = (self.modifiers.lock_angle, self.prior_segment_endpoint) {
self.set_lock_angle(vector, prior_endpoint, self.prior_segment);
@@ -802,13 +802,14 @@ impl PenToolData {
mouse: &DVec2,
vector: &Vector,
input: &InputPreprocessorMessageHandler,
viewport: &ViewportMessageHandler,
) -> Option<DVec2> {
let reference_handle = if self.path_closed { TargetHandle::PreviewInHandle } else { TargetHandle::FuturePreviewOutHandle };
let end_handle = self.get_opposite_handle_type(reference_handle, vector);
let end_handle_pos = self.target_handle_position(end_handle, vector);
let ref_pos = self.target_handle_position(reference_handle, vector)?;
let snap = &mut self.snap_manager;
let snap_data = SnapData::new_snap_cache(snap_data.document, input, &self.snap_cache);
let snap_data = SnapData::new_snap_cache(snap_data.document, input, viewport, &self.snap_cache);
let handle_start_offset = self.handle_start_offset.unwrap_or(DVec2::ZERO);
let document_pos = viewport_to_document.transform_point2(*mouse + handle_start_offset);
@@ -964,6 +965,7 @@ impl PenToolData {
}
}
#[allow(clippy::too_many_arguments)]
fn drag_handle(
&mut self,
snap_data: SnapData,
@@ -972,6 +974,7 @@ impl PenToolData {
responses: &mut VecDeque<Message>,
layer: Option<LayerNodeIdentifier>,
input: &InputPreprocessorMessageHandler,
viewport: &ViewportMessageHandler,
) -> Option<PenToolFsmState> {
let colinear = (self.handle_mode == HandleMode::ColinearEquidistant && self.modifiers.break_handle) || (self.handle_mode == HandleMode::ColinearLocked && !self.modifiers.break_handle);
let document = snap_data.document;
@@ -982,7 +985,7 @@ impl PenToolData {
// Handles pressing Space to drag anchor and its handles
if self.modifiers.move_anchor_with_handles {
let Some(delta) = self.space_anchor_handle_snap(&viewport_to_document, &transform, &snap_data, &mouse, &vector, input) else {
let Some(delta) = self.space_anchor_handle_snap(&viewport_to_document, &transform, &snap_data, &mouse, &vector, input, viewport) else {
return Some(PenToolFsmState::DraggingHandle(self.handle_mode));
};
@@ -1221,6 +1224,7 @@ impl PenToolData {
&mut self,
document: &DocumentMessageHandler,
input: &InputPreprocessorMessageHandler,
viewport: &ViewportMessageHandler,
responses: &mut VecDeque<Message>,
tool_options: &PenOptions,
append: bool,
@@ -1228,21 +1232,21 @@ impl PenToolData {
shape_editor: &mut ShapeState,
) {
let point = SnapCandidatePoint::handle(document.metadata().document_to_viewport.inverse().transform_point2(input.mouse.position));
let snapped = self.snap_manager.free_snap(&SnapData::new(document, input), &point, SnapTypeConfiguration::default());
let viewport = document.metadata().document_to_viewport.transform_point2(snapped.snapped_point_document);
let snapped = self.snap_manager.free_snap(&SnapData::new(document, input, viewport), &point, SnapTypeConfiguration::default());
let viewport_vec = document.metadata().document_to_viewport.transform_point2(snapped.snapped_point_document);
self.handle_type = TargetHandle::FuturePreviewOutHandle;
let selected_nodes = document.network_interface.selected_nodes();
self.handle_end = None;
let tolerance = crate::consts::SNAP_POINT_TOLERANCE;
let extension_choice = should_extend(document, viewport, tolerance, selected_nodes.selected_layers(document.metadata()), preferences);
let extension_choice = should_extend(document, viewport_vec, tolerance, selected_nodes.selected_layers(document.metadata()), preferences);
if let Some((layer, point, position)) = extension_choice {
self.current_layer = Some(layer);
self.extend_existing_path(document, layer, point, position);
return;
} else if preferences.vector_meshes {
if let Some(closest_segment) = shape_editor.upper_closest_segment(&document.network_interface, viewport, tolerance) {
if let Some(closest_segment) = shape_editor.upper_closest_segment(&document.network_interface, viewport_vec, tolerance) {
let (point, segments) = closest_segment.adjusted_insert(responses);
let layer = closest_segment.layer();
let position = closest_segment.closest_point_document();
@@ -1258,7 +1262,7 @@ impl PenToolData {
}
if append {
if let Some((layer, point, _)) = closest_point(document, viewport, tolerance, document.metadata().all_layers(), |_| false, preferences) {
if let Some((layer, point, _)) = closest_point(document, viewport_vec, tolerance, document.metadata().all_layers(), |_| false, preferences) {
let vector = document.network_interface.compute_modified_vector(layer).unwrap();
let segment = vector.all_connected(point).collect::<Vec<_>>().first().map(|s| s.segment);
@@ -1271,12 +1275,12 @@ impl PenToolData {
let existing_layer = selected_layers_except_artboards.next().filter(|_| selected_layers_except_artboards.next().is_none());
if let Some(layer) = existing_layer {
// Add point to existing layer
responses.add(PenToolMessage::AddPointLayerPosition { layer, viewport });
responses.add(PenToolMessage::AddPointLayerPosition { layer, viewport: viewport_vec });
return;
}
}
if let Some((layer, point, _position)) = closest_point(document, viewport, tolerance, document.metadata().all_layers(), |_| false, preferences) {
if let Some((layer, point, _position)) = closest_point(document, viewport_vec, tolerance, document.metadata().all_layers(), |_| false, preferences) {
let vector = document.network_interface.compute_modified_vector(layer).unwrap();
let segment = vector.all_connected(point).collect::<Vec<_>>().first().map(|s| s.segment);
self.handle_mode = HandleMode::Free;
@@ -1290,7 +1294,7 @@ impl PenToolData {
let node_type = resolve_document_node_type("Path").expect("Path node does not exist");
let nodes = vec![(NodeId(0), node_type.default_node_template())];
let parent = document.new_layer_bounding_artboard(input);
let parent = document.new_layer_bounding_artboard(input, viewport);
let layer = graph_modification_utils::new_custom(NodeId::new(), nodes, parent, responses);
self.current_layer = Some(layer);
tool_options.fill.apply_fill(layer, responses);
@@ -1301,7 +1305,7 @@ impl PenToolData {
// It is necessary to defer this until the transform of the layer can be accurately computed (quite hacky)
responses.add(DeferMessage::AfterGraphRun {
messages: vec![PenToolMessage::AddPointLayerPosition { layer, viewport }.into()],
messages: vec![PenToolMessage::AddPointLayerPosition { layer, viewport: viewport_vec }.into()],
});
responses.add(NodeGraphMessage::RunDocumentGraph);
}
@@ -1360,14 +1364,21 @@ impl PenToolData {
}
// Stores the segment and point ID of the clicked endpoint
fn store_clicked_endpoint(&mut self, document: &DocumentMessageHandler, transform: &DAffine2, input: &InputPreprocessorMessageHandler, preferences: &PreferencesMessageHandler) {
fn store_clicked_endpoint(
&mut self,
document: &DocumentMessageHandler,
transform: &DAffine2,
input: &InputPreprocessorMessageHandler,
viewport: &ViewportMessageHandler,
preferences: &PreferencesMessageHandler,
) {
let mut manipulators = HashMap::with_hasher(NoHashBuilder);
let mut unselected = Vec::new();
let mut layer_manipulators = HashSet::with_hasher(NoHashBuilder);
let point = SnapCandidatePoint::handle(document.metadata().document_to_viewport.inverse().transform_point2(input.mouse.position));
let snapped = self.snap_manager.free_snap(&SnapData::new(document, input), &point, SnapTypeConfiguration::default());
let snapped = self.snap_manager.free_snap(&SnapData::new(document, input, viewport), &point, SnapTypeConfiguration::default());
let viewport = document.metadata().document_to_viewport.transform_point2(snapped.snapped_point_document);
let tolerance = crate::consts::SNAP_POINT_TOLERANCE;
@@ -1456,6 +1467,7 @@ impl Fsm for PenToolFsmState {
input,
shape_editor,
preferences,
viewport,
..
} = tool_action_data;
let selected_nodes = document.network_interface.selected_nodes();
@@ -1613,19 +1625,19 @@ impl Fsm for PenToolFsmState {
// If not check if there is a closest segment within threshold, if yes then draw overlay
let tolerance = crate::consts::SNAP_POINT_TOLERANCE;
let point = SnapCandidatePoint::handle(document.metadata().document_to_viewport.inverse().transform_point2(input.mouse.position));
let snapped = tool_data.snap_manager.free_snap(&SnapData::new(document, input), &point, SnapTypeConfiguration::default());
let viewport = document.metadata().document_to_viewport.transform_point2(snapped.snapped_point_document);
let snapped = tool_data.snap_manager.free_snap(&SnapData::new(document, input, viewport), &point, SnapTypeConfiguration::default());
let viewport_vec = document.metadata().document_to_viewport.transform_point2(snapped.snapped_point_document);
let close_to_point = closest_point(document, viewport, tolerance, document.metadata().all_layers(), |_| false, preferences).is_some();
let close_to_point = closest_point(document, viewport_vec, tolerance, document.metadata().all_layers(), |_| false, preferences).is_some();
if preferences.vector_meshes && !close_to_point {
if let Some(closest_segment) = shape_editor.upper_closest_segment(&document.network_interface, viewport, tolerance) {
if let Some(closest_segment) = shape_editor.upper_closest_segment(&document.network_interface, viewport_vec, tolerance) {
let pos = closest_segment.closest_point_to_viewport();
let perp = closest_segment.calculate_perp(document);
overlay_context.manipulator_anchor(pos, true, None);
overlay_context.line(pos - perp * SEGMENT_OVERLAY_SIZE, pos + perp * SEGMENT_OVERLAY_SIZE, Some(COLOR_OVERLAY_BLUE), None);
}
}
tool_data.snap_manager.draw_overlays(SnapData::new(document, input), &mut overlay_context);
tool_data.snap_manager.draw_overlays(SnapData::new(document, input, viewport), &mut overlay_context);
self
}
(_, PenToolMessage::Overlays { context: mut overlay_context }) => {
@@ -1743,7 +1755,7 @@ impl Fsm for PenToolFsmState {
if self == PenToolFsmState::PlacingAnchor && preferences.vector_meshes {
let tolerance = crate::consts::SNAP_POINT_TOLERANCE;
let point = SnapCandidatePoint::handle(document.metadata().document_to_viewport.inverse().transform_point2(input.mouse.position));
let snapped = tool_data.snap_manager.free_snap(&SnapData::new(document, input), &point, SnapTypeConfiguration::default());
let snapped = tool_data.snap_manager.free_snap(&SnapData::new(document, input, viewport), &point, SnapTypeConfiguration::default());
let viewport = document.metadata().document_to_viewport.transform_point2(snapped.snapped_point_document);
let close_to_point = closest_point(document, viewport, tolerance, document.metadata().all_layers(), |_| false, preferences).is_some();
if !close_to_point {
@@ -1805,7 +1817,7 @@ impl Fsm for PenToolFsmState {
}
// Draw the overlays that visualize current snapping
tool_data.snap_manager.draw_overlays(SnapData::new(document, input), &mut overlay_context);
tool_data.snap_manager.draw_overlays(SnapData::new(document, input, viewport), &mut overlay_context);
self
}
@@ -1822,8 +1834,8 @@ impl Fsm for PenToolFsmState {
// Get the closest point and the segment it is on
let append = input.keyboard.key(append_to_selected);
tool_data.store_clicked_endpoint(document, &transform, input, preferences);
tool_data.create_initial_point(document, input, responses, tool_options, append, preferences, shape_editor);
tool_data.store_clicked_endpoint(document, &transform, input, viewport, preferences);
tool_data.create_initial_point(document, input, viewport, responses, tool_options, append, preferences, shape_editor);
// Enter the dragging handle state while the mouse is held down, allowing the user to move the mouse and position the handle
PenToolFsmState::DraggingHandle(tool_data.handle_mode)
@@ -1839,16 +1851,16 @@ impl Fsm for PenToolFsmState {
}
(PenToolFsmState::PlacingAnchor, PenToolMessage::DragStart { append_to_selected }) => {
let point = SnapCandidatePoint::handle(document.metadata().document_to_viewport.inverse().transform_point2(input.mouse.position));
let snapped = tool_data.snap_manager.free_snap(&SnapData::new(document, input), &point, SnapTypeConfiguration::default());
let viewport = document.metadata().document_to_viewport.transform_point2(snapped.snapped_point_document);
let snapped = tool_data.snap_manager.free_snap(&SnapData::new(document, input, viewport), &point, SnapTypeConfiguration::default());
let viewport_vec = document.metadata().document_to_viewport.transform_point2(snapped.snapped_point_document);
// Early return if the buffer was started and this message is being run again after the buffer (so that place_anchor updates the state with the newly merged vector)
if tool_data.buffering_merged_vector {
if let Some(layer) = layer {
tool_data.buffering_merged_vector = false;
tool_data.handle_mode = HandleMode::ColinearLocked;
tool_data.bend_from_previous_point(SnapData::new(document, input), transform, layer, preferences, shape_editor, responses);
tool_data.place_anchor(SnapData::new(document, input), transform, input.mouse.position, preferences, responses);
tool_data.bend_from_previous_point(SnapData::new(document, input, viewport), transform, layer, preferences, shape_editor, responses);
tool_data.place_anchor(SnapData::new(document, input, viewport), transform, input.mouse.position, preferences, responses);
}
tool_data.buffering_merged_vector = false;
PenToolFsmState::DraggingHandle(tool_data.handle_mode)
@@ -1863,7 +1875,7 @@ impl Fsm for PenToolFsmState {
let layers = LayerNodeIdentifier::ROOT_PARENT
.descendants(document.metadata())
.filter(|layer| !document.network_interface.is_artboard(&layer.to_node(), &[]));
if let Some((other_layer, _, _)) = should_extend(document, viewport, crate::consts::SNAP_POINT_TOLERANCE, layers, preferences) {
if let Some((other_layer, _, _)) = should_extend(document, viewport_vec, crate::consts::SNAP_POINT_TOLERANCE, layers, preferences) {
let selected_nodes = document.network_interface.selected_nodes();
let mut selected_layers = selected_nodes.selected_layers(document.metadata());
if let Some(current_layer) = selected_layers
@@ -1893,7 +1905,7 @@ impl Fsm for PenToolFsmState {
(PenToolFsmState::DraggingHandle(_), PenToolMessage::DragStop) => {
tool_data.cleanup_target_selections(shape_editor, layer, document, responses);
tool_data
.finish_placing_handle(SnapData::new(document, input), transform, preferences, responses)
.finish_placing_handle(SnapData::new(document, input, viewport), transform, preferences, responses)
.unwrap_or(PenToolFsmState::PlacingAnchor)
}
(
@@ -1914,7 +1926,7 @@ impl Fsm for PenToolFsmState {
move_anchor_with_handles: input.keyboard.key(move_anchor_with_handles),
};
let snap_data = SnapData::new(document, input);
let snap_data = SnapData::new(document, input, viewport);
if tool_data.modifiers.colinear && !tool_data.toggle_colinear_debounce {
tool_data.handle_mode = match tool_data.handle_mode {
HandleMode::Free => {
@@ -1962,7 +1974,7 @@ impl Fsm for PenToolFsmState {
}
let state = tool_data
.drag_handle(snap_data, transform, input.mouse.position, responses, layer, input)
.drag_handle(snap_data, transform, input.mouse.position, responses, layer, input, viewport)
.unwrap_or(PenToolFsmState::Ready);
if tool_data.handle_swapped {
@@ -1988,7 +2000,7 @@ impl Fsm for PenToolFsmState {
}
.into(),
];
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
tool_data.auto_panning.setup_by_mouse_position(input, viewport, &messages, responses);
state
}
@@ -2012,7 +2024,7 @@ impl Fsm for PenToolFsmState {
move_anchor_with_handles: input.keyboard.key(move_anchor_with_handles),
};
let state = tool_data
.place_anchor(SnapData::new(document, input), transform, input.mouse.position, preferences, responses)
.place_anchor(SnapData::new(document, input, viewport), transform, input.mouse.position, preferences, responses)
.unwrap_or(PenToolFsmState::Ready);
// Auto-panning
@@ -2034,7 +2046,7 @@ impl Fsm for PenToolFsmState {
}
.into(),
];
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
tool_data.auto_panning.setup_by_mouse_position(input, viewport, &messages, responses);
state
}
@@ -2063,13 +2075,13 @@ impl Fsm for PenToolFsmState {
colinear: input.keyboard.key(colinear),
move_anchor_with_handles: input.keyboard.key(move_anchor_with_handles),
};
tool_data.snap_manager.preview_draw(&SnapData::new(document, input), input.mouse.position);
tool_data.snap_manager.preview_draw(&SnapData::new(document, input, viewport), input.mouse.position);
responses.add(OverlaysMessage::Draw);
self
}
(PenToolFsmState::DraggingHandle(mode), PenToolMessage::PointerOutsideViewport { .. }) => {
// Auto-panning
let _ = tool_data.auto_panning.shift_viewport(input, responses);
let _ = tool_data.auto_panning.shift_viewport(input, viewport, responses);
PenToolFsmState::DraggingHandle(mode)
}
@@ -2078,7 +2090,7 @@ impl Fsm for PenToolFsmState {
return self;
}
// Auto-panning
let _ = tool_data.auto_panning.shift_viewport(input, responses);
let _ = tool_data.auto_panning.shift_viewport(input, viewport, responses);
PenToolFsmState::PlacingAnchor
}
@@ -2119,7 +2131,7 @@ impl Fsm for PenToolFsmState {
// Confirm to end path
if let Some((vector, layer)) = layer.and_then(|layer| document.network_interface.compute_modified_vector(layer)).zip(layer) {
let single_point_in_layer = vector.point_domain.ids().len() == 1;
tool_data.finish_placing_handle(SnapData::new(document, input), transform, preferences, responses);
tool_data.finish_placing_handle(SnapData::new(document, input, viewport), transform, preferences, responses);
let latest_points = tool_data.latest_points.len() == 1;
if latest_points && single_point_in_layer {
@@ -2166,7 +2178,7 @@ impl Fsm for PenToolFsmState {
PenToolFsmState::Ready
} else {
tool_data
.place_anchor(SnapData::new(document, input), transform, input.mouse.position, preferences, responses)
.place_anchor(SnapData::new(document, input, viewport), transform, input.mouse.position, preferences, responses)
.unwrap_or(PenToolFsmState::Ready)
}
}
@@ -2197,7 +2209,7 @@ impl Fsm for PenToolFsmState {
if tool_data.point_index > 0 {
tool_data.point_index -= 1;
tool_data
.place_anchor(SnapData::new(document, input), transform, input.mouse.position, preferences, responses)
.place_anchor(SnapData::new(document, input, viewport), transform, input.mouse.position, preferences, responses)
.unwrap_or(PenToolFsmState::PlacingAnchor)
} else {
responses.add(PenToolMessage::Abort);
@@ -2206,7 +2218,7 @@ impl Fsm for PenToolFsmState {
}
(_, PenToolMessage::Redo) => {
tool_data.point_index = (tool_data.point_index + 1).min(tool_data.latest_points.len().saturating_sub(1));
tool_data.place_anchor(SnapData::new(document, input), transform, input.mouse.position, preferences, responses);
tool_data.place_anchor(SnapData::new(document, input, viewport), transform, input.mouse.position, preferences, responses);
match tool_data.point_index {
0 => PenToolFsmState::Ready,
_ => PenToolFsmState::PlacingAnchor,
@@ -419,11 +419,11 @@ struct SelectToolData {
}
impl SelectToolData {
fn get_snap_candidates(&mut self, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler) {
fn get_snap_candidates(&mut self, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, viewport: &ViewportMessageHandler) {
self.snap_candidates.clear();
for &layer in &self.layers_dragging {
if (self.snap_candidates.len() as f64) < document.snapping_state.tolerance {
snapping::get_layer_snap_points(layer, &SnapData::new(document, input), &mut self.snap_candidates);
snapping::get_layer_snap_points(layer, &SnapData::new(document, input, viewport), &mut self.snap_candidates);
}
if let Some(bounds) = document.metadata().bounding_box_with_transform(layer, DAffine2::IDENTITY) {
let quad = document.metadata().transform_to_document(layer) * Quad::from_box(bounds);
@@ -463,20 +463,20 @@ impl SelectToolData {
}
}
pub fn intersect_lasso_no_artboards(&self, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler) -> Vec<LayerNodeIdentifier> {
pub fn intersect_lasso_no_artboards(&self, document: &DocumentMessageHandler, viewport: &ViewportMessageHandler) -> Vec<LayerNodeIdentifier> {
if self.lasso_polygon.len() < 2 {
return Vec::new();
}
let polygon = Subpath::from_anchors_linear(self.lasso_polygon.clone(), true);
document.intersect_polygon_no_artboards(polygon, input).collect()
document.intersect_polygon_no_artboards(polygon, viewport).collect()
}
pub fn is_layer_inside_lasso_polygon(&self, layer: &LayerNodeIdentifier, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler) -> bool {
pub fn is_layer_inside_lasso_polygon(&self, layer: &LayerNodeIdentifier, document: &DocumentMessageHandler, viewport: &ViewportMessageHandler) -> bool {
if self.lasso_polygon.len() < 2 {
return false;
}
let polygon = Subpath::from_anchors_linear(self.lasso_polygon.clone(), true);
document.is_layer_fully_inside_polygon(layer, input, polygon)
document.is_layer_fully_inside_polygon(layer, viewport, polygon)
}
/// Duplicates the currently dragging layers. Called when Alt is pressed and the layers have not yet been duplicated.
@@ -598,12 +598,18 @@ impl Fsm for SelectToolFsmState {
type ToolOptions = ();
fn transition(self, event: ToolMessage, tool_data: &mut Self::ToolData, tool_action_data: &mut ToolActionMessageContext, _tool_options: &(), responses: &mut VecDeque<Message>) -> Self {
let ToolActionMessageContext { document, input, font_cache, .. } = tool_action_data;
let ToolActionMessageContext {
document,
input,
viewport,
font_cache,
..
} = tool_action_data;
let ToolMessage::Select(event) = event else { return self };
match (self, event) {
(_, SelectToolMessage::Overlays { context: mut overlay_context }) => {
tool_data.snap_manager.draw_overlays(SnapData::new(document, input), &mut overlay_context);
tool_data.snap_manager.draw_overlays(SnapData::new(document, input, viewport), &mut overlay_context);
let selected_layers_count = document.network_interface.selected_nodes().selected_unlocked_layers(&document.network_interface).count();
tool_data.selected_layers_changed = selected_layers_count != tool_data.selected_layers_count;
@@ -661,7 +667,7 @@ impl Fsm for SelectToolFsmState {
if !matches!(self, Self::Drawing { .. }) && !input.keyboard.get(Key::MouseMiddle as usize) {
// Get the layer the user is hovering over
// Artboards are included since they're needed for quick measurement, but will be filtered out for selection later on
let click = document.click_list_with_artboards(input).last();
let click = document.click_list_with_artboards(input, viewport).last();
let not_selected_click = click.filter(|&hovered_layer| !document.network_interface.selected_nodes().selected_layers_contains(hovered_layer, document.metadata()));
if let Some(layer) = not_selected_click {
if overlay_context.visibility_settings.hover_outline() && !document.network_interface.is_artboard(&layer.to_node(), &[]) {
@@ -896,7 +902,7 @@ impl Fsm for SelectToolFsmState {
_ => unreachable!(),
};
let viewport_diagonal = input.viewport_bounds.size().length();
let viewport_diagonal = viewport.size().into_dvec2().length();
let color = if !hover {
color
@@ -918,7 +924,7 @@ impl Fsm for SelectToolFsmState {
let extension = tool_data.drag_current - tool_data.drag_start;
let origin = compass_center - extension;
let viewport_diagonal = input.viewport_bounds.size().length();
let viewport_diagonal = viewport.size().into_dvec2().length();
let edge = DVec2::from_angle(snapped_angle).normalize_or(DVec2::X) * viewport_diagonal;
let perp = edge.perp();
@@ -949,13 +955,13 @@ impl Fsm for SelectToolFsmState {
// Draw outline visualizations on the layers to be selected
let intersected_layers = match selection_shape {
SelectionShapeType::Box => document.intersect_quad_no_artboards(quad, input).collect(),
SelectionShapeType::Lasso => tool_data.intersect_lasso_no_artboards(document, input),
SelectionShapeType::Box => document.intersect_quad_no_artboards(quad, viewport).collect(),
SelectionShapeType::Lasso => tool_data.intersect_lasso_no_artboards(document, viewport),
};
let layers_to_outline = intersected_layers.into_iter().filter(|layer| match current_selection_mode {
SelectionMode::Enclosed => match selection_shape {
SelectionShapeType::Box => document.is_layer_fully_inside(layer, quad),
SelectionShapeType::Lasso => tool_data.is_layer_inside_lasso_polygon(layer, document, input),
SelectionShapeType::Lasso => tool_data.is_layer_inside_lasso_polygon(layer, document, viewport),
},
SelectionMode::Touched => match tool_data.nested_selection_behavior {
NestedSelectionBehavior::Deepest => !layer.has_children(document.metadata()),
@@ -1008,7 +1014,7 @@ impl Fsm for SelectToolFsmState {
self
}
(_, SelectToolMessage::EditLayerExec) => {
if let Some(intersect) = document.click(input) {
if let Some(intersect) = document.click(input, viewport) {
match tool_data.nested_selection_behavior {
NestedSelectionBehavior::Shallowest => edit_layer_shallowest_manipulation(document, intersect, responses),
NestedSelectionBehavior::Deepest => edit_layer_deepest_manipulation(intersect, &document.network_interface, responses),
@@ -1031,7 +1037,7 @@ impl Fsm for SelectToolFsmState {
tool_data.selection_mode = None;
let mut selected: Vec<_> = document.network_interface.selected_nodes().selected_visible_and_unlocked_layers(&document.network_interface).collect();
let intersection_list = document.click_list(input).collect::<Vec<_>>();
let intersection_list = document.click_list(input, viewport).collect::<Vec<_>>();
let intersection = document.find_deepest(&intersection_list);
let position = tool_data.pivot_gizmo().position(document);
@@ -1064,10 +1070,10 @@ impl Fsm for SelectToolFsmState {
}
// Dragging one (or two, forming a corner) of the transform cage bounding box edges
else if resize {
tool_data.get_snap_candidates(document, input);
tool_data.get_snap_candidates(document, input, viewport);
SelectToolFsmState::ResizingBounds
} else if skew {
tool_data.get_snap_candidates(document, input);
tool_data.get_snap_candidates(document, input, viewport);
SelectToolFsmState::SkewingBounds { skew: Key::Control }
}
// Dragging the selected layers around to transform them
@@ -1081,7 +1087,7 @@ impl Fsm for SelectToolFsmState {
}
tool_data.layers_dragging = selected;
tool_data.get_snap_candidates(document, input);
tool_data.get_snap_candidates(document, input, viewport);
let (axis, using_compass) = {
let axis_state = compass_rose_state.axis_type().filter(|_| can_grab_compass_rose);
(axis_state.unwrap_or_default(), axis_state.is_some())
@@ -1124,7 +1130,7 @@ impl Fsm for SelectToolFsmState {
NestedSelectionBehavior::Shallowest if !input.keyboard.key(select_deepest) => drag_shallowest_manipulation(responses, selected, tool_data, document, false, extend),
_ => drag_deepest_manipulation(responses, selected, tool_data, document, false),
}
tool_data.get_snap_candidates(document, input);
tool_data.get_snap_candidates(document, input, viewport);
responses.add(DocumentMessage::StartTransaction);
@@ -1177,7 +1183,7 @@ impl Fsm for SelectToolFsmState {
let layers_exist = tool_data.layers_dragging.iter().all(|&layer| document.metadata().click_targets(layer).is_some());
let ignore = tool_data.non_duplicated_layers.as_ref().filter(|_| !layers_exist).unwrap_or(&tool_data.layers_dragging);
let snap_data = SnapData::ignore(document, input, ignore);
let snap_data = SnapData::ignore(document, input, viewport, ignore);
let (start, current) = (tool_data.drag_start, tool_data.drag_current);
let e0 = tool_data
.bounding_box_manager
@@ -1208,7 +1214,7 @@ impl Fsm for SelectToolFsmState {
SelectToolMessage::PointerOutsideViewport { modifier_keys: modifier_keys.clone() }.into(),
SelectToolMessage::PointerMove { modifier_keys }.into(),
];
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
tool_data.auto_panning.setup_by_mouse_position(input, viewport, &messages, responses);
SelectToolFsmState::Dragging {
axis,
@@ -1228,6 +1234,7 @@ impl Fsm for SelectToolFsmState {
&mut tool_data.snap_manager,
&mut tool_data.snap_candidates,
input,
viewport,
input.keyboard.key(modifier_keys.center),
input.keyboard.key(modifier_keys.axis_align),
ToolType::Select,
@@ -1236,7 +1243,7 @@ impl Fsm for SelectToolFsmState {
SelectToolMessage::PointerOutsideViewport { modifier_keys: modifier_keys.clone() }.into(),
SelectToolMessage::PointerMove { modifier_keys }.into(),
];
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
tool_data.auto_panning.setup_by_mouse_position(input, viewport, &messages, responses);
}
SelectToolFsmState::ResizingBounds
}
@@ -1283,7 +1290,7 @@ impl Fsm for SelectToolFsmState {
SelectToolMessage::PointerOutsideViewport { modifier_keys: modifier_keys.clone() }.into(),
SelectToolMessage::PointerMove { modifier_keys }.into(),
];
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
tool_data.auto_panning.setup_by_mouse_position(input, viewport, &messages, responses);
SelectToolFsmState::DraggingPivot
}
@@ -1304,7 +1311,7 @@ impl Fsm for SelectToolFsmState {
SelectToolMessage::PointerOutsideViewport { modifier_keys: modifier_keys.clone() }.into(),
SelectToolMessage::PointerMove { modifier_keys }.into(),
];
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
tool_data.auto_panning.setup_by_mouse_position(input, viewport, &messages, responses);
SelectToolFsmState::Drawing { selection_shape, has_drawn: true }
}
@@ -1347,7 +1354,7 @@ impl Fsm for SelectToolFsmState {
SelectToolMessage::PointerOutsideViewport { .. },
) => {
// Auto-panning
if let Some(shift) = tool_data.auto_panning.shift_viewport(input, responses) {
if let Some(shift) = tool_data.auto_panning.shift_viewport(input, viewport, responses) {
tool_data.drag_current += shift;
tool_data.drag_start += shift;
}
@@ -1362,7 +1369,7 @@ impl Fsm for SelectToolFsmState {
}
(SelectToolFsmState::ResizingBounds | SelectToolFsmState::SkewingBounds { .. }, SelectToolMessage::PointerOutsideViewport { .. }) => {
// Auto-panning
if let Some(shift) = tool_data.auto_panning.shift_viewport(input, responses) {
if let Some(shift) = tool_data.auto_panning.shift_viewport(input, viewport, responses) {
if let Some(bounds) = &mut tool_data.bounding_box_manager {
bounds.center_of_transformation += shift;
bounds.original_bound_transform.translation += shift;
@@ -1373,13 +1380,13 @@ impl Fsm for SelectToolFsmState {
}
(SelectToolFsmState::DraggingPivot, SelectToolMessage::PointerOutsideViewport { .. }) => {
// Auto-panning
let _ = tool_data.auto_panning.shift_viewport(input, responses);
let _ = tool_data.auto_panning.shift_viewport(input, viewport, responses);
self
}
(SelectToolFsmState::Drawing { .. }, SelectToolMessage::PointerOutsideViewport { .. }) => {
// Auto-panning
if let Some(shift) = tool_data.auto_panning.shift_viewport(input, responses) {
if let Some(shift) = tool_data.auto_panning.shift_viewport(input, viewport, responses) {
tool_data.drag_start += shift;
}
@@ -1403,7 +1410,7 @@ impl Fsm for SelectToolFsmState {
if !has_dragged && input.keyboard.key(remove_from_selection) && tool_data.layer_selected_on_start.is_none() {
// When you click on the layer with remove from selection key (shift) pressed, we deselect all nodes that are children.
let quad = tool_data.selection_quad();
let intersection = document.intersect_quad_no_artboards(quad, input);
let intersection = document.intersect_quad_no_artboards(quad, viewport);
if let Some(path) = intersection.last() {
let replacement_selected_layers: Vec<_> = document
@@ -1433,7 +1440,7 @@ impl Fsm for SelectToolFsmState {
} else if tool_data.select_single_layer.take().is_some() {
// Previously, we may have had many layers selected. If the user clicks without dragging, we should just select the one layer that has been clicked.
if !has_dragged {
let selected = document.click_list(input).collect::<Vec<_>>();
let selected = document.click_list(input, viewport).collect::<Vec<_>>();
let intersection = document.find_deepest(&selected);
if let Some(intersection) = intersection {
tool_data.layer_selected_on_start = Some(intersection);
@@ -1449,7 +1456,7 @@ impl Fsm for SelectToolFsmState {
}
}
tool_data.get_snap_candidates(document, input);
tool_data.get_snap_candidates(document, input, viewport);
}
}
}
@@ -1510,13 +1517,13 @@ impl Fsm for SelectToolFsmState {
};
let intersection: Vec<LayerNodeIdentifier> = match selection_shape {
SelectionShapeType::Box => document.intersect_quad_no_artboards(quad, input).collect(),
SelectionShapeType::Lasso => tool_data.intersect_lasso_no_artboards(document, input),
SelectionShapeType::Box => document.intersect_quad_no_artboards(quad, viewport).collect(),
SelectionShapeType::Lasso => tool_data.intersect_lasso_no_artboards(document, viewport),
};
let new_selected: HashSet<_> = if selection_mode == SelectionMode::Enclosed {
let is_inside = |layer: &LayerNodeIdentifier| match selection_shape {
SelectionShapeType::Box => document.is_layer_fully_inside(layer, quad),
SelectionShapeType::Lasso => tool_data.is_layer_inside_lasso_polygon(layer, document, input),
SelectionShapeType::Lasso => tool_data.is_layer_inside_lasso_polygon(layer, document, viewport),
};
intersection.into_iter().filter(is_inside).collect()
} else {
@@ -501,11 +501,11 @@ pub struct ShapeToolData {
}
impl ShapeToolData {
fn get_snap_candidates(&mut self, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler) {
fn get_snap_candidates(&mut self, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, viewport: &ViewportMessageHandler) {
self.snap_candidates.clear();
for &layer in &self.layers_dragging {
if (self.snap_candidates.len() as f64) < document.snapping_state.tolerance {
snapping::get_layer_snap_points(layer, &SnapData::new(document, input), &mut self.snap_candidates);
snapping::get_layer_snap_points(layer, &SnapData::new(document, input, viewport), &mut self.snap_candidates);
}
if let Some(bounds) = document.metadata().bounding_box_with_transform(layer, DAffine2::IDENTITY) {
let quad = document.metadata().transform_to_document(layer) * Quad::from_box(bounds);
@@ -558,6 +558,7 @@ impl Fsm for ShapeToolFsmState {
input,
preferences,
shape_editor,
viewport,
..
}: &mut ToolActionMessageContext,
tool_options: &Self::ToolOptions,
@@ -596,7 +597,7 @@ impl Fsm for ShapeToolFsmState {
let hovering_over_gizmo = tool_data.gizmo_manager.hovering_over_gizmo();
if !matches!(self, ShapeToolFsmState::ModifyingGizmo) && !modifying_transform_cage && !hovering_over_gizmo {
tool_data.data.snap_manager.draw_overlays(SnapData::new(document, input), &mut overlay_context);
tool_data.data.snap_manager.draw_overlays(SnapData::new(document, input, viewport), &mut overlay_context);
}
if modifying_transform_cage && !matches!(self, ShapeToolFsmState::ModifyingGizmo) {
@@ -783,7 +784,7 @@ impl Fsm for ShapeToolFsmState {
match (resize, rotate, skew) {
(true, false, false) => {
tool_data.get_snap_candidates(document, input);
tool_data.get_snap_candidates(document, input, viewport);
update_cursor_and_pointer(tool_data, responses);
return ShapeToolFsmState::ResizingBounds;
@@ -795,7 +796,7 @@ impl Fsm for ShapeToolFsmState {
return ShapeToolFsmState::RotatingBounds;
}
(false, false, true) => {
tool_data.get_snap_candidates(document, input);
tool_data.get_snap_candidates(document, input, viewport);
update_cursor_and_pointer(tool_data, responses);
return ShapeToolFsmState::SkewingBounds { skew: Key::Control };
@@ -806,11 +807,14 @@ 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 => {
tool_data.data.start(document, input)
tool_data.data.start(document, input, viewport);
}
ShapeType::Line => {
let point = SnapCandidatePoint::handle(document.metadata().document_to_viewport.inverse().transform_point2(input.mouse.position));
let snapped = tool_data.data.snap_manager.free_snap(&SnapData::new(document, input), &point, SnapTypeConfiguration::default());
let snapped = tool_data
.data
.snap_manager
.free_snap(&SnapData::new(document, input, viewport), &point, SnapTypeConfiguration::default());
tool_data.data.drag_start = snapped.snapped_point_document;
}
}
@@ -830,7 +834,7 @@ impl Fsm for ShapeToolFsmState {
};
let nodes = vec![(NodeId(0), node)];
let layer = graph_modification_utils::new_custom(NodeId::new(), nodes, document.new_layer_bounding_artboard(input), responses);
let layer = graph_modification_utils::new_custom(NodeId::new(), nodes, document.new_layer_bounding_artboard(input, viewport), responses);
let defered_responses = &mut VecDeque::new();
@@ -868,20 +872,20 @@ impl Fsm for ShapeToolFsmState {
};
match tool_data.current_shape {
ShapeType::Polygon => Polygon::update_shape(document, input, layer, tool_data, modifier, responses),
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::Spiral => Spiral::update_shape(document, input, layer, tool_data, responses),
ShapeType::Polygon => Polygon::update_shape(document, input, viewport, layer, tool_data, modifier, responses),
ShapeType::Star => Star::update_shape(document, input, viewport, layer, tool_data, modifier, responses),
ShapeType::Circle => Circle::update_shape(document, input, viewport, layer, tool_data, modifier, responses),
ShapeType::Arc => Arc::update_shape(document, input, viewport, layer, tool_data, modifier, responses),
ShapeType::Spiral => Spiral::update_shape(document, input, viewport, 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),
ShapeType::Ellipse => Ellipse::update_shape(document, input, layer, tool_data, modifier, responses),
ShapeType::Line => Line::update_shape(document, input, layer, tool_data, modifier, responses),
ShapeType::Rectangle => Rectangle::update_shape(document, input, viewport, layer, tool_data, modifier, responses),
ShapeType::Ellipse => Ellipse::update_shape(document, input, viewport, layer, tool_data, modifier, responses),
ShapeType::Line => Line::update_shape(document, input, viewport, layer, tool_data, modifier, responses),
}
// Auto-panning
let messages = [ShapeToolMessage::PointerOutsideViewport { modifier }.into(), ShapeToolMessage::PointerMove { modifier }.into()];
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
tool_data.auto_panning.setup_by_mouse_position(input, viewport, &messages, responses);
self
}
@@ -890,10 +894,10 @@ impl Fsm for ShapeToolFsmState {
return ShapeToolFsmState::Ready(tool_data.current_shape);
};
Line::update_shape(document, input, layer, tool_data, modifier, responses);
Line::update_shape(document, input, viewport, layer, tool_data, modifier, responses);
// Auto-panning
let messages = [ShapeToolMessage::PointerOutsideViewport { modifier }.into(), ShapeToolMessage::PointerMove { modifier }.into()];
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
tool_data.auto_panning.setup_by_mouse_position(input, viewport, &messages, responses);
self
}
@@ -915,11 +919,12 @@ impl Fsm for ShapeToolFsmState {
&mut tool_data.data.snap_manager,
&mut tool_data.snap_candidates,
input,
viewport,
input.keyboard.key(modifier[0]),
input.keyboard.key(modifier[1]),
ToolType::Shape,
);
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
tool_data.auto_panning.setup_by_mouse_position(input, viewport, &messages, responses);
}
responses.add(OverlaysMessage::Draw);
@@ -974,14 +979,14 @@ impl Fsm for ShapeToolFsmState {
responses.add(FrontendMessage::UpdateMouseCursor { cursor });
}
tool_data.data.snap_manager.preview_draw(&SnapData::new(document, input), input.mouse.position);
tool_data.data.snap_manager.preview_draw(&SnapData::new(document, input, viewport), input.mouse.position);
responses.add(OverlaysMessage::Draw);
self
}
(ShapeToolFsmState::ResizingBounds | ShapeToolFsmState::SkewingBounds { .. }, ShapeToolMessage::PointerOutsideViewport { .. }) => {
// Auto-panning
if let Some(shift) = tool_data.auto_panning.shift_viewport(input, responses)
if let Some(shift) = tool_data.auto_panning.shift_viewport(input, viewport, responses)
&& let Some(bounds) = &mut tool_data.bounding_box_manager
{
bounds.center_of_transformation += shift;
@@ -993,7 +998,7 @@ impl Fsm for ShapeToolFsmState {
(ShapeToolFsmState::Ready(_), ShapeToolMessage::PointerOutsideViewport { .. }) => self,
(_, ShapeToolMessage::PointerOutsideViewport { .. }) => {
// Auto-panning
let _ = tool_data.auto_panning.shift_viewport(input, responses);
let _ = tool_data.auto_panning.shift_viewport(input, viewport, responses);
self
}
(
@@ -267,12 +267,12 @@ impl SplineToolData {
}
/// Get the snapped point while ignoring current layer
fn snapped_point(&mut self, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler) -> SnappedPoint {
fn snapped_point(&mut self, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, viewport: &ViewportMessageHandler) -> SnappedPoint {
let metadata = document.metadata();
let transform = self.current_layer.map_or(metadata.document_to_viewport, |layer| metadata.transform_to_viewport(layer));
let point = SnapCandidatePoint::handle(transform.inverse().transform_point2(input.mouse.position));
let ignore = if let Some(layer) = self.current_layer { vec![layer] } else { vec![] };
let snap_data = SnapData::ignore(document, input, &ignore);
let snap_data = SnapData::ignore(document, input, viewport, &ignore);
self.snap_manager.free_snap(&snap_data, &point, SnapTypeConfiguration::default())
}
}
@@ -295,6 +295,7 @@ impl Fsm for SplineToolFsmState {
input,
shape_editor,
preferences,
viewport,
..
} = tool_action_data;
@@ -303,7 +304,7 @@ impl Fsm for SplineToolFsmState {
(_, SplineToolMessage::CanvasTransformed) => self,
(_, SplineToolMessage::Overlays { context: mut overlay_context }) => {
path_endpoint_overlays(document, shape_editor, &mut overlay_context, preferences);
tool_data.snap_manager.draw_overlays(SnapData::new(document, input), &mut overlay_context);
tool_data.snap_manager.draw_overlays(SnapData::new(document, input, viewport), &mut overlay_context);
self
}
(SplineToolFsmState::MergingEndpoints, SplineToolMessage::MergeEndpoints) => {
@@ -342,15 +343,15 @@ impl Fsm for SplineToolFsmState {
tool_data.weight = tool_options.line_weight;
let point = SnapCandidatePoint::handle(document.metadata().document_to_viewport.inverse().transform_point2(input.mouse.position));
let snapped = tool_data.snap_manager.free_snap(&SnapData::new(document, input), &point, SnapTypeConfiguration::default());
let viewport = document.metadata().document_to_viewport.transform_point2(snapped.snapped_point_document);
let snapped = tool_data.snap_manager.free_snap(&SnapData::new(document, input, viewport), &point, SnapTypeConfiguration::default());
let viewport_vec = document.metadata().document_to_viewport.transform_point2(snapped.snapped_point_document);
let layers = LayerNodeIdentifier::ROOT_PARENT
.descendants(document.metadata())
.filter(|layer| !document.network_interface.is_artboard(&layer.to_node(), &[]));
// Extend an endpoint of the selected path
if let Some((layer, point, position)) = should_extend(document, viewport, SNAP_POINT_TOLERANCE, layers, preferences) {
if let Some((layer, point, position)) = should_extend(document, viewport_vec, SNAP_POINT_TOLERANCE, layers, preferences) {
if find_spline(document, layer).is_some() {
// If the point is the part of Spline then we extend it.
tool_data.current_layer = Some(layer);
@@ -386,7 +387,7 @@ impl Fsm for SplineToolFsmState {
responses.add(DocumentMessage::DeselectAllLayers);
let parent = document.new_layer_bounding_artboard(input);
let parent = document.new_layer_bounding_artboard(input, viewport);
let path_node_type = resolve_document_node_type("Path").expect("Path node does not exist");
let path_node = path_node_type.default_node_template();
@@ -410,7 +411,7 @@ impl Fsm for SplineToolFsmState {
if tool_data.current_layer.is_none() {
return SplineToolFsmState::Ready;
};
tool_data.next_point = tool_data.snapped_point(document, input).snapped_point_document;
tool_data.next_point = tool_data.snapped_point(document, input, viewport).snapped_point_document;
if tool_data.points.last().is_none_or(|last_pos| last_pos.1.distance(tool_data.next_point) > DRAG_THRESHOLD) {
let preview_point = tool_data.preview_point;
extend_spline(tool_data, false, responses);
@@ -433,7 +434,7 @@ impl Fsm for SplineToolFsmState {
tool_data.next_point = point;
tool_data.snap_manager.clear_indicator();
} else {
let snapped_point = tool_data.snapped_point(document, input);
let snapped_point = tool_data.snapped_point(document, input, viewport);
tool_data.next_point = snapped_point.snapped_point_document;
tool_data.snap_manager.update_indicator(snapped_point);
}
@@ -442,12 +443,12 @@ impl Fsm for SplineToolFsmState {
// Auto-panning
let messages = [SplineToolMessage::PointerOutsideViewport.into(), SplineToolMessage::PointerMove.into()];
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
tool_data.auto_panning.setup_by_mouse_position(input, viewport, &messages, responses);
SplineToolFsmState::Drawing
}
(_, SplineToolMessage::PointerMove) => {
tool_data.snap_manager.preview_draw(&SnapData::new(document, input), input.mouse.position);
tool_data.snap_manager.preview_draw(&SnapData::new(document, input, viewport), input.mouse.position);
responses.add(OverlaysMessage::Draw);
self
}
@@ -456,7 +457,7 @@ impl Fsm for SplineToolFsmState {
return self;
}
// Auto-panning
let _ = tool_data.auto_panning.shift_viewport(input, responses);
let _ = tool_data.auto_panning.shift_viewport(input, viewport, responses);
SplineToolFsmState::Drawing
}
@@ -499,6 +499,7 @@ impl Fsm for TextToolFsmState {
global_tool_data,
input,
font_cache,
viewport,
..
} = transition_data;
let fill_color = graphene_std::Color::from_rgb_str(COLOR_OVERLAY_BLUE.strip_prefix('#').unwrap())
@@ -509,9 +510,8 @@ impl Fsm for TextToolFsmState {
let ToolMessage::Text(event) = event else { return self };
match (self, event) {
(TextToolFsmState::Editing, TextToolMessage::Overlays { context: mut overlay_context }) => {
responses.add(FrontendMessage::DisplayEditableTextboxTransform {
transform: document.metadata().transform_to_viewport(tool_data.layer).to_cols_array(),
});
let transform = document.metadata().transform_to_viewport(tool_data.layer).to_cols_array();
responses.add(FrontendMessage::DisplayEditableTextboxTransform { transform });
if let Some(editing_text) = tool_data.editing_text.as_mut() {
let far = graphene_std::text::bounding_box(&tool_data.new_text, &editing_text.font, font_cache, editing_text.typesetting, false);
if far.x != 0. && far.y != 0. {
@@ -529,7 +529,7 @@ impl Fsm for TextToolFsmState {
let quad = Quad::from_box(tool_data.cached_resize_bounds);
// Draw a bounding box on the layers to be selected
for layer in document.intersect_quad_no_artboards(quad, input) {
for layer in document.intersect_quad_no_artboards(quad, viewport) {
overlay_context.quad(
Quad::from_box(document.metadata().bounding_box_viewport(layer).unwrap_or([DVec2::ZERO; 2])),
None,
@@ -572,7 +572,7 @@ impl Fsm for TextToolFsmState {
tool_data.bounding_box_manager.take();
}
tool_data.resize.snap_manager.draw_overlays(SnapData::new(document, input), &mut overlay_context);
tool_data.resize.snap_manager.draw_overlays(SnapData::new(document, input, viewport), &mut overlay_context);
self
}
@@ -585,7 +585,7 @@ impl Fsm for TextToolFsmState {
state
}
(TextToolFsmState::Ready, TextToolMessage::DragStart) => {
tool_data.resize.start(document, input);
tool_data.resize.start(document, input, viewport);
tool_data.cached_resize_bounds = [tool_data.resize.viewport_drag_start(document); 2];
tool_data.drag_start = input.mouse.position;
tool_data.drag_current = input.mouse.position;
@@ -659,7 +659,7 @@ impl Fsm for TextToolFsmState {
TextToolFsmState::Ready
}
(TextToolFsmState::Placing, TextToolMessage::PointerMove { center, lock_ratio }) => {
tool_data.cached_resize_bounds = tool_data.resize.calculate_points_ignore_layer(document, input, center, lock_ratio, false);
tool_data.cached_resize_bounds = tool_data.resize.calculate_points_ignore_layer(document, input, viewport, center, lock_ratio, false);
responses.add(OverlaysMessage::Draw);
@@ -668,7 +668,7 @@ impl Fsm for TextToolFsmState {
TextToolMessage::PointerOutsideViewport { center, lock_ratio }.into(),
TextToolMessage::PointerMove { center, lock_ratio }.into(),
];
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
tool_data.auto_panning.setup_by_mouse_position(input, viewport, &messages, responses);
TextToolFsmState::Placing
}
@@ -691,7 +691,7 @@ impl Fsm for TextToolFsmState {
TextToolMessage::PointerOutsideViewport { center, lock_ratio }.into(),
TextToolMessage::PointerMove { center, lock_ratio }.into(),
];
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
tool_data.auto_panning.setup_by_mouse_position(input, viewport, &messages, responses);
}
TextToolFsmState::Dragging
@@ -713,7 +713,7 @@ impl Fsm for TextToolFsmState {
let snap = Some(SizeSnapData {
manager: &mut tool_data.resize.snap_manager,
points: &mut tool_data.snap_candidates,
snap_data: SnapData::ignore(document, input, &selected),
snap_data: SnapData::ignore(document, input, viewport, &selected),
});
let (position, size) = movement.new_size(input.mouse.position, bounds.original_bound_transform, center_position, constrain, snap);
@@ -752,26 +752,26 @@ impl Fsm for TextToolFsmState {
TextToolMessage::PointerOutsideViewport { center, lock_ratio }.into(),
TextToolMessage::PointerMove { center, lock_ratio }.into(),
];
tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses);
tool_data.auto_panning.setup_by_mouse_position(input, viewport, &messages, responses);
}
}
TextToolFsmState::ResizingBounds
}
(_, TextToolMessage::PointerMove { .. }) => {
tool_data.resize.snap_manager.preview_draw(&SnapData::new(document, input), input.mouse.position);
tool_data.resize.snap_manager.preview_draw(&SnapData::new(document, input, viewport), input.mouse.position);
responses.add(OverlaysMessage::Draw);
self
}
(TextToolFsmState::Placing, TextToolMessage::PointerOutsideViewport { .. }) => {
// Auto-panning setup
let _ = tool_data.auto_panning.shift_viewport(input, responses);
let _ = tool_data.auto_panning.shift_viewport(input, viewport, responses);
TextToolFsmState::Placing
}
(TextToolFsmState::ResizingBounds | TextToolFsmState::Dragging, TextToolMessage::PointerOutsideViewport { .. }) => {
// Auto-panning
if let Some(shift) = tool_data.auto_panning.shift_viewport(input, responses) {
if let Some(shift) = tool_data.auto_panning.shift_viewport(input, viewport, responses) {
if let Some(bounds) = &mut tool_data.bounding_box_manager {
bounds.center_of_transformation += shift;
bounds.original_bound_transform.translation += shift;