Pcbnew: point editor: move pads to a behavior class

Hopefully, this will make the extra logic for padstacks
more localised, rather than splitting it up throughout
PCB_POINT_EDITOR.
This commit is contained in:
John Beard 2024-11-02 18:49:36 +08:00
parent dd7d90089d
commit d12ad6820b

View File

@ -1269,6 +1269,226 @@ private:
}; };
class PAD_POINT_EDIT_BEHAVIOR : public POINT_EDIT_BEHAVIOR
{
public:
PAD_POINT_EDIT_BEHAVIOR( PAD& aPad ) : m_pad( aPad ) {}
void MakePoints( EDIT_POINTS& aPoints ) override
{
// TODO(JE) padstacks
VECTOR2I shapePos = m_pad.ShapePos( PADSTACK::ALL_LAYERS );
VECTOR2I halfSize( m_pad.GetSize( PADSTACK::ALL_LAYERS ).x / 2,
m_pad.GetSize( PADSTACK::ALL_LAYERS ).y / 2 );
if( m_pad.IsLocked() )
return;
switch( m_pad.GetShape( PADSTACK::ALL_LAYERS ) )
{
case PAD_SHAPE::CIRCLE:
aPoints.AddPoint( VECTOR2I( shapePos.x + halfSize.x, shapePos.y ) );
break;
case PAD_SHAPE::OVAL:
case PAD_SHAPE::TRAPEZOID:
case PAD_SHAPE::RECTANGLE:
case PAD_SHAPE::ROUNDRECT:
case PAD_SHAPE::CHAMFERED_RECT:
{
if( !m_pad.GetOrientation().IsCardinal() )
break;
if( m_pad.GetOrientation() == ANGLE_90 || m_pad.GetOrientation() == ANGLE_270 )
std::swap( halfSize.x, halfSize.y );
// It's important to fill these according to the RECT indices
aPoints.AddPoint( shapePos - halfSize );
aPoints.AddPoint( VECTOR2I( shapePos.x + halfSize.x, shapePos.y - halfSize.y ) );
aPoints.AddPoint( shapePos + halfSize );
aPoints.AddPoint( VECTOR2I( shapePos.x - halfSize.x, shapePos.y + halfSize.y ) );
}
break;
default: // suppress warnings
break;
}
}
void UpdatePoints( EDIT_POINTS& aPoints ) override
{
// TODO(JE) padstacks
bool locked = m_pad.GetParent() && m_pad.IsLocked();
VECTOR2I shapePos = m_pad.ShapePos( PADSTACK::ALL_LAYERS );
VECTOR2I halfSize( m_pad.GetSize( PADSTACK::ALL_LAYERS ).x / 2,
m_pad.GetSize( PADSTACK::ALL_LAYERS ).y / 2 );
switch( m_pad.GetShape( PADSTACK::ALL_LAYERS ) )
{
case PAD_SHAPE::CIRCLE:
{
int target = locked ? 0 : 1;
// Careful; pad shape is mutable...
if( int( aPoints.PointsSize() ) != target )
{
aPoints.Clear();
MakePoints( aPoints );
}
else if( target == 1 )
{
shapePos.x += halfSize.x;
aPoints.Point( 0 ).SetPosition( shapePos );
}
}
break;
case PAD_SHAPE::OVAL:
case PAD_SHAPE::TRAPEZOID:
case PAD_SHAPE::RECTANGLE:
case PAD_SHAPE::ROUNDRECT:
case PAD_SHAPE::CHAMFERED_RECT:
{
// Careful; pad shape and orientation are mutable...
int target = locked || !m_pad.GetOrientation().IsCardinal() ? 0 : 4;
if( int( aPoints.PointsSize() ) != target )
{
aPoints.Clear();
MakePoints( aPoints );
}
else if( target == 4 )
{
if( m_pad.GetOrientation() == ANGLE_90 || m_pad.GetOrientation() == ANGLE_270 )
std::swap( halfSize.x, halfSize.y );
aPoints.Point( RECT_TOP_LEFT ).SetPosition( shapePos - halfSize );
aPoints.Point( RECT_TOP_RIGHT )
.SetPosition(
VECTOR2I( shapePos.x + halfSize.x, shapePos.y - halfSize.y ) );
aPoints.Point( RECT_BOT_RIGHT ).SetPosition( shapePos + halfSize );
aPoints.Point( RECT_BOT_LEFT )
.SetPosition(
VECTOR2I( shapePos.x - halfSize.x, shapePos.y + halfSize.y ) );
}
break;
}
default: // suppress warnings
break;
}
}
void UpdateItem( const EDIT_POINT& aEditedPoint, EDIT_POINTS& aPoints ) override
{
// TODO(JE) padstacks
switch( m_pad.GetShape( PADSTACK::ALL_LAYERS ) )
{
case PAD_SHAPE::CIRCLE:
{
VECTOR2I end = aPoints.Point( 0 ).GetPosition();
int diameter = 2 * ( end - m_pad.GetPosition() ).EuclideanNorm();
m_pad.SetSize( PADSTACK::ALL_LAYERS, VECTOR2I( diameter, diameter ) );
break;
}
case PAD_SHAPE::OVAL:
case PAD_SHAPE::TRAPEZOID:
case PAD_SHAPE::RECTANGLE:
case PAD_SHAPE::ROUNDRECT:
case PAD_SHAPE::CHAMFERED_RECT:
{
VECTOR2I topLeft = aPoints.Point( RECT_TOP_LEFT ).GetPosition();
VECTOR2I topRight = aPoints.Point( RECT_TOP_RIGHT ).GetPosition();
VECTOR2I botLeft = aPoints.Point( RECT_BOT_LEFT ).GetPosition();
VECTOR2I botRight = aPoints.Point( RECT_BOT_RIGHT ).GetPosition();
VECTOR2I holeCenter = m_pad.GetPosition();
VECTOR2I holeSize = m_pad.GetDrillSize();
RECTANGLE_POINT_EDIT_BEHAVIOR::PinEditedCorner( aEditedPoint, aPoints, topLeft,
topRight, botLeft, botRight, holeCenter,
holeSize );
if( ( m_pad.GetOffset( PADSTACK::ALL_LAYERS ).x
|| m_pad.GetOffset( PADSTACK::ALL_LAYERS ).y )
|| ( m_pad.GetDrillSize().x && m_pad.GetDrillSize().y ) )
{
// Keep hole pinned at the current location; adjust the pad around the hole
VECTOR2I center = m_pad.GetPosition();
int dist[4];
if( isModified( aEditedPoint, aPoints.Point( RECT_TOP_LEFT ) )
|| isModified( aEditedPoint, aPoints.Point( RECT_BOT_RIGHT ) ) )
{
dist[0] = center.x - topLeft.x;
dist[1] = center.y - topLeft.y;
dist[2] = botRight.x - center.x;
dist[3] = botRight.y - center.y;
}
else
{
dist[0] = center.x - botLeft.x;
dist[1] = center.y - topRight.y;
dist[2] = topRight.x - center.x;
dist[3] = botLeft.y - center.y;
}
VECTOR2I padSize( dist[0] + dist[2], dist[1] + dist[3] );
VECTOR2I deltaOffset( padSize.x / 2 - dist[2], padSize.y / 2 - dist[3] );
if( m_pad.GetOrientation() == ANGLE_90 || m_pad.GetOrientation() == ANGLE_270 )
std::swap( padSize.x, padSize.y );
RotatePoint( deltaOffset, -m_pad.GetOrientation() );
m_pad.SetSize( PADSTACK::ALL_LAYERS, padSize );
m_pad.SetOffset( PADSTACK::ALL_LAYERS, -deltaOffset );
}
else
{
// Keep pad position at the center of the pad shape
int left, top, right, bottom;
if( isModified( aEditedPoint, aPoints.Point( RECT_TOP_LEFT ) )
|| isModified( aEditedPoint, aPoints.Point( RECT_BOT_RIGHT ) ) )
{
left = topLeft.x;
top = topLeft.y;
right = botRight.x;
bottom = botRight.y;
}
else
{
left = botLeft.x;
top = topRight.y;
right = topRight.x;
bottom = botLeft.y;
}
VECTOR2I padSize( abs( right - left ), abs( bottom - top ) );
if( m_pad.GetOrientation() == ANGLE_90 || m_pad.GetOrientation() == ANGLE_270 )
std::swap( padSize.x, padSize.y );
m_pad.SetSize( PADSTACK::ALL_LAYERS, padSize );
m_pad.SetPosition( VECTOR2I( ( left + right ) / 2, ( top + bottom ) / 2 ) );
}
break;
}
default: // suppress warnings
break;
}
}
private:
PAD& m_pad;
};
PCB_POINT_EDITOR::PCB_POINT_EDITOR() : PCB_POINT_EDITOR::PCB_POINT_EDITOR() :
PCB_TOOL_BASE( "pcbnew.PointEditor" ), PCB_TOOL_BASE( "pcbnew.PointEditor" ),
m_selectionTool( nullptr ), m_selectionTool( nullptr ),
@ -1381,45 +1601,13 @@ std::shared_ptr<EDIT_POINTS> PCB_POINT_EDITOR::makePoints( EDA_ITEM* aItem )
case PCB_PAD_T: case PCB_PAD_T:
{ {
const PAD* pad = static_cast<const PAD*>( aItem ); // Pad edit only for the footprint editor
// TODO(JE) padstacks if( m_isFootprintEditor )
VECTOR2I shapePos = pad->ShapePos( PADSTACK::ALL_LAYERS );
VECTOR2I halfSize( pad->GetSize( PADSTACK::ALL_LAYERS ).x / 2,
pad->GetSize( PADSTACK::ALL_LAYERS ).y / 2 );
if( !m_isFootprintEditor || pad->IsLocked() )
break;
switch( pad->GetShape( PADSTACK::ALL_LAYERS ) )
{ {
case PAD_SHAPE::CIRCLE: PAD& pad = static_cast<PAD&>( *aItem );
points->AddPoint( VECTOR2I( shapePos.x + halfSize.x, shapePos.y ) ); m_editorBehavior = std::make_unique<PAD_POINT_EDIT_BEHAVIOR>( pad );
break;
case PAD_SHAPE::OVAL:
case PAD_SHAPE::TRAPEZOID:
case PAD_SHAPE::RECTANGLE:
case PAD_SHAPE::ROUNDRECT:
case PAD_SHAPE::CHAMFERED_RECT:
{
if( !pad->GetOrientation().IsCardinal() )
break;
if( pad->GetOrientation() == ANGLE_90 || pad->GetOrientation() == ANGLE_270 )
std::swap( halfSize.x, halfSize.y );
points->AddPoint( shapePos - halfSize );
points->AddPoint( VECTOR2I( shapePos.x + halfSize.x, shapePos.y - halfSize.y ) );
points->AddPoint( shapePos + halfSize );
points->AddPoint( VECTOR2I( shapePos.x - halfSize.x, shapePos.y + halfSize.y ) );
} }
break; break;
default: // suppress warnings
break;
}
break;
} }
case PCB_ZONE_T: case PCB_ZONE_T:
@ -2051,114 +2239,6 @@ void PCB_POINT_EDITOR::updateItem( BOARD_COMMIT* aCommit )
getView()->Update( &table ); getView()->Update( &table );
break; break;
} }
case PCB_PAD_T:
{
PAD* pad = static_cast<PAD*>( item );
// TODO(JE) padstacks
switch( pad->GetShape( PADSTACK::ALL_LAYERS ) )
{
case PAD_SHAPE::CIRCLE:
{
VECTOR2I end = m_editPoints->Point( 0 ).GetPosition();
int diameter = 2 * ( end - pad->GetPosition() ).EuclideanNorm();
pad->SetSize( PADSTACK::ALL_LAYERS, VECTOR2I( diameter, diameter ) );
break;
}
case PAD_SHAPE::OVAL:
case PAD_SHAPE::TRAPEZOID:
case PAD_SHAPE::RECTANGLE:
case PAD_SHAPE::ROUNDRECT:
case PAD_SHAPE::CHAMFERED_RECT:
{
VECTOR2I topLeft = m_editPoints->Point( RECT_TOP_LEFT ).GetPosition();
VECTOR2I topRight = m_editPoints->Point( RECT_TOP_RIGHT ).GetPosition();
VECTOR2I botLeft = m_editPoints->Point( RECT_BOT_LEFT ).GetPosition();
VECTOR2I botRight = m_editPoints->Point( RECT_BOT_RIGHT ).GetPosition();
VECTOR2I holeCenter = pad->GetPosition();
VECTOR2I holeSize = pad->GetDrillSize();
RECTANGLE_POINT_EDIT_BEHAVIOR::PinEditedCorner( *m_editedPoint, *m_editPoints, topLeft,
topRight, botLeft, botRight, holeCenter,
holeSize );
if( ( pad->GetOffset( PADSTACK::ALL_LAYERS ).x || pad->GetOffset( PADSTACK::ALL_LAYERS ).y )
|| ( pad->GetDrillSize().x && pad->GetDrillSize().y ) )
{
// Keep hole pinned at the current location; adjust the pad around the hole
VECTOR2I center = pad->GetPosition();
int dist[4];
if( isModified( m_editPoints->Point( RECT_TOP_LEFT ) )
|| isModified( m_editPoints->Point( RECT_BOT_RIGHT ) ) )
{
dist[0] = center.x - topLeft.x;
dist[1] = center.y - topLeft.y;
dist[2] = botRight.x - center.x;
dist[3] = botRight.y - center.y;
}
else
{
dist[0] = center.x - botLeft.x;
dist[1] = center.y - topRight.y;
dist[2] = topRight.x - center.x;
dist[3] = botLeft.y - center.y;
}
VECTOR2I padSize( dist[0] + dist[2], dist[1] + dist[3] );
VECTOR2I deltaOffset( padSize.x / 2 - dist[2], padSize.y / 2 - dist[3] );
if( pad->GetOrientation() == ANGLE_90 || pad->GetOrientation() == ANGLE_270 )
std::swap( padSize.x, padSize.y );
RotatePoint( deltaOffset, -pad->GetOrientation() );
pad->SetSize( PADSTACK::ALL_LAYERS, padSize );
pad->SetOffset( PADSTACK::ALL_LAYERS, -deltaOffset );
}
else
{
// Keep pad position at the center of the pad shape
int left, top, right, bottom;
if( isModified( m_editPoints->Point( RECT_TOP_LEFT ) )
|| isModified( m_editPoints->Point( RECT_BOT_RIGHT ) ) )
{
left = topLeft.x;
top = topLeft.y;
right = botRight.x;
bottom = botRight.y;
}
else
{
left = botLeft.x;
top = topRight.y;
right = topRight.x;
bottom = botLeft.y;
}
VECTOR2I padSize( abs( right - left ), abs( bottom - top ) );
if( pad->GetOrientation() == ANGLE_90 || pad->GetOrientation() == ANGLE_270 )
std::swap( padSize.x, padSize.y );
pad->SetSize( PADSTACK::ALL_LAYERS, padSize );
pad->SetPosition( VECTOR2I( ( left + right ) / 2, ( top + bottom ) / 2 ) );
}
break;
}
default: // suppress warnings
break;
}
break;
}
case PCB_GENERATOR_T: case PCB_GENERATOR_T:
{ {
GENERATOR_TOOL* generatorTool = m_toolMgr->GetTool<GENERATOR_TOOL>(); GENERATOR_TOOL* generatorTool = m_toolMgr->GetTool<GENERATOR_TOOL>();
@ -2480,82 +2560,6 @@ void PCB_POINT_EDITOR::updatePoints()
break; break;
} }
case PCB_PAD_T:
{
// TODO(JE) padstacks
const PAD* pad = static_cast<const PAD*>( item );
bool locked = pad->GetParent() && pad->IsLocked();
VECTOR2I shapePos = pad->ShapePos( PADSTACK::ALL_LAYERS );
VECTOR2I halfSize( pad->GetSize( PADSTACK::ALL_LAYERS ).x / 2, pad->GetSize( PADSTACK::ALL_LAYERS ).y / 2 );
switch( pad->GetShape( PADSTACK::ALL_LAYERS ) )
{
case PAD_SHAPE::CIRCLE:
{
int target = locked ? 0 : 1;
// Careful; pad shape is mutable...
if( int( m_editPoints->PointsSize() ) != target )
{
getView()->Remove( m_editPoints.get() );
m_editedPoint = nullptr;
m_editPoints = makePoints( item );
if( m_editPoints )
getView()->Add( m_editPoints.get() );
}
else if( target == 1 )
{
shapePos.x += halfSize.x;
m_editPoints->Point( 0 ).SetPosition( shapePos );
}
}
break;
case PAD_SHAPE::OVAL:
case PAD_SHAPE::TRAPEZOID:
case PAD_SHAPE::RECTANGLE:
case PAD_SHAPE::ROUNDRECT:
case PAD_SHAPE::CHAMFERED_RECT:
{
// Careful; pad shape and orientation are mutable...
int target = locked || !pad->GetOrientation().IsCardinal() ? 0 : 4;
if( int( m_editPoints->PointsSize() ) != target )
{
getView()->Remove( m_editPoints.get() );
m_editedPoint = nullptr;
m_editPoints = makePoints( item );
if( m_editPoints )
getView()->Add( m_editPoints.get() );
}
else if( target == 4 )
{
if( pad->GetOrientation() == ANGLE_90 || pad->GetOrientation() == ANGLE_270 )
std::swap( halfSize.x, halfSize.y );
m_editPoints->Point( RECT_TOP_LEFT ).SetPosition( shapePos - halfSize );
m_editPoints->Point( RECT_TOP_RIGHT )
.SetPosition(
VECTOR2I( shapePos.x + halfSize.x, shapePos.y - halfSize.y ) );
m_editPoints->Point( RECT_BOT_RIGHT ).SetPosition( shapePos + halfSize );
m_editPoints->Point( RECT_BOT_LEFT )
.SetPosition(
VECTOR2I( shapePos.x - halfSize.x, shapePos.y + halfSize.y ) );
}
break;
}
default: // suppress warnings
break;
}
}
break;
case PCB_GENERATOR_T: case PCB_GENERATOR_T:
{ {
PCB_GENERATOR* generator = static_cast<PCB_GENERATOR*>( item ); PCB_GENERATOR* generator = static_cast<PCB_GENERATOR*>( item );