Browse Source

Eeschema: swap label rotations (and include fields)

This means that labels keep the position relative
to what they are connected to after the swap.

An attempt is made to map the fields of a label
into the position of a matching field (i.e. same name)
on the swapped-to label.

Move the SCH_FIELD rotation justification
handling to the SCH_FIELD class, so it's not just
SCH_LABEL that handles it.

https://gitlab.com/kicad/code/kicad/-/issues/18303
jobs
John Beard 1 year ago
parent
commit
bb100994a7
  1. 31
      eeschema/sch_field.cpp
  2. 43
      eeschema/sch_label.cpp
  3. 5
      eeschema/sch_label.h
  4. 105
      eeschema/tools/sch_edit_tool.cpp

31
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 );
}

43
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 );
}
}
}

5
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;
};

105
eeschema/tools/sch_edit_tool.cpp

@ -1149,6 +1149,90 @@ const std::vector<KICAD_T> 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<SCH_FIELD>& aAFields,
std::vector<SCH_FIELD>& aBFields,
unsigned aFallbackRotationsCCW )
{
std::set<wxString> 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<SCH_LABEL_BASE&>( *a );
SCH_LABEL_BASE& bLabelBase = static_cast<SCH_LABEL_BASE&>( *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<SCH_FIELD>& aFields = aLabelBase.GetFields();
std::vector<SCH_FIELD>& bFields = bLabelBase.GetFields();
const unsigned rotationsAtoB = aSpinStyle.CCWRotationsTo( bSpinStyle );
swapFieldPositionsWithMatching( aFields, bFields, rotationsAtoB );
break;
}
case SCH_SYMBOL_T:
{
SCH_SYMBOL* aSymbol = static_cast<SCH_SYMBOL*>( a );

Loading…
Cancel
Save