@@ -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 ) ]
7076pub 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 ) ;
0 commit comments