@@ -58,14 +58,20 @@ pub enum DocumentMessage {
58
58
WheelCanvasZoom ,
59
59
SetCanvasRotation ( f64 ) ,
60
60
NudgeSelectedLayers ( f64 , f64 ) ,
61
- FlipLayer ( Vec < LayerId > , bool , bool ) ,
61
+ FlipSelectedLayers ( FlipAxis ) ,
62
62
AlignSelectedLayers ( AlignAxis , AlignAggregate ) ,
63
63
DragLayer ( Vec < LayerId > , DVec2 ) ,
64
64
MoveSelectedLayersTo { path : Vec < LayerId > , insert_index : isize } ,
65
65
ReorderSelectedLayers ( i32 ) , // relative_position,
66
66
SetLayerTranslation ( Vec < LayerId > , Option < f64 > , Option < f64 > ) ,
67
67
}
68
68
69
+ #[ derive( PartialEq , Clone , Debug , Serialize , Deserialize ) ]
70
+ pub enum FlipAxis {
71
+ X ,
72
+ Y ,
73
+ }
74
+
69
75
#[ derive( PartialEq , Clone , Debug , Serialize , Deserialize ) ]
70
76
pub enum AlignAxis {
71
77
X ,
@@ -652,13 +658,52 @@ impl MessageHandler<DocumentMessage, &InputPreprocessor> for DocumentMessageHand
652
658
}
653
659
}
654
660
}
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
+
658
703
responses. push_back (
659
704
DocumentOperation :: SetLayerTransform {
660
705
path,
661
- transform : ( layer . transform * DAffine2 :: from_scale ( scale ) ) . to_cols_array ( ) ,
706
+ transform : transform. to_cols_array ( ) ,
662
707
}
663
708
. into ( ) ,
664
709
) ;
0 commit comments