From de6e368ac66792051f7a3d142f40623bbb6b44ae Mon Sep 17 00:00:00 2001 From: Mike Williams Date: Mon, 29 Aug 2022 15:07:16 -0400 Subject: [PATCH] PCB: Swap Tool --- pcbnew/tools/edit_tool.cpp | 2 + pcbnew/tools/edit_tool.h | 5 ++ pcbnew/tools/edit_tool_move_fct.cpp | 110 ++++++++++++++++++++++++++++ pcbnew/tools/pcb_actions.cpp | 5 ++ pcbnew/tools/pcb_actions.h | 3 + 5 files changed, 125 insertions(+) diff --git a/pcbnew/tools/edit_tool.cpp b/pcbnew/tools/edit_tool.cpp index 0ea8c7f085..e144e11c39 100644 --- a/pcbnew/tools/edit_tool.cpp +++ b/pcbnew/tools/edit_tool.cpp @@ -191,6 +191,7 @@ bool EDIT_TOOL::Init() menu.AddItem( PCB_ACTIONS::rotateCw, SELECTION_CONDITIONS::NotEmpty ); menu.AddItem( PCB_ACTIONS::flip, SELECTION_CONDITIONS::NotEmpty ); menu.AddItem( PCB_ACTIONS::mirror, inFootprintEditor && SELECTION_CONDITIONS::NotEmpty ); + menu.AddItem( PCB_ACTIONS::swap, SELECTION_CONDITIONS::MoreThan( 1 ) ); menu.AddItem( PCB_ACTIONS::properties, propertiesCondition ); @@ -2197,6 +2198,7 @@ void EDIT_TOOL::setTransitions() Go( &EDIT_TOOL::Duplicate, PCB_ACTIONS::duplicateIncrement.MakeEvent() ); Go( &EDIT_TOOL::CreateArray, PCB_ACTIONS::createArray.MakeEvent() ); Go( &EDIT_TOOL::Mirror, PCB_ACTIONS::mirror.MakeEvent() ); + Go( &EDIT_TOOL::Swap, PCB_ACTIONS::swap.MakeEvent() ); Go( &EDIT_TOOL::ChangeTrackWidth, PCB_ACTIONS::changeTrackWidth.MakeEvent() ); Go( &EDIT_TOOL::FilletTracks, PCB_ACTIONS::filletTracks.MakeEvent() ); diff --git a/pcbnew/tools/edit_tool.h b/pcbnew/tools/edit_tool.h index a42a18e4d8..f82b3f38f9 100644 --- a/pcbnew/tools/edit_tool.h +++ b/pcbnew/tools/edit_tool.h @@ -111,6 +111,11 @@ public: */ int Mirror( const TOOL_EVENT& aEvent ); + /** + * Swap currently selected items' positions. Changes position of each item to the next. + */ + int Swap( const TOOL_EVENT& aEvent ); + int ChangeTrackWidth( const TOOL_EVENT& aEvent ); /** diff --git a/pcbnew/tools/edit_tool_move_fct.cpp b/pcbnew/tools/edit_tool_move_fct.cpp index c30816c8ef..8f68cd8b60 100644 --- a/pcbnew/tools/edit_tool_move_fct.cpp +++ b/pcbnew/tools/edit_tool_move_fct.cpp @@ -270,6 +270,116 @@ bool DRC_TEST_PROVIDER_COURTYARD_CLEARANCE_ON_MOVE::Run() } +int EDIT_TOOL::Swap( const TOOL_EVENT& aEvent ) +{ + if( isRouterActive() || m_dragging ) + { + wxBell(); + return 0; + } + + PCB_SELECTION& selection = m_selectionTool->RequestSelection( + []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool ) + { + sTool->FilterCollectorForMarkers( aCollector ); + sTool->FilterCollectorForHierarchy( aCollector, true ); + sTool->FilterCollectorForFreePads( aCollector ); + }, + true /* prompt user regarding locked items */ ); + + if( selection.Size() < 2 ) + return 0; + + std::vector sorted = selection.GetItemsSortedBySelectionOrder(); + + // When editing footprints, all items have the same parent + if( IsFootprintEditor() ) + { + m_commit->Modify( selection.Front() ); + } + else + { + // Save items, so changes can be undone + for( EDA_ITEM* item : selection ) + { + // Don't double move footprint pads, fields, etc. + // + // For PCB_GROUP_T, the parent is the board. + if( item->GetParent() && item->GetParent()->IsSelected() ) + continue; + + m_commit->Modify( item ); + + // If moving a group, record position of all the descendants for undo + if( item->Type() == PCB_GROUP_T ) + { + PCB_GROUP* group = static_cast( item ); + group->RunOnDescendants( [&]( BOARD_ITEM* bItem ) + { + m_commit->Modify( bItem ); + }); + } + } + } + + for( size_t i = 0; i < sorted.size() - 1; i++ ) + { + BOARD_ITEM* a = static_cast( sorted[i] ); + BOARD_ITEM* b = static_cast( sorted[( i + 1 ) % sorted.size()] ); + + // Swap X,Y position + VECTOR2I aPos = a->GetPosition(), bPos = b->GetPosition(); + std::swap( aPos, bPos ); + a->SetPosition( aPos ); + b->SetPosition( bPos ); + + // Pads need special handling to keep their offset from their parent + if( a->Type() == PCB_PAD_T ) + static_cast( a )->SetLocalCoord(); + + if( b->Type() == PCB_PAD_T ) + static_cast( b )->SetLocalCoord(); + + // Handle footprints specially. They can be flipped to the back of the board which + // requires a special transformation. + if( a->Type() == PCB_FOOTPRINT_T && b->Type() == PCB_FOOTPRINT_T ) + { + FOOTPRINT* aFP = static_cast( a ); + FOOTPRINT* bFP = static_cast( b ); + + // Flip both if needed + if( aFP->IsFlipped() != bFP->IsFlipped() ) + { + aFP->Flip( aPos, false ); + bFP->Flip( bPos, false ); + } + + // Set orientation + EDA_ANGLE aAngle = aFP->GetOrientation(), bAngle = bFP->GetOrientation(); + std::swap( aAngle, bAngle ); + aFP->SetOrientation( aAngle ); + bFP->SetOrientation( bAngle ); + } + // We can also do a layer swap safely for two objects of the same type, + // except groups which don't support layer swaps. + else if( a->Type() == b->Type() && a->Type() != PCB_GROUP_T ) + { + // Swap layers + PCB_LAYER_ID aLayer = a->GetLayer(), bLayer = b->GetLayer(); + std::swap( aLayer, bLayer ); + a->SetLayer( aLayer ); + b->SetLayer( bLayer ); + } + } + + m_commit->Push( _( "Swap" ) ); + + m_toolMgr->ProcessEvent( EVENTS::SelectedItemsModified ); + + return 0; +} + + int EDIT_TOOL::Move( const TOOL_EVENT& aEvent ) { if( isRouterActive() ) diff --git a/pcbnew/tools/pcb_actions.cpp b/pcbnew/tools/pcb_actions.cpp index 732a9ac4d4..c26bab176b 100644 --- a/pcbnew/tools/pcb_actions.cpp +++ b/pcbnew/tools/pcb_actions.cpp @@ -325,6 +325,11 @@ TOOL_ACTION PCB_ACTIONS::mirror( "pcbnew.InteractiveEdit.mirror", _( "Mirror" ), _( "Mirrors selected item" ), BITMAPS::mirror_h ); +TOOL_ACTION PCB_ACTIONS::swap( "pcbnew.InteractiveEdit.swap", + AS_GLOBAL, 0, "", + _( "Swap" ), _( "Swaps selected items' positions" ), + BITMAPS::swap_layer ); + TOOL_ACTION PCB_ACTIONS::changeTrackWidth( "pcbnew.InteractiveEdit.changeTrackWidth", AS_GLOBAL, 0, "", _( "Change Track Width" ), _( "Updates selected track & via sizes" ) ); diff --git a/pcbnew/tools/pcb_actions.h b/pcbnew/tools/pcb_actions.h index ce5d24bb5b..dbb479e656 100644 --- a/pcbnew/tools/pcb_actions.h +++ b/pcbnew/tools/pcb_actions.h @@ -116,6 +116,9 @@ public: /// Mirroring of selected items static TOOL_ACTION mirror; + /// Swapping of selected items + static TOOL_ACTION swap; + /// Update selected tracks & vias to the current track & via dimensions static TOOL_ACTION changeTrackWidth;