diff --git a/eeschema/sch_field.cpp b/eeschema/sch_field.cpp index 5770d3aa74..fdb62bdeb0 100644 --- a/eeschema/sch_field.cpp +++ b/eeschema/sch_field.cpp @@ -1017,11 +1017,38 @@ bool SCH_FIELD::Replace( const EDA_SEARCH_DATA& aSearchData, void* aAuxData ) void SCH_FIELD::Rotate( const VECTOR2I& aCenter, bool aRotateCCW ) { + if( GetTextAngle().IsVertical() && GetHorizJustify() == GR_TEXT_H_ALIGN_LEFT ) + { + if( aRotateCCW ) + SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT ); + + SetTextAngle( ANGLE_HORIZONTAL ); + } + else if( GetTextAngle().IsVertical() && GetHorizJustify() == GR_TEXT_H_ALIGN_RIGHT ) + { + if( aRotateCCW ) + SetHorizJustify( GR_TEXT_H_ALIGN_LEFT ); + + SetTextAngle( ANGLE_HORIZONTAL ); + } + else if( GetTextAngle().IsHorizontal() && GetHorizJustify() == GR_TEXT_H_ALIGN_LEFT ) + { + if( !aRotateCCW ) + SetHorizJustify( GR_TEXT_H_ALIGN_LEFT ); + + SetTextAngle( ANGLE_VERTICAL ); + } + else if( GetTextAngle().IsHorizontal() && GetHorizJustify() == GR_TEXT_H_ALIGN_RIGHT ) + { + if( !aRotateCCW ) + SetHorizJustify( GR_TEXT_H_ALIGN_LEFT ); + + SetTextAngle( ANGLE_VERTICAL ); + } + VECTOR2I pt = GetPosition(); RotatePoint( pt, aCenter, aRotateCCW ? ANGLE_90 : ANGLE_270 ); SetPosition( pt ); - - SetTextAngle( GetTextAngle() != ANGLE_HORIZONTAL ? ANGLE_HORIZONTAL : ANGLE_VERTICAL ); } diff --git a/eeschema/sch_label.cpp b/eeschema/sch_label.cpp index 84321dff46..b8bf89c7ee 100644 --- a/eeschema/sch_label.cpp +++ b/eeschema/sch_label.cpp @@ -203,6 +203,12 @@ SPIN_STYLE SPIN_STYLE::MirrorY() } +unsigned SPIN_STYLE::CCWRotationsTo( const SPIN_STYLE& aOther ) const +{ + return ( ( (int) m_spin - (int) aOther.m_spin ) % 4 + 4 ) % 4; +} + + SCH_LABEL_BASE::SCH_LABEL_BASE( const VECTOR2I& aPos, const wxString& aText, KICAD_T aType ) : SCH_TEXT( aPos, aText, LAYER_NOTES, aType ), m_shape( L_UNSPECIFIED ), @@ -456,42 +462,7 @@ void SCH_LABEL_BASE::Rotate90( bool aClockwise ) { for( SCH_FIELD& field : m_fields ) { - if( field.GetTextAngle().IsVertical() - && field.GetHorizJustify() == GR_TEXT_H_ALIGN_LEFT ) - { - if( !aClockwise ) - field.SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT ); - - field.SetTextAngle( ANGLE_HORIZONTAL ); - } - else if( field.GetTextAngle().IsVertical() - && field.GetHorizJustify() == GR_TEXT_H_ALIGN_RIGHT ) - { - if( !aClockwise ) - field.SetHorizJustify( GR_TEXT_H_ALIGN_LEFT ); - - field.SetTextAngle( ANGLE_HORIZONTAL ); - } - else if( field.GetTextAngle().IsHorizontal() - && field.GetHorizJustify() == GR_TEXT_H_ALIGN_LEFT ) - { - if( aClockwise ) - field.SetHorizJustify( GR_TEXT_H_ALIGN_LEFT ); - - field.SetTextAngle( ANGLE_VERTICAL ); - } - else if( field.GetTextAngle().IsHorizontal() - && field.GetHorizJustify() == GR_TEXT_H_ALIGN_RIGHT ) - { - if( aClockwise ) - field.SetHorizJustify( GR_TEXT_H_ALIGN_LEFT ); - - field.SetTextAngle( ANGLE_VERTICAL ); - } - - VECTOR2I pos = field.GetTextPos(); - RotatePoint( pos, GetPosition(), aClockwise ? -ANGLE_90 : ANGLE_90 ); - field.SetTextPos( pos ); + field.Rotate( GetPosition(), !aClockwise ); } } } diff --git a/eeschema/sch_label.h b/eeschema/sch_label.h index c52fd82f90..46c90ddd96 100644 --- a/eeschema/sch_label.h +++ b/eeschema/sch_label.h @@ -81,6 +81,11 @@ public: */ SPIN_STYLE MirrorY(); + /** + * Get CCW rotation needed to get to the given spin style. + */ + unsigned CCWRotationsTo( const SPIN_STYLE& aOther ) const; + private: SPIN m_spin; }; diff --git a/eeschema/tools/sch_edit_tool.cpp b/eeschema/tools/sch_edit_tool.cpp index 2d9672fdbe..77946c09d0 100644 --- a/eeschema/tools/sch_edit_tool.cpp +++ b/eeschema/tools/sch_edit_tool.cpp @@ -1149,6 +1149,90 @@ const std::vector swappableItems = { }; +/** + * Swap the positions of the fields in the two lists, aAFields and aBFields, + * relative to their parent positions. + * + * If a field is in both lists, it will be swapped to the position of the + * matching field on the counterpart. + * + * If a field is in only one list, it will simply be rotated by aFallbackRotation + * (CW or CCW depending on which list it is in) + */ +static void swapFieldPositionsWithMatching( std::vector& aAFields, + std::vector& aBFields, + unsigned aFallbackRotationsCCW ) +{ + std::set handledKeys; + + const auto swapFieldTextProps = []( SCH_FIELD& aField, SCH_FIELD& bField ) + { + const VECTOR2I aRelPos = aField.GetPosition() - aField.GetParentPosition(); + const GR_TEXT_H_ALIGN_T aTextJustifyH = aField.GetHorizJustify(); + const GR_TEXT_V_ALIGN_T aTextJustifyV = aField.GetVertJustify(); + const EDA_ANGLE aTextAngle = aField.GetTextAngle(); + + const VECTOR2I bRelPos = bField.GetPosition() - bField.GetParentPosition(); + const GR_TEXT_H_ALIGN_T bTextJustifyH = bField.GetHorizJustify(); + const GR_TEXT_V_ALIGN_T bTextJustifyV = bField.GetVertJustify(); + const EDA_ANGLE bTextAngle = bField.GetTextAngle(); + + aField.SetPosition( aField.GetParentPosition() + bRelPos ); + aField.SetHorizJustify( bTextJustifyH ); + aField.SetVertJustify( bTextJustifyV ); + aField.SetTextAngle( bTextAngle ); + + bField.SetPosition( bField.GetParentPosition() + aRelPos ); + bField.SetHorizJustify( aTextJustifyH ); + bField.SetVertJustify( aTextJustifyV ); + bField.SetTextAngle( aTextAngle ); + }; + + for( SCH_FIELD& aField : aAFields ) + { + const wxString name = aField.GetCanonicalName(); + + auto it = std::find_if( aBFields.begin(), aBFields.end(), + [name]( const SCH_FIELD& bField ) + { + return bField.GetCanonicalName() == name; + } ); + + if( it != aBFields.end() ) + { + // We have a field with the same key in both labels + SCH_FIELD& bField = *it; + swapFieldTextProps( aField, bField ); + } + else + { + // We only have this field in A, so just rotate it + for( unsigned ii = 0; ii < aFallbackRotationsCCW; ii++ ) + { + aField.Rotate( aField.GetParentPosition(), true ); + } + } + + // And keep track that we did this one + handledKeys.insert( name ); + } + + // Any fields in B that weren't in A weren't handled and need to be rotated + // in reverse + for( SCH_FIELD& bField : aBFields ) + { + const wxString bName = bField.GetCanonicalName(); + if( handledKeys.find( bName ) == handledKeys.end() ) + { + for( unsigned ii = 0; ii < aFallbackRotationsCCW; ii++ ) + { + bField.Rotate( bField.GetParentPosition(), false ); + } + } + } +} + + int SCH_EDIT_TOOL::Swap( const TOOL_EVENT& aEvent ) { EE_SELECTION& selection = m_selectionTool->RequestSelection( swappableItems ); @@ -1217,9 +1301,26 @@ int SCH_EDIT_TOOL::Swap( const TOOL_EVENT& aEvent ) case SCH_GLOBAL_LABEL_T: case SCH_HIER_LABEL_T: case SCH_DIRECTIVE_LABEL_T: - m_frame->AutoRotateItem( screen, a ); - m_frame->AutoRotateItem( screen, b ); + { + SCH_LABEL_BASE& aLabelBase = static_cast( *a ); + SCH_LABEL_BASE& bLabelBase = static_cast( *b ); + + const SPIN_STYLE aSpinStyle = aLabelBase.GetSpinStyle(); + const SPIN_STYLE bSpinStyle = bLabelBase.GetSpinStyle(); + + // First, swap the label orientations + aLabelBase.SetSpinStyle( bSpinStyle ); + bLabelBase.SetSpinStyle( aSpinStyle ); + + // And swap the fields as best we can + std::vector& aFields = aLabelBase.GetFields(); + std::vector& bFields = bLabelBase.GetFields(); + + const unsigned rotationsAtoB = aSpinStyle.CCWRotationsTo( bSpinStyle ); + + swapFieldPositionsWithMatching( aFields, bFields, rotationsAtoB ); break; + } case SCH_SYMBOL_T: { SCH_SYMBOL* aSymbol = static_cast( a );