diff --git a/core/editor/src/document/document_message_handler.rs b/core/editor/src/document/document_message_handler.rs index 6221fb156d..63b32efa4f 100644 --- a/core/editor/src/document/document_message_handler.rs +++ b/core/editor/src/document/document_message_handler.rs @@ -57,6 +57,7 @@ pub enum DocumentMessage { SetCanvasRotation(f64), NudgeSelectedLayers(f64, f64), FlipLayer(Vec, bool, bool), + DragLayer(Vec, DVec2), MoveSelectedLayersTo { path: Vec, insert_index: isize }, ReorderSelectedLayers(i32), // relatve_position, } @@ -647,6 +648,20 @@ impl MessageHandler for DocumentMessageHand ); } } + DragLayer(path, offset) => { + // TODO: Replace root transformations with functions of the transform api + // and do the same with all instances of `root.transform.inverse()` in other messages + let transformed_mouse_pos = self.active_document().document.root.transform.inverse().transform_vector2(ipp.mouse.position.as_dvec2()); + let translation = offset + transformed_mouse_pos; + if let Ok(layer) = self.active_document_mut().document.layer_mut(&path) { + let transform = { + let mut transform = layer.transform; + transform.translation = translation; + transform.to_cols_array() + }; + responses.push_back(DocumentOperation::SetLayerTransform { path, transform }.into()); + } + } message => todo!("document_action_handler does not implement: {}", message.to_discriminant().global_name()), } } diff --git a/core/editor/src/tool/tools/select.rs b/core/editor/src/tool/tools/select.rs index 590298d4f0..ba0e42dcf8 100644 --- a/core/editor/src/tool/tools/select.rs +++ b/core/editor/src/tool/tools/select.rs @@ -57,6 +57,7 @@ impl Default for SelectToolFsmState { struct SelectToolData { drag_start: ViewportPosition, drag_current: ViewportPosition, + layers_dragging: Vec<(Vec, DVec2)>, // Paths and offsets } impl Fsm for SelectToolFsmState { @@ -71,33 +72,13 @@ impl Fsm for SelectToolFsmState { (Ready, DragStart) => { data.drag_start = input.mouse.position; data.drag_current = input.mouse.position; - responses.push_back(Operation::MountWorkingFolder { path: vec![] }.into()); - Dragging - } - (Dragging, MouseMove) => { - data.drag_current = input.mouse.position; - - responses.push_back(Operation::ClearWorkingFolder.into()); - responses.push_back(make_operation(data, tool_data, transform)); - - Dragging - } - (Dragging, DragStop) => { - data.drag_current = input.mouse.position; - responses.push_back(Operation::ClearWorkingFolder.into()); - - let (point_1, point_2) = if data.drag_start == data.drag_current { - let (x, y) = (data.drag_current.x as f64, data.drag_current.y as f64); + let (point_1, point_2) = { + let (x, y) = (data.drag_start.x as f64, data.drag_start.y as f64); ( DVec2::new(x - SELECTION_TOLERANCE, y - SELECTION_TOLERANCE), DVec2::new(x + SELECTION_TOLERANCE, y + SELECTION_TOLERANCE), ) - } else { - ( - DVec2::new(data.drag_start.x as f64, data.drag_start.y as f64), - DVec2::new(data.drag_current.x as f64, data.drag_current.y as f64), - ) }; let quad = [ @@ -107,21 +88,77 @@ impl Fsm for SelectToolFsmState { DVec2::new(point_1.x, point_2.y), ]; - responses.push_back(Operation::DiscardWorkingFolder.into()); - if data.drag_start == data.drag_current { - if let Some(intersection) = document.document.intersects_quad_root(quad).last() { - responses.push_back(DocumentMessage::SelectLayers(vec![intersection.clone()]).into()); + if let Some(intersection) = document.document.intersects_quad_root(quad).last() { + // TODO: Replace root transformations with functions of the transform api + let transformed_start = document.document.root.transform.inverse().transform_vector2(data.drag_start.as_dvec2()); + if document.layer_data.get(intersection).map_or(false, |layer_data| layer_data.selected) { + data.layers_dragging = document + .layer_data + .iter() + .filter_map(|(path, layer_data)| { + layer_data + .selected + .then(|| (path.clone(), document.document.layer(path).unwrap().transform.translation - transformed_start)) + }) + .collect(); } else { + responses.push_back(DocumentMessage::SelectLayers(vec![intersection.clone()]).into()); + data.layers_dragging = vec![(intersection.clone(), document.document.layer(intersection).unwrap().transform.translation - transformed_start)] + } + } else { + responses.push_back(Operation::MountWorkingFolder { path: vec![] }.into()); + data.layers_dragging = Vec::new(); + } + + Dragging + } + (Dragging, MouseMove) => { + data.drag_current = input.mouse.position; + + if data.layers_dragging.is_empty() { + responses.push_back(Operation::ClearWorkingFolder.into()); + responses.push_back(make_operation(data, tool_data, transform)); + } else { + for (path, offset) in &data.layers_dragging { + responses.push_back(DocumentMessage::DragLayer(path.clone(), offset.clone()).into()); + } + } + + Dragging + } + (Dragging, DragStop) => { + data.drag_current = input.mouse.position; + + if data.layers_dragging.is_empty() { + responses.push_back(Operation::ClearWorkingFolder.into()); + responses.push_back(Operation::DiscardWorkingFolder.into()); + + if data.drag_start == data.drag_current { responses.push_back(DocumentMessage::SelectLayers(vec![]).into()); + } else { + let (point_1, point_2) = ( + DVec2::new(data.drag_start.x as f64, data.drag_start.y as f64), + DVec2::new(data.drag_current.x as f64, data.drag_current.y as f64), + ); + + let quad = [ + DVec2::new(point_1.x, point_1.y), + DVec2::new(point_2.x, point_1.y), + DVec2::new(point_2.x, point_2.y), + DVec2::new(point_1.x, point_2.y), + ]; + + responses.push_back(DocumentMessage::SelectLayers(document.document.intersects_quad_root(quad)).into()); } } else { - responses.push_back(DocumentMessage::SelectLayers(document.document.intersects_quad_root(quad)).into()); + data.layers_dragging = Vec::new(); } Ready } (Dragging, Abort) => { responses.push_back(Operation::DiscardWorkingFolder.into()); + data.layers_dragging = Vec::new(); Ready }