mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-10-04 15:28:12 +08:00
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:
@@ -6,6 +6,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
#[impl_message(Message, BroadcastMessage, TriggerEvent)]
|
#[impl_message(Message, BroadcastMessage, TriggerEvent)]
|
||||||
pub enum BroadcastEvent {
|
pub enum BroadcastEvent {
|
||||||
DocumentIsDirty,
|
DocumentIsDirty,
|
||||||
|
CanvasTransformed,
|
||||||
ToolAbort,
|
ToolAbort,
|
||||||
SelectionChanged,
|
SelectionChanged,
|
||||||
WorkingColorChanged,
|
WorkingColorChanged,
|
||||||
|
|||||||
@@ -211,6 +211,7 @@ impl MessageHandler<NavigationMessage, (&Document, Option<[DVec2; 2]>, &InputPre
|
|||||||
TransformCanvasEnd => {
|
TransformCanvasEnd => {
|
||||||
self.tilt = self.snapped_angle();
|
self.tilt = self.snapped_angle();
|
||||||
self.zoom = self.snapped_scale();
|
self.zoom = self.snapped_scale();
|
||||||
|
responses.add(BroadcastEvent::CanvasTransformed);
|
||||||
responses.add(BroadcastEvent::DocumentIsDirty);
|
responses.add(BroadcastEvent::DocumentIsDirty);
|
||||||
responses.add(ToolMessage::UpdateCursor);
|
responses.add(ToolMessage::UpdateCursor);
|
||||||
responses.add(ToolMessage::UpdateHints);
|
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);
|
let transformed_delta = document.root.transform.inverse().transform_vector2(delta);
|
||||||
|
|
||||||
self.pan += transformed_delta;
|
self.pan += transformed_delta;
|
||||||
|
responses.add(BroadcastEvent::CanvasTransformed);
|
||||||
responses.add(BroadcastEvent::DocumentIsDirty);
|
responses.add(BroadcastEvent::DocumentIsDirty);
|
||||||
self.create_document_transform(&ipp.viewport_bounds, responses);
|
self.create_document_transform(&ipp.viewport_bounds, responses);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,12 @@ impl Resize {
|
|||||||
self.drag_start = root_transform.inverse().transform_point2(self.snap_manager.snap_position(responses, document, input.mouse.position));
|
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.
|
/// Calculate the drag start position in viewport space.
|
||||||
pub fn viewport_drag_start(&self, document: &DocumentMessageHandler) -> DVec2 {
|
pub fn viewport_drag_start(&self, document: &DocumentMessageHandler) -> DVec2 {
|
||||||
let root_transform = document.document_legacy.root.transform;
|
let root_transform = document.document_legacy.root.transform;
|
||||||
|
|||||||
@@ -54,6 +54,8 @@ pub enum EllipseOptionsUpdate {
|
|||||||
pub enum EllipseToolMessage {
|
pub enum EllipseToolMessage {
|
||||||
// Standard messages
|
// Standard messages
|
||||||
#[remain::unsorted]
|
#[remain::unsorted]
|
||||||
|
CanvasTransformed,
|
||||||
|
#[remain::unsorted]
|
||||||
Abort,
|
Abort,
|
||||||
#[remain::unsorted]
|
#[remain::unsorted]
|
||||||
WorkingColorChanged,
|
WorkingColorChanged,
|
||||||
@@ -165,6 +167,7 @@ impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for Ellipse
|
|||||||
impl ToolTransition for EllipseTool {
|
impl ToolTransition for EllipseTool {
|
||||||
fn event_to_message_map(&self) -> EventToMessageMap {
|
fn event_to_message_map(&self) -> EventToMessageMap {
|
||||||
EventToMessageMap {
|
EventToMessageMap {
|
||||||
|
canvas_transformed: Some(EllipseToolMessage::CanvasTransformed.into()),
|
||||||
tool_abort: Some(EllipseToolMessage::Abort.into()),
|
tool_abort: Some(EllipseToolMessage::Abort.into()),
|
||||||
working_color_changed: Some(EllipseToolMessage::WorkingColorChanged.into()),
|
working_color_changed: Some(EllipseToolMessage::WorkingColorChanged.into()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@@ -209,6 +212,10 @@ impl Fsm for EllipseToolFsmState {
|
|||||||
|
|
||||||
if let ToolMessage::Ellipse(event) = event {
|
if let ToolMessage::Ellipse(event) = event {
|
||||||
match (self, event) {
|
match (self, event) {
|
||||||
|
(Drawing, CanvasTransformed) => {
|
||||||
|
tool_data.data.recalculate_snaps(document, input, render_data);
|
||||||
|
self
|
||||||
|
}
|
||||||
(Ready, DragStart) => {
|
(Ready, DragStart) => {
|
||||||
shape_data.start(responses, document, input, render_data);
|
shape_data.start(responses, document, input, render_data);
|
||||||
responses.add(DocumentMessage::StartTransaction);
|
responses.add(DocumentMessage::StartTransaction);
|
||||||
|
|||||||
@@ -44,6 +44,10 @@ impl Default for LineOptions {
|
|||||||
pub enum LineToolMessage {
|
pub enum LineToolMessage {
|
||||||
// Standard messages
|
// Standard messages
|
||||||
#[remain::unsorted]
|
#[remain::unsorted]
|
||||||
|
DocumentIsDirty,
|
||||||
|
#[remain::unsorted]
|
||||||
|
CanvasTransformed,
|
||||||
|
#[remain::unsorted]
|
||||||
Abort,
|
Abort,
|
||||||
#[remain::unsorted]
|
#[remain::unsorted]
|
||||||
WorkingColorChanged,
|
WorkingColorChanged,
|
||||||
@@ -140,6 +144,7 @@ impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for LineToo
|
|||||||
impl ToolTransition for LineTool {
|
impl ToolTransition for LineTool {
|
||||||
fn event_to_message_map(&self) -> EventToMessageMap {
|
fn event_to_message_map(&self) -> EventToMessageMap {
|
||||||
EventToMessageMap {
|
EventToMessageMap {
|
||||||
|
canvas_transformed: Some(LineToolMessage::CanvasTransformed.into()),
|
||||||
tool_abort: Some(LineToolMessage::Abort.into()),
|
tool_abort: Some(LineToolMessage::Abort.into()),
|
||||||
working_color_changed: Some(LineToolMessage::WorkingColorChanged.into()),
|
working_color_changed: Some(LineToolMessage::WorkingColorChanged.into()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@@ -219,7 +224,6 @@ impl Fsm for LineToolFsmState {
|
|||||||
tool_data.snap_manager.cleanup(responses);
|
tool_data.snap_manager.cleanup(responses);
|
||||||
input.mouse.finish_transaction(tool_data.drag_start, responses);
|
input.mouse.finish_transaction(tool_data.drag_start, responses);
|
||||||
tool_data.path = None;
|
tool_data.path = None;
|
||||||
|
|
||||||
Ready
|
Ready
|
||||||
}
|
}
|
||||||
(Drawing, Abort) => {
|
(Drawing, Abort) => {
|
||||||
|
|||||||
@@ -52,6 +52,8 @@ impl Default for PenOptions {
|
|||||||
pub enum PenToolMessage {
|
pub enum PenToolMessage {
|
||||||
// Standard messages
|
// Standard messages
|
||||||
#[remain::unsorted]
|
#[remain::unsorted]
|
||||||
|
CanvasTransformed,
|
||||||
|
#[remain::unsorted]
|
||||||
DocumentIsDirty,
|
DocumentIsDirty,
|
||||||
#[remain::unsorted]
|
#[remain::unsorted]
|
||||||
Abort,
|
Abort,
|
||||||
@@ -193,6 +195,7 @@ impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for PenTool
|
|||||||
impl ToolTransition for PenTool {
|
impl ToolTransition for PenTool {
|
||||||
fn event_to_message_map(&self) -> EventToMessageMap {
|
fn event_to_message_map(&self) -> EventToMessageMap {
|
||||||
EventToMessageMap {
|
EventToMessageMap {
|
||||||
|
canvas_transformed: Some(PenToolMessage::CanvasTransformed.into()),
|
||||||
document_dirty: Some(PenToolMessage::DocumentIsDirty.into()),
|
document_dirty: Some(PenToolMessage::DocumentIsDirty.into()),
|
||||||
tool_abort: Some(PenToolMessage::Abort.into()),
|
tool_abort: Some(PenToolMessage::Abort.into()),
|
||||||
selection_changed: Some(PenToolMessage::SelectionChanged.into()),
|
selection_changed: Some(PenToolMessage::SelectionChanged.into()),
|
||||||
@@ -589,6 +592,10 @@ impl Fsm for PenToolFsmState {
|
|||||||
|
|
||||||
if let ToolMessage::Pen(event) = event {
|
if let ToolMessage::Pen(event) = event {
|
||||||
match (self, 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) => {
|
(_, PenToolMessage::DocumentIsDirty) => {
|
||||||
// When the document has moved / needs to be redraw, re-render the overlays
|
// 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
|
// TODO the overlay system should probably receive this message instead of the tool
|
||||||
|
|||||||
@@ -47,6 +47,8 @@ impl Default for PolygonOptions {
|
|||||||
pub enum PolygonToolMessage {
|
pub enum PolygonToolMessage {
|
||||||
// Standard messages
|
// Standard messages
|
||||||
#[remain::unsorted]
|
#[remain::unsorted]
|
||||||
|
CanvasTransformed,
|
||||||
|
#[remain::unsorted]
|
||||||
Abort,
|
Abort,
|
||||||
#[remain::unsorted]
|
#[remain::unsorted]
|
||||||
WorkingColorChanged,
|
WorkingColorChanged,
|
||||||
@@ -205,6 +207,7 @@ impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for Polygon
|
|||||||
impl ToolTransition for PolygonTool {
|
impl ToolTransition for PolygonTool {
|
||||||
fn event_to_message_map(&self) -> EventToMessageMap {
|
fn event_to_message_map(&self) -> EventToMessageMap {
|
||||||
EventToMessageMap {
|
EventToMessageMap {
|
||||||
|
canvas_transformed: Some(PolygonToolMessage::CanvasTransformed.into()),
|
||||||
tool_abort: Some(PolygonToolMessage::Abort.into()),
|
tool_abort: Some(PolygonToolMessage::Abort.into()),
|
||||||
working_color_changed: Some(PolygonToolMessage::WorkingColorChanged.into()),
|
working_color_changed: Some(PolygonToolMessage::WorkingColorChanged.into()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@@ -249,6 +252,10 @@ impl Fsm for PolygonToolFsmState {
|
|||||||
|
|
||||||
if let ToolMessage::Polygon(event) = event {
|
if let ToolMessage::Polygon(event) = event {
|
||||||
match (self, event) {
|
match (self, event) {
|
||||||
|
(Drawing, CanvasTransformed) => {
|
||||||
|
tool_data.data.recalculate_snaps(document, input, render_data);
|
||||||
|
self
|
||||||
|
}
|
||||||
(Ready, DragStart) => {
|
(Ready, DragStart) => {
|
||||||
polygon_data.start(responses, document, input, render_data);
|
polygon_data.start(responses, document, input, render_data);
|
||||||
responses.add(DocumentMessage::StartTransaction);
|
responses.add(DocumentMessage::StartTransaction);
|
||||||
|
|||||||
@@ -53,6 +53,8 @@ pub enum RectangleOptionsUpdate {
|
|||||||
pub enum RectangleToolMessage {
|
pub enum RectangleToolMessage {
|
||||||
// Standard messages
|
// Standard messages
|
||||||
#[remain::unsorted]
|
#[remain::unsorted]
|
||||||
|
CanvasTransformed,
|
||||||
|
#[remain::unsorted]
|
||||||
Abort,
|
Abort,
|
||||||
#[remain::unsorted]
|
#[remain::unsorted]
|
||||||
WorkingColorChanged,
|
WorkingColorChanged,
|
||||||
@@ -164,6 +166,7 @@ impl ToolMetadata for RectangleTool {
|
|||||||
impl ToolTransition for RectangleTool {
|
impl ToolTransition for RectangleTool {
|
||||||
fn event_to_message_map(&self) -> EventToMessageMap {
|
fn event_to_message_map(&self) -> EventToMessageMap {
|
||||||
EventToMessageMap {
|
EventToMessageMap {
|
||||||
|
canvas_transformed: Some(RectangleToolMessage::CanvasTransformed.into()),
|
||||||
tool_abort: Some(RectangleToolMessage::Abort.into()),
|
tool_abort: Some(RectangleToolMessage::Abort.into()),
|
||||||
working_color_changed: Some(RectangleToolMessage::WorkingColorChanged.into()),
|
working_color_changed: Some(RectangleToolMessage::WorkingColorChanged.into()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@@ -208,6 +211,10 @@ impl Fsm for RectangleToolFsmState {
|
|||||||
|
|
||||||
if let ToolMessage::Rectangle(event) = event {
|
if let ToolMessage::Rectangle(event) = event {
|
||||||
match (self, event) {
|
match (self, event) {
|
||||||
|
(Drawing, CanvasTransformed) => {
|
||||||
|
tool_data.data.recalculate_snaps(document, input, render_data);
|
||||||
|
self
|
||||||
|
}
|
||||||
(Ready, DragStart) => {
|
(Ready, DragStart) => {
|
||||||
shape_data.start(responses, document, input, render_data);
|
shape_data.start(responses, document, input, render_data);
|
||||||
|
|
||||||
|
|||||||
@@ -45,6 +45,8 @@ impl Default for SplineOptions {
|
|||||||
pub enum SplineToolMessage {
|
pub enum SplineToolMessage {
|
||||||
// Standard messages
|
// Standard messages
|
||||||
#[remain::unsorted]
|
#[remain::unsorted]
|
||||||
|
CanvasTransformed,
|
||||||
|
#[remain::unsorted]
|
||||||
Abort,
|
Abort,
|
||||||
#[remain::unsorted]
|
#[remain::unsorted]
|
||||||
WorkingColorChanged,
|
WorkingColorChanged,
|
||||||
@@ -178,6 +180,7 @@ impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for SplineT
|
|||||||
impl ToolTransition for SplineTool {
|
impl ToolTransition for SplineTool {
|
||||||
fn event_to_message_map(&self) -> EventToMessageMap {
|
fn event_to_message_map(&self) -> EventToMessageMap {
|
||||||
EventToMessageMap {
|
EventToMessageMap {
|
||||||
|
canvas_transformed: Some(SplineToolMessage::CanvasTransformed.into()),
|
||||||
tool_abort: Some(SplineToolMessage::Abort.into()),
|
tool_abort: Some(SplineToolMessage::Abort.into()),
|
||||||
working_color_changed: Some(SplineToolMessage::WorkingColorChanged.into()),
|
working_color_changed: Some(SplineToolMessage::WorkingColorChanged.into()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@@ -219,6 +222,10 @@ impl Fsm for SplineToolFsmState {
|
|||||||
|
|
||||||
if let ToolMessage::Spline(event) = event {
|
if let ToolMessage::Spline(event) = event {
|
||||||
match (self, 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) => {
|
(Ready, DragStart) => {
|
||||||
responses.add(DocumentMessage::StartTransaction);
|
responses.add(DocumentMessage::StartTransaction);
|
||||||
responses.add(DocumentMessage::DeselectAllLayers);
|
responses.add(DocumentMessage::DeselectAllLayers);
|
||||||
|
|||||||
@@ -200,6 +200,7 @@ impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for TextToo
|
|||||||
impl ToolTransition for TextTool {
|
impl ToolTransition for TextTool {
|
||||||
fn event_to_message_map(&self) -> EventToMessageMap {
|
fn event_to_message_map(&self) -> EventToMessageMap {
|
||||||
EventToMessageMap {
|
EventToMessageMap {
|
||||||
|
canvas_transformed: None,
|
||||||
document_dirty: Some(TextToolMessage::DocumentIsDirty.into()),
|
document_dirty: Some(TextToolMessage::DocumentIsDirty.into()),
|
||||||
tool_abort: Some(TextToolMessage::Abort.into()),
|
tool_abort: Some(TextToolMessage::Abort.into()),
|
||||||
selection_changed: Some(TextToolMessage::DocumentIsDirty.into()),
|
selection_changed: Some(TextToolMessage::DocumentIsDirty.into()),
|
||||||
|
|||||||
@@ -169,6 +169,7 @@ impl DocumentToolData {
|
|||||||
|
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct EventToMessageMap {
|
pub struct EventToMessageMap {
|
||||||
|
pub canvas_transformed: Option<ToolMessage>,
|
||||||
pub document_dirty: Option<ToolMessage>,
|
pub document_dirty: Option<ToolMessage>,
|
||||||
pub selection_changed: Option<ToolMessage>,
|
pub selection_changed: Option<ToolMessage>,
|
||||||
pub tool_abort: Option<ToolMessage>,
|
pub tool_abort: Option<ToolMessage>,
|
||||||
@@ -189,6 +190,7 @@ pub trait ToolTransition {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let event_to_tool_map = self.event_to_message_map();
|
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.document_dirty, BroadcastEvent::DocumentIsDirty);
|
||||||
subscribe_message(event_to_tool_map.tool_abort, BroadcastEvent::ToolAbort);
|
subscribe_message(event_to_tool_map.tool_abort, BroadcastEvent::ToolAbort);
|
||||||
subscribe_message(event_to_tool_map.selection_changed, BroadcastEvent::SelectionChanged);
|
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();
|
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.document_dirty, BroadcastEvent::DocumentIsDirty);
|
||||||
unsubscribe_message(event_to_tool_map.tool_abort, BroadcastEvent::ToolAbort);
|
unsubscribe_message(event_to_tool_map.tool_abort, BroadcastEvent::ToolAbort);
|
||||||
unsubscribe_message(event_to_tool_map.selection_changed, BroadcastEvent::SelectionChanged);
|
unsubscribe_message(event_to_tool_map.selection_changed, BroadcastEvent::SelectionChanged);
|
||||||
|
|||||||
Reference in New Issue
Block a user