Skip to content

Commit 6bb8357

Browse files
henryksloanKeavon
authored andcommitted
Change flipping to use the joint bounding box of the selection (#323)
* Change flipping to use the joint bounding box * Fix minor untested changes * Replace unwrap with question mark
1 parent e02250e commit 6bb8357

File tree

3 files changed

+54
-15
lines changed

3 files changed

+54
-15
lines changed

core/editor/src/document/document_message_handler.rs

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,14 +58,20 @@ pub enum DocumentMessage {
5858
WheelCanvasZoom,
5959
SetCanvasRotation(f64),
6060
NudgeSelectedLayers(f64, f64),
61-
FlipLayer(Vec<LayerId>, bool, bool),
61+
FlipSelectedLayers(FlipAxis),
6262
AlignSelectedLayers(AlignAxis, AlignAggregate),
6363
DragLayer(Vec<LayerId>, DVec2),
6464
MoveSelectedLayersTo { path: Vec<LayerId>, insert_index: isize },
6565
ReorderSelectedLayers(i32), // relative_position,
6666
SetLayerTranslation(Vec<LayerId>, Option<f64>, Option<f64>),
6767
}
6868

69+
#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)]
70+
pub enum FlipAxis {
71+
X,
72+
Y,
73+
}
74+
6975
#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)]
7076
pub enum AlignAxis {
7177
X,
@@ -652,13 +658,52 @@ impl MessageHandler<DocumentMessage, &InputPreprocessor> for DocumentMessageHand
652658
}
653659
}
654660
}
655-
FlipLayer(path, flip_horizontal, flip_vertical) => {
656-
if let Ok(layer) = self.active_document_mut().document.layer_mut(&path) {
657-
let scale = DVec2::new(if flip_horizontal { -1. } else { 1. }, if flip_vertical { -1. } else { 1. });
661+
FlipSelectedLayers(axis) => {
662+
// TODO: Handle folder nested transforms with the transforms API
663+
let selected_paths = self.selected_layers_sorted();
664+
if selected_paths.is_empty() {
665+
return;
666+
}
667+
668+
let selected_layers = selected_paths.iter().filter_map(|path| {
669+
let layer = self.active_document().document.layer(path).ok()?;
670+
// TODO: Refactor with `reduce` and `merge_bounding_boxes` once the latter is added
671+
let (min, max) = {
672+
let bounding_box = layer.bounding_box(layer.transform, layer.style)?;
673+
match axis {
674+
FlipAxis::X => (bounding_box[0].x, bounding_box[1].x),
675+
FlipAxis::Y => (bounding_box[0].y, bounding_box[1].y),
676+
}
677+
};
678+
Some((path.clone(), (min, max)))
679+
});
680+
681+
let (min, max) = selected_layers
682+
.clone()
683+
.map(|(_, extrema)| extrema)
684+
.reduce(|(min_a, max_a), (min_b, max_b)| (min_a.min(min_b), max_a.max(max_b)))
685+
.unwrap();
686+
let middle = (min + max) / 2.;
687+
688+
for (path, _) in selected_layers {
689+
let layer = self.active_document().document.layer(&path).unwrap();
690+
let mut transform = layer.transform;
691+
let scale = match axis {
692+
FlipAxis::X => DVec2::new(-1., 1.),
693+
FlipAxis::Y => DVec2::new(1., -1.),
694+
};
695+
transform = transform * DAffine2::from_scale(scale);
696+
697+
let coord = match axis {
698+
FlipAxis::X => &mut transform.translation.x,
699+
FlipAxis::Y => &mut transform.translation.y,
700+
};
701+
*coord = *coord - 2. * (*coord - middle);
702+
658703
responses.push_back(
659704
DocumentOperation::SetLayerTransform {
660705
path,
661-
transform: (layer.transform * DAffine2::from_scale(scale)).to_cols_array(),
706+
transform: transform.to_cols_array(),
662707
}
663708
.into(),
664709
);

core/editor/src/document/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ mod document_message_handler;
55
pub use document_file::{Document, LayerData};
66

77
#[doc(inline)]
8-
pub use document_message_handler::{AlignAggregate, AlignAxis, DocumentMessage, DocumentMessageDiscriminant, DocumentMessageHandler};
8+
pub use document_message_handler::{AlignAggregate, AlignAxis, DocumentMessage, DocumentMessageDiscriminant, DocumentMessageHandler, FlipAxis};

core/editor/src/tool/tools/select.rs

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use crate::input::{mouse::ViewportPosition, InputPreprocessor};
1010
use crate::tool::{DocumentToolData, Fsm, ToolActionHandlerData};
1111
use crate::{
1212
consts::SELECTION_TOLERANCE,
13-
document::{AlignAggregate, AlignAxis, Document},
13+
document::{AlignAggregate, AlignAxis, Document, FlipAxis},
1414
message_prelude::*,
1515
};
1616

@@ -173,18 +173,12 @@ impl Fsm for SelectToolFsmState {
173173
self
174174
}
175175
(_, FlipHorizontal) => {
176-
let selected_layers = document.layer_data.iter().filter_map(|(path, data)| data.selected.then(|| path.clone()));
177-
for path in selected_layers {
178-
responses.push_back(DocumentMessage::FlipLayer(path, true, false).into());
179-
}
176+
responses.push_back(DocumentMessage::FlipSelectedLayers(FlipAxis::X).into());
180177

181178
self
182179
}
183180
(_, FlipVertical) => {
184-
let selected_layers = document.layer_data.iter().filter_map(|(path, data)| data.selected.then(|| path.clone()));
185-
for path in selected_layers {
186-
responses.push_back(DocumentMessage::FlipLayer(path, false, true).into());
187-
}
181+
responses.push_back(DocumentMessage::FlipSelectedLayers(FlipAxis::Y).into());
188182

189183
self
190184
}

0 commit comments

Comments
 (0)