Correct snapping offsets after canvas transformation when using snap-reliant tools (#1370)

* fix: pen, spline tool incorrect snap offsets
- re-render snapping offsets if canvas transformed during line draw

* [wip]feat: add CanvasTransformed global message

* [wip]fix: synchronize line tool snap offsets

* fix: update offsets for shape tools on canvas transform

* chore: remove unneeded function parameter

* [wip]fix: use line tool at canvas level

* refactor: revert line tool changes
This commit is contained in:
Dhruv 2023-08-11 14:51:39 +05:30 committed by Keavon Chambers
parent 2377240d07
commit 1c11ebcc4e
11 changed files with 53 additions and 1 deletions

View File

@ -6,6 +6,7 @@ use serde::{Deserialize, Serialize};
#[impl_message(Message, BroadcastMessage, TriggerEvent)]
pub enum BroadcastEvent {
DocumentIsDirty,
CanvasTransformed,
ToolAbort,
SelectionChanged,
WorkingColorChanged,

View File

@ -211,6 +211,7 @@ impl MessageHandler<NavigationMessage, (&Document, Option<[DVec2; 2]>, &InputPre
TransformCanvasEnd => {
self.tilt = self.snapped_angle();
self.zoom = self.snapped_scale();
responses.add(BroadcastEvent::CanvasTransformed);
responses.add(BroadcastEvent::DocumentIsDirty);
responses.add(ToolMessage::UpdateCursor);
responses.add(ToolMessage::UpdateHints);
@ -225,6 +226,7 @@ impl MessageHandler<NavigationMessage, (&Document, Option<[DVec2; 2]>, &InputPre
let transformed_delta = document.root.transform.inverse().transform_vector2(delta);
self.pan += transformed_delta;
responses.add(BroadcastEvent::CanvasTransformed);
responses.add(BroadcastEvent::DocumentIsDirty);
self.create_document_transform(&ipp.viewport_bounds, responses);
}

View File

@ -24,6 +24,12 @@ impl Resize {
self.drag_start = root_transform.inverse().transform_point2(self.snap_manager.snap_position(responses, document, input.mouse.position));
}
/// Recalculates snap targets without snapping the starting position.
pub fn recalculate_snaps(&mut self, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, render_data: &RenderData) {
self.snap_manager.start_snap(document, input, document.bounding_boxes(None, None, render_data), true, true);
self.snap_manager.add_all_document_handles(document, input, &[], &[], &[]);
}
/// Calculate the drag start position in viewport space.
pub fn viewport_drag_start(&self, document: &DocumentMessageHandler) -> DVec2 {
let root_transform = document.document_legacy.root.transform;

View File

@ -54,6 +54,8 @@ pub enum EllipseOptionsUpdate {
pub enum EllipseToolMessage {
// Standard messages
#[remain::unsorted]
CanvasTransformed,
#[remain::unsorted]
Abort,
#[remain::unsorted]
WorkingColorChanged,
@ -165,6 +167,7 @@ impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for Ellipse
impl ToolTransition for EllipseTool {
fn event_to_message_map(&self) -> EventToMessageMap {
EventToMessageMap {
canvas_transformed: Some(EllipseToolMessage::CanvasTransformed.into()),
tool_abort: Some(EllipseToolMessage::Abort.into()),
working_color_changed: Some(EllipseToolMessage::WorkingColorChanged.into()),
..Default::default()
@ -209,6 +212,10 @@ impl Fsm for EllipseToolFsmState {
if let ToolMessage::Ellipse(event) = event {
match (self, event) {
(Drawing, CanvasTransformed) => {
tool_data.data.recalculate_snaps(document, input, render_data);
self
}
(Ready, DragStart) => {
shape_data.start(responses, document, input, render_data);
responses.add(DocumentMessage::StartTransaction);

View File

@ -44,6 +44,10 @@ impl Default for LineOptions {
pub enum LineToolMessage {
// Standard messages
#[remain::unsorted]
DocumentIsDirty,
#[remain::unsorted]
CanvasTransformed,
#[remain::unsorted]
Abort,
#[remain::unsorted]
WorkingColorChanged,
@ -140,6 +144,7 @@ impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for LineToo
impl ToolTransition for LineTool {
fn event_to_message_map(&self) -> EventToMessageMap {
EventToMessageMap {
canvas_transformed: Some(LineToolMessage::CanvasTransformed.into()),
tool_abort: Some(LineToolMessage::Abort.into()),
working_color_changed: Some(LineToolMessage::WorkingColorChanged.into()),
..Default::default()
@ -219,7 +224,6 @@ impl Fsm for LineToolFsmState {
tool_data.snap_manager.cleanup(responses);
input.mouse.finish_transaction(tool_data.drag_start, responses);
tool_data.path = None;
Ready
}
(Drawing, Abort) => {

View File

@ -52,6 +52,8 @@ impl Default for PenOptions {
pub enum PenToolMessage {
// Standard messages
#[remain::unsorted]
CanvasTransformed,
#[remain::unsorted]
DocumentIsDirty,
#[remain::unsorted]
Abort,
@ -193,6 +195,7 @@ impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for PenTool
impl ToolTransition for PenTool {
fn event_to_message_map(&self) -> EventToMessageMap {
EventToMessageMap {
canvas_transformed: Some(PenToolMessage::CanvasTransformed.into()),
document_dirty: Some(PenToolMessage::DocumentIsDirty.into()),
tool_abort: Some(PenToolMessage::Abort.into()),
selection_changed: Some(PenToolMessage::SelectionChanged.into()),
@ -589,6 +592,10 @@ impl Fsm for PenToolFsmState {
if let ToolMessage::Pen(event) = event {
match (self, event) {
(_, PenToolMessage::CanvasTransformed) => {
tool_data.snap_manager.start_snap(document, input, document.bounding_boxes(None, None, render_data), true, true);
self
}
(_, PenToolMessage::DocumentIsDirty) => {
// When the document has moved / needs to be redraw, re-render the overlays
// TODO the overlay system should probably receive this message instead of the tool

View File

@ -47,6 +47,8 @@ impl Default for PolygonOptions {
pub enum PolygonToolMessage {
// Standard messages
#[remain::unsorted]
CanvasTransformed,
#[remain::unsorted]
Abort,
#[remain::unsorted]
WorkingColorChanged,
@ -205,6 +207,7 @@ impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for Polygon
impl ToolTransition for PolygonTool {
fn event_to_message_map(&self) -> EventToMessageMap {
EventToMessageMap {
canvas_transformed: Some(PolygonToolMessage::CanvasTransformed.into()),
tool_abort: Some(PolygonToolMessage::Abort.into()),
working_color_changed: Some(PolygonToolMessage::WorkingColorChanged.into()),
..Default::default()
@ -249,6 +252,10 @@ impl Fsm for PolygonToolFsmState {
if let ToolMessage::Polygon(event) = event {
match (self, event) {
(Drawing, CanvasTransformed) => {
tool_data.data.recalculate_snaps(document, input, render_data);
self
}
(Ready, DragStart) => {
polygon_data.start(responses, document, input, render_data);
responses.add(DocumentMessage::StartTransaction);

View File

@ -53,6 +53,8 @@ pub enum RectangleOptionsUpdate {
pub enum RectangleToolMessage {
// Standard messages
#[remain::unsorted]
CanvasTransformed,
#[remain::unsorted]
Abort,
#[remain::unsorted]
WorkingColorChanged,
@ -164,6 +166,7 @@ impl ToolMetadata for RectangleTool {
impl ToolTransition for RectangleTool {
fn event_to_message_map(&self) -> EventToMessageMap {
EventToMessageMap {
canvas_transformed: Some(RectangleToolMessage::CanvasTransformed.into()),
tool_abort: Some(RectangleToolMessage::Abort.into()),
working_color_changed: Some(RectangleToolMessage::WorkingColorChanged.into()),
..Default::default()
@ -208,6 +211,10 @@ impl Fsm for RectangleToolFsmState {
if let ToolMessage::Rectangle(event) = event {
match (self, event) {
(Drawing, CanvasTransformed) => {
tool_data.data.recalculate_snaps(document, input, render_data);
self
}
(Ready, DragStart) => {
shape_data.start(responses, document, input, render_data);

View File

@ -45,6 +45,8 @@ impl Default for SplineOptions {
pub enum SplineToolMessage {
// Standard messages
#[remain::unsorted]
CanvasTransformed,
#[remain::unsorted]
Abort,
#[remain::unsorted]
WorkingColorChanged,
@ -178,6 +180,7 @@ impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for SplineT
impl ToolTransition for SplineTool {
fn event_to_message_map(&self) -> EventToMessageMap {
EventToMessageMap {
canvas_transformed: Some(SplineToolMessage::CanvasTransformed.into()),
tool_abort: Some(SplineToolMessage::Abort.into()),
working_color_changed: Some(SplineToolMessage::WorkingColorChanged.into()),
..Default::default()
@ -219,6 +222,10 @@ impl Fsm for SplineToolFsmState {
if let ToolMessage::Spline(event) = event {
match (self, event) {
(_, CanvasTransformed) => {
tool_data.snap_manager.start_snap(document, input, document.bounding_boxes(None, None, render_data), true, true);
self
}
(Ready, DragStart) => {
responses.add(DocumentMessage::StartTransaction);
responses.add(DocumentMessage::DeselectAllLayers);

View File

@ -200,6 +200,7 @@ impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for TextToo
impl ToolTransition for TextTool {
fn event_to_message_map(&self) -> EventToMessageMap {
EventToMessageMap {
canvas_transformed: None,
document_dirty: Some(TextToolMessage::DocumentIsDirty.into()),
tool_abort: Some(TextToolMessage::Abort.into()),
selection_changed: Some(TextToolMessage::DocumentIsDirty.into()),

View File

@ -169,6 +169,7 @@ impl DocumentToolData {
#[derive(Clone, Debug, Default)]
pub struct EventToMessageMap {
pub canvas_transformed: Option<ToolMessage>,
pub document_dirty: Option<ToolMessage>,
pub selection_changed: Option<ToolMessage>,
pub tool_abort: Option<ToolMessage>,
@ -189,6 +190,7 @@ pub trait ToolTransition {
};
let event_to_tool_map = self.event_to_message_map();
subscribe_message(event_to_tool_map.canvas_transformed, BroadcastEvent::CanvasTransformed);
subscribe_message(event_to_tool_map.document_dirty, BroadcastEvent::DocumentIsDirty);
subscribe_message(event_to_tool_map.tool_abort, BroadcastEvent::ToolAbort);
subscribe_message(event_to_tool_map.selection_changed, BroadcastEvent::SelectionChanged);
@ -206,6 +208,7 @@ pub trait ToolTransition {
};
let event_to_tool_map = self.event_to_message_map();
unsubscribe_message(event_to_tool_map.canvas_transformed, BroadcastEvent::CanvasTransformed);
unsubscribe_message(event_to_tool_map.document_dirty, BroadcastEvent::DocumentIsDirty);
unsubscribe_message(event_to_tool_map.tool_abort, BroadcastEvent::ToolAbort);
unsubscribe_message(event_to_tool_map.selection_changed, BroadcastEvent::SelectionChanged);