From ddcc23865a4a93639a0e4c60db66c664da8ccc09 Mon Sep 17 00:00:00 2001 From: Oliver Davies Date: Fri, 7 Jan 2022 03:41:57 -0800 Subject: [PATCH] WIP conversion to messages --- editor/src/tool/snapping.rs | 79 +++++++++++++++---------- editor/src/tool/tool_message_handler.rs | 5 ++ 2 files changed, 52 insertions(+), 32 deletions(-) diff --git a/editor/src/tool/snapping.rs b/editor/src/tool/snapping.rs index e5579302d9..4891f30617 100644 --- a/editor/src/tool/snapping.rs +++ b/editor/src/tool/snapping.rs @@ -1,5 +1,6 @@ -use std::f64::consts::PI; +use std::{collections::HashMap, f64::consts::PI}; +use super::DocumentMessageHandler; use glam::{DAffine2, DVec2}; use graphene::{ layers::style::{self, Stroke}, @@ -11,41 +12,40 @@ use crate::{ message_prelude::*, }; -use super::DocumentMessageHandler; - #[derive(Debug, Clone, Default)] pub struct SnapHandler { + enabled: bool, + document: DocumentMessageHandler, snap_targets: Option<(Vec, Vec)>, + snappables: HashMap, Vec>>, + overlay_messages: Vec, + overlay_paths: Vec>, } impl SnapHandler { - fn add_overlays(&mut self, responses: &mut VecDeque, viewport_bounds: DVec2) { - fn add_overlay_line(responses: &mut VecDeque, transform: DAffine2) -> Vec { - let layer_path = vec![generate_uuid()]; + fn add_overlay_line(&mut self, transform: DAffine2) -> Vec { + let layer_path = vec![generate_uuid()]; - let operation = Operation::AddOverlayLine { - path: layer_path.clone(), - transform: transform.to_cols_array(), - style: style::PathStyle::new(Some(Stroke::new(COLOR_ACCENT, 1.0)), None), - }; - responses.push_back(DocumentMessage::Overlay(operation.into()).into()); + let operation = Operation::AddOverlayLine { + path: layer_path.clone(), + transform: transform.to_cols_array(), + style: style::PathStyle::new(Some(Stroke::new(COLOR_ACCENT, 1.0)), None), + }; + self.overlay_messages.push(DocumentMessage::Overlay(operation.into()).into()); - layer_path - } + layer_path + } + fn add_overlays(&mut self, viewport_bounds: DVec2) { if let Some((x_targets, y_targets)) = &self.snap_targets { for x_target in x_targets { - self.overlay_paths.push(add_overlay_line( - responses, - DAffine2::from_scale_angle_translation(DVec2::new(viewport_bounds.y, 1.), PI / 2., DVec2::new(x_target.round(), 0.)), - )); + self.overlay_paths + .push(self.add_overlay_line(DAffine2::from_scale_angle_translation(DVec2::new(viewport_bounds.y, 1.), PI / 2., DVec2::new(x_target.round(), 0.)))); } for y_target in y_targets { - self.overlay_paths.push(add_overlay_line( - responses, - DAffine2::from_scale_angle_translation(DVec2::new(viewport_bounds.x, 1.), 0., DVec2::new(0., y_target.round())), - )); + self.overlay_paths + .push(self.add_overlay_line(DAffine2::from_scale_angle_translation(DVec2::new(viewport_bounds.x, 1.), 0., DVec2::new(0., y_target.round())))); } } } @@ -58,29 +58,30 @@ impl SnapHandler { /// Gets a list of snap targets for the X and Y axes in Viewport coords for the target layers (usually all layers or all non-selected layers.) /// This should be called at the start of a drag. - pub fn start_snap(&mut self, responses: &mut VecDeque, viewport_bounds: DVec2, document_message_handler: &DocumentMessageHandler, target_layers: Vec>) { - if document_message_handler.snapping_enabled { + pub fn start_snap(&mut self, viewport_bounds: DVec2, target_layers: Vec>) { + if self.document.snapping_enabled { // Could be made into sorted Vec or a HashSet for more performant lookups. self.snap_targets = Some( target_layers .iter() - .filter_map(|path| document_message_handler.graphene_document.viewport_bounding_box(path).ok()?) + .filter_map(|path| self.document.graphene_document.viewport_bounding_box(path).ok()?) .flat_map(|[bound1, bound2]| [bound1, bound2, ((bound1 + bound2) / 2.)]) .map(|vec| vec.into()) .unzip(), ); - self.add_overlays(responses, viewport_bounds); + self.add_overlays(viewport_bounds); } } /// Finds the closest snap from an array of layers to the specified snap targets in viewport coords. /// Returns 0 for each axis that there is no snap less than the snap tolerance. - pub fn snap_layers(&self, document_message_handler: &DocumentMessageHandler, selected_layers: &[Vec], mouse_delta: DVec2) -> DVec2 { - if document_message_handler.snapping_enabled { + pub fn snap_layers(&self, mouse_delta: DVec2) -> DVec2 { + if self.enabled { if let Some((targets_x, targets_y)) = &self.snap_targets { - let (snap_x, snap_y): (Vec, Vec) = selected_layers + let (snap_x, snap_y): (Vec, Vec) = self + .snappables .iter() - .filter_map(|path| document_message_handler.graphene_document.viewport_bounding_box(path).ok()?) + .filter_map(|(path, _)| self.document.graphene_document.viewport_bounding_box(path).ok()?) .flat_map(|[bound1, bound2]| [bound1, bound2, (bound1 + bound2) / 2.]) .map(|vec| vec.into()) .unzip(); @@ -112,8 +113,8 @@ impl SnapHandler { } /// Handles snapping of a viewport position, returning another viewport position. - pub fn snap_position(&self, document_message_handler: &DocumentMessageHandler, position_viewport: DVec2) -> DVec2 { - if document_message_handler.snapping_enabled { + pub fn snap_position(&self, position_viewport: DVec2) -> DVec2 { + if self.document.snapping_enabled { if let Some((targets_x, targets_y)) = &self.snap_targets { // For each list of snap targets, find the shortest distance to move the point to that target. let closest_move = DVec2::new( @@ -148,4 +149,18 @@ impl SnapHandler { self.remove_overlays(responses); self.snap_targets = None; } + + // --- + pub fn add_snappable(&mut self, layer: Vec) { + self.snappables.insert(layer, vec![]); + } + + pub fn remove_snappable(&mut self, layer: Vec) { + self.snappables.remove(&layer); + } + + pub fn process_overlays(&mut self, responses: &mut VecDeque) { + responses.extend(self.overlay_messages.into_iter()); + self.overlay_messages.clear(); + } } diff --git a/editor/src/tool/tool_message_handler.rs b/editor/src/tool/tool_message_handler.rs index b67294b471..57f4bf4f7b 100644 --- a/editor/src/tool/tool_message_handler.rs +++ b/editor/src/tool/tool_message_handler.rs @@ -1,4 +1,5 @@ use crate::message_prelude::*; +use glam::DVec2; use graphene::color::Color; use crate::input::InputPreprocessor; @@ -21,6 +22,10 @@ pub enum ToolMessage { DocumentIsDirty, UpdateHints, SetToolOptions(ToolType, ToolOptions), + SetSnapping(bool), + AddSnappable(Vec), + RemoveSnappable(Vec), + SnapLayer(Vec), #[child] Fill(FillMessage), #[child]