From 7ab127c3aecbad2ee410f26c4d385badfdadef1e Mon Sep 17 00:00:00 2001 From: 0HyperCube <78500760+0HyperCube@users.noreply.github.com> Date: Fri, 31 Dec 2021 03:10:30 +0000 Subject: [PATCH] Remove transformations from LayerData (#439) Co-authored-by: Keavon Chambers --- editor/src/document/document_file.rs | 14 +- .../src/document/document_message_handler.rs | 2 +- editor/src/document/layer_panel.rs | 21 +-- editor/src/document/movement_handler.rs | 141 ++++++++++-------- .../src/document/overlay_message_handler.rs | 2 +- 5 files changed, 89 insertions(+), 91 deletions(-) diff --git a/editor/src/document/document_file.rs b/editor/src/document/document_file.rs index ae4d904a..8d3eb01e 100644 --- a/editor/src/document/document_file.rs +++ b/editor/src/document/document_file.rs @@ -193,7 +193,7 @@ impl DocumentMessageHandler { pub fn with_name(name: String, ipp: &InputPreprocessor) -> Self { let mut document = Self { name, ..Self::default() }; - document.graphene_document.root.transform = document.layer_data(&[]).calculate_offset_transform(ipp.viewport_bounds.size() / 2., 0.); + document.graphene_document.root.transform = document.movement_handler.calculate_offset_transform(ipp.viewport_bounds.size() / 2.); document } @@ -497,9 +497,7 @@ impl MessageHandler for DocumentMessageHand fn process_action(&mut self, message: DocumentMessage, ipp: &InputPreprocessor, responses: &mut VecDeque) { use DocumentMessage::*; match message { - Movement(message) => self - .movement_handler - .process_action(message, (Self::layer_data_mut_no_borrow_self(&mut self.layer_data, &[]), &self.graphene_document, ipp), responses), + Movement(message) => self.movement_handler.process_action(message, (&self.graphene_document, ipp), responses), TransformLayers(message) => self .transform_layer_handler .process_action(message, (&mut self.layer_data, &mut self.graphene_document, ipp), responses), @@ -764,9 +762,9 @@ impl MessageHandler for DocumentMessageHand } .into(), ); - let root_layerdata = self.layer_data(&[]); + let document_transform = &self.movement_handler; - let scale = 0.5 + ASYMPTOTIC_EFFECT + root_layerdata.scale * SCALE_EFFECT; + let scale = 0.5 + ASYMPTOTIC_EFFECT + document_transform.scale * SCALE_EFFECT; let viewport_size = ipp.viewport_bounds.size(); let viewport_mid = ipp.viewport_bounds.center(); let [bounds1, bounds2] = self.graphene_document.visible_layers_bounding_box().unwrap_or([viewport_mid; 2]); @@ -777,9 +775,9 @@ impl MessageHandler for DocumentMessageHand let scrollbar_multiplier = bounds_length - viewport_size; let scrollbar_size = viewport_size / bounds_length; - let log = root_layerdata.scale.log2(); + let log = document_transform.scale.log2(); let ruler_interval = if log < 0. { 100. * 2_f64.powf(-log.ceil()) } else { 100. / 2_f64.powf(log.ceil()) }; - let ruler_spacing = ruler_interval * root_layerdata.scale; + let ruler_spacing = ruler_interval * document_transform.scale; let ruler_origin = self.graphene_document.root.transform.transform_point2(DVec2::ZERO); diff --git a/editor/src/document/document_message_handler.rs b/editor/src/document/document_message_handler.rs index 3a980be9..159cb06d 100644 --- a/editor/src/document/document_message_handler.rs +++ b/editor/src/document/document_message_handler.rs @@ -104,7 +104,7 @@ impl DocumentsMessageHandler { } // TODO Fix how this doesn't preserve tab order upon loading new document from file>load - fn load_document(&mut self, mut new_document: DocumentMessageHandler, document_id: u64, replace_first_empty: bool, responses: &mut VecDeque) { + fn load_document(&mut self, new_document: DocumentMessageHandler, document_id: u64, replace_first_empty: bool, responses: &mut VecDeque) { // Special case when loading a document on an empty page if replace_first_empty && self.active_document().is_unmodified_default() { responses.push_back(DocumentsMessage::CloseDocument(self.active_document_id).into()); diff --git a/editor/src/document/layer_panel.rs b/editor/src/document/layer_panel.rs index ea2d844c..ad094380 100644 --- a/editor/src/document/layer_panel.rs +++ b/editor/src/document/layer_panel.rs @@ -2,36 +2,17 @@ use glam::{DAffine2, DVec2}; use graphene::layers::{style::ViewMode, BlendMode, Layer, LayerData as DocumentLayerData, LayerDataType}; use graphene::LayerId; use serde::{ser::SerializeStruct, Deserialize, Serialize}; -use std::collections::HashMap; use std::fmt; #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Copy)] pub struct LayerData { pub selected: bool, pub expanded: bool, - pub translation: DVec2, - pub rotation: f64, - pub scale: f64, } impl LayerData { pub fn new(expanded: bool) -> LayerData { - LayerData { - selected: false, - expanded, - translation: DVec2::ZERO, - rotation: 0., - scale: 1., - } - } - - pub fn calculate_offset_transform(&self, offset: DVec2, snapped_angle: f64) -> DAffine2 { - // TODO: replace with DAffine2::from_scale_angle_translation and fix the errors - let offset_transform = DAffine2::from_translation(offset); - let scale_transform = DAffine2::from_scale(DVec2::new(self.scale, self.scale)); - let angle_transform = DAffine2::from_angle(snapped_angle); - let translation_transform = DAffine2::from_translation(self.translation); - scale_transform * offset_transform * angle_transform * translation_transform + LayerData { selected: false, expanded } } } diff --git a/editor/src/document/movement_handler.rs b/editor/src/document/movement_handler.rs index c693dce2..5f51f2fc 100644 --- a/editor/src/document/movement_handler.rs +++ b/editor/src/document/movement_handler.rs @@ -1,6 +1,6 @@ use crate::consts::VIEWPORT_ROTATE_SNAP_INTERVAL; pub use crate::document::layer_panel::*; -use crate::document::{DocumentMessage, LayerData}; +use crate::document::DocumentMessage; use crate::message_prelude::*; use crate::{ consts::{VIEWPORT_SCROLL_RATE, VIEWPORT_ZOOM_LEVELS, VIEWPORT_ZOOM_MOUSE_RATE, VIEWPORT_ZOOM_SCALE_MAX, VIEWPORT_ZOOM_SCALE_MIN, VIEWPORT_ZOOM_WHEEL_RATE}, @@ -9,7 +9,7 @@ use crate::{ use graphene::document::Document; use graphene::Operation as DocumentOperation; -use glam::DVec2; +use glam::{DAffine2, DVec2}; use serde::{Deserialize, Serialize}; use std::collections::VecDeque; @@ -34,42 +34,67 @@ pub enum MovementMessage { TranslateCanvasByViewportFraction(DVec2), } -#[derive(Debug, Clone, Default, PartialEq)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct MovementMessageHandler { translating: bool, + pub translation: DVec2, rotating: bool, + pub rotation: f64, zooming: bool, - snapping: bool, - mouse_pos: ViewportPosition, + pub scale: f64, snap_rotate: bool, + mouse_pos: ViewportPosition, +} + +impl Default for MovementMessageHandler { + fn default() -> Self { + Self { + scale: 1., + translating: false, + translation: DVec2::ZERO, + rotating: false, + rotation: 0., + zooming: false, + snap_rotate: false, + mouse_pos: ViewportPosition::default(), + } + } } impl MovementMessageHandler { - pub fn snapped_angle(&self, layerdata: &LayerData) -> f64 { + pub fn snapped_angle(&self) -> f64 { let increment_radians: f64 = VIEWPORT_ROTATE_SNAP_INTERVAL.to_radians(); if self.snap_rotate { - (layerdata.rotation / increment_radians).round() * increment_radians + (self.rotation / increment_radians).round() * increment_radians } else { - layerdata.rotation + self.rotation } } + pub fn calculate_offset_transform(&self, offset: DVec2) -> DAffine2 { + // TODO: replace with DAffine2::from_scale_angle_translation and fix the errors + let offset_transform = DAffine2::from_translation(offset); + let scale_transform = DAffine2::from_scale(DVec2::new(self.scale, self.scale)); + let angle_transform = DAffine2::from_angle(self.snapped_angle()); + let translation_transform = DAffine2::from_translation(self.translation); + scale_transform * offset_transform * angle_transform * translation_transform + } - fn create_document_transform_from_layerdata(&self, layerdata: &LayerData, viewport_bounds: &ViewportBounds, responses: &mut VecDeque) { + fn create_document_transform(&self, viewport_bounds: &ViewportBounds, responses: &mut VecDeque) { let half_viewport = viewport_bounds.size() / 2.; - let scaled_half_viewport = half_viewport / layerdata.scale; + let scaled_half_viewport = half_viewport / self.scale; responses.push_back( DocumentOperation::SetLayerTransform { path: vec![], - transform: layerdata.calculate_offset_transform(scaled_half_viewport, self.snapped_angle(layerdata)).to_cols_array(), + transform: self.calculate_offset_transform(scaled_half_viewport).to_cols_array(), } .into(), ); } } -impl MessageHandler for MovementMessageHandler { - fn process_action(&mut self, message: MovementMessage, data: (&mut LayerData, &Document, &InputPreprocessor), responses: &mut VecDeque) { - let (layer_data, document, ipp) = data; +impl MessageHandler for MovementMessageHandler { + fn process_action(&mut self, message: MovementMessage, data: (&Document, &InputPreprocessor), responses: &mut VecDeque) { + let (document, ipp) = data; use MovementMessage::*; match message { TranslateCanvasBegin => { @@ -78,18 +103,20 @@ impl MessageHandler { self.rotating = true; - self.snapping = snap; self.snap_rotate = snap; self.mouse_pos = ipp.mouse.position; } - EnableSnapping => self.snapping = true, - DisableSnapping => self.snapping = false, + EnableSnapping => self.snap_rotate = true, + DisableSnapping => { + self.rotation = self.snapped_angle(); + self.snap_rotate = false + } ZoomCanvasBegin => { self.zooming = true; self.mouse_pos = ipp.mouse.position; } TransformCanvasEnd => { - layer_data.rotation = self.snapped_angle(layer_data); + self.rotation = self.snapped_angle(); responses.push_back(ToolMessage::DocumentIsDirty.into()); self.snap_rotate = false; self.translating = false; @@ -101,9 +128,9 @@ impl MessageHandler { - layer_data.scale = new.clamp(VIEWPORT_ZOOM_SCALE_MIN, VIEWPORT_ZOOM_SCALE_MAX); + self.scale = new.clamp(VIEWPORT_ZOOM_SCALE_MIN, VIEWPORT_ZOOM_SCALE_MAX); + responses.push_back(FrontendMessage::SetCanvasZoom { new_zoom: self.scale }.into()); responses.push_back(ToolMessage::DocumentIsDirty.into()); - responses.push_back(FrontendMessage::SetCanvasZoom { new_zoom: layer_data.scale }.into()); responses.push_back(DocumentMessage::DirtyRenderDocumentInOutlineView.into()); - self.create_document_transform_from_layerdata(layer_data, &ipp.viewport_bounds, responses); + self.create_document_transform(&ipp.viewport_bounds, responses); } IncreaseCanvasZoom => { // TODO: Eliminate redundant code by making this call SetCanvasZoom - layer_data.scale = *VIEWPORT_ZOOM_LEVELS.iter().find(|scale| **scale > layer_data.scale).unwrap_or(&layer_data.scale); + self.scale = *VIEWPORT_ZOOM_LEVELS.iter().find(|scale| **scale > self.scale).unwrap_or(&self.scale); + responses.push_back(FrontendMessage::SetCanvasZoom { new_zoom: self.scale }.into()); responses.push_back(ToolMessage::DocumentIsDirty.into()); - responses.push_back(FrontendMessage::SetCanvasZoom { new_zoom: layer_data.scale }.into()); responses.push_back(DocumentMessage::DirtyRenderDocumentInOutlineView.into()); - self.create_document_transform_from_layerdata(layer_data, &ipp.viewport_bounds, responses); + self.create_document_transform(&ipp.viewport_bounds, responses); } DecreaseCanvasZoom => { // TODO: Eliminate redundant code by making this call SetCanvasZoom - layer_data.scale = *VIEWPORT_ZOOM_LEVELS.iter().rev().find(|scale| **scale < layer_data.scale).unwrap_or(&layer_data.scale); + self.scale = *VIEWPORT_ZOOM_LEVELS.iter().rev().find(|scale| **scale < self.scale).unwrap_or(&self.scale); + responses.push_back(FrontendMessage::SetCanvasZoom { new_zoom: self.scale }.into()); responses.push_back(ToolMessage::DocumentIsDirty.into()); - responses.push_back(FrontendMessage::SetCanvasZoom { new_zoom: layer_data.scale }.into()); responses.push_back(DocumentMessage::DirtyRenderDocumentInOutlineView.into()); - self.create_document_transform_from_layerdata(layer_data, &ipp.viewport_bounds, responses); + self.create_document_transform(&ipp.viewport_bounds, responses); } WheelCanvasZoom => { // TODO: Eliminate redundant code by making this call SetCanvasZoom @@ -176,13 +195,13 @@ impl MessageHandler { let delta = match use_y_as_x { @@ -190,14 +209,14 @@ impl MessageHandler (-ipp.mouse.scroll_delta.y as f64, 0.).into(), } * VIEWPORT_SCROLL_RATE; let transformed_delta = document.root.transform.inverse().transform_vector2(delta); - layer_data.translation += transformed_delta; + self.translation += transformed_delta; responses.push_back(ToolMessage::DocumentIsDirty.into()); - self.create_document_transform_from_layerdata(layer_data, &ipp.viewport_bounds, responses); + self.create_document_transform(&ipp.viewport_bounds, responses); } SetCanvasRotation(new) => { - layer_data.rotation = new; + self.rotation = new; + self.create_document_transform(&ipp.viewport_bounds, responses); responses.push_back(ToolMessage::DocumentIsDirty.into()); - self.create_document_transform_from_layerdata(layer_data, &ipp.viewport_bounds, responses); responses.push_back(FrontendMessage::SetCanvasRotation { new_radians: new }.into()); } ZoomCanvasToFitAll => { @@ -212,27 +231,27 @@ impl MessageHandler { let transformed_delta = document.root.transform.inverse().transform_vector2(delta); - layer_data.translation += transformed_delta; + self.translation += transformed_delta; responses.push_back(ToolMessage::DocumentIsDirty.into()); - self.create_document_transform_from_layerdata(layer_data, &ipp.viewport_bounds, responses); + self.create_document_transform(&ipp.viewport_bounds, responses); } TranslateCanvasByViewportFraction(delta) => { let transformed_delta = document.root.transform.inverse().transform_vector2(delta * ipp.viewport_bounds.size()); - layer_data.translation += transformed_delta; + self.translation += transformed_delta; responses.push_back(ToolMessage::DocumentIsDirty.into()); - self.create_document_transform_from_layerdata(layer_data, &ipp.viewport_bounds, responses); + self.create_document_transform(&ipp.viewport_bounds, responses); } } } diff --git a/editor/src/document/overlay_message_handler.rs b/editor/src/document/overlay_message_handler.rs index cd36f13b..6bd3dbae 100644 --- a/editor/src/document/overlay_message_handler.rs +++ b/editor/src/document/overlay_message_handler.rs @@ -31,7 +31,7 @@ pub struct OverlayMessageHandler { impl MessageHandler for OverlayMessageHandler { fn process_action(&mut self, message: OverlayMessage, data: (&mut LayerData, &Document, &InputPreprocessor), responses: &mut VecDeque) { - let (layerdata, document, ipp) = data; + let (layer_data, document, ipp) = data; use OverlayMessage::*; match message { DispatchOperation(operation) => match self.overlays_graphene_document.handle_operation(&operation) {