55#include <wx/richmsgdlg.h>
56#include <wx/choicdlg.h>
57#include <unordered_set>
58#include <unordered_map>
62 const std::vector<PAD*>& aPads,
63 const wxString& aDialogTitle,
64 bool& aIncludeConnectedPads )
68 aIncludeConnectedPads =
true;
72 std::unordered_set<PAD*> uniquePads( aPads.begin(), aPads.end() );
75 msg.Printf(
_(
"%zu unselected pad(s) are connected to these nets. How do you want to proceed?" ),
79 details <<
_(
"Connected tracks, vias, and other non-zone copper items will still swap nets"
80 " even if you ignore the unselected pads." )
82 <<
_(
"Unselected pads:" ) <<
'\n';
84 for(
PAD*
pad : uniquePads )
87 details << wxS(
" • " ) << ( fp ? fp->
GetReference() :
_(
"<no reference designator>" ) ) << wxS(
":" )
88 <<
pad->GetNumber() <<
'\n';
92 wxRichMessageDialog dlg( aFrame, msg, aDialogTitle, wxYES_NO | wxCANCEL | wxYES_DEFAULT | wxICON_WARNING );
93 dlg.SetYesNoLabels(
_(
"Ignore Unselected Pads" ),
_(
"Swap All Connected Pads" ) );
94 dlg.SetExtendedMessage( details );
96 int ret = dlg.ShowModal();
98 if( ret == wxID_CANCEL )
101 aIncludeConnectedPads = ( ret == wxID_NO );
122 for(
int i = aCollector.
GetCount() - 1; i >= 0; --i )
127 aCollector.
Remove( item );
140 commit = &localCommit;
142 std::vector<EDA_ITEM*> sorted =
selection.GetItemsSortedBySelectionOrder();
148 for(
size_t i = 0; i < sorted.size() - 1; i++ )
151 EDA_ITEM* edaItemB = sorted[( i + 1 ) % sorted.size()];
161 std::swap( aPos, bPos );
184 std::swap( aAngle, bAngle );
194 std::swap( aLayer, bLayer );
200 if( !localCommit.
Empty() )
201 localCommit.
Push(
_(
"Swap" ) );
224 std::vector<EDA_ITEM*> orderedPads =
selection.GetItemsSortedBySelectionOrder();
225 std::vector<PAD*> pads;
226 const size_t padsCount = orderedPads.size();
229 pads.push_back(
static_cast<PAD*
>(
static_cast<BOARD_ITEM*
>( it ) ) );
233 std::vector<int> originalNets( padsCount );
234 std::unordered_set<PAD*> selectedPads;
236 for(
size_t i = 0; i < padsCount; ++i )
238 originalNets[i] = pads[i]->GetNetCode();
239 selectedPads.insert( pads[i] );
244 for(
size_t i = 1; i < padsCount; ++i )
246 if( originalNets[i] != originalNets[0] )
257 auto newNetForIndex = [&](
size_t i )
259 return originalNets[( i + 1 ) % padsCount];
267 commit = &localCommit;
270 std::shared_ptr<CONNECTIVITY_DATA> connectivity =
board()->GetConnectivity();
273 std::unordered_map<BOARD_CONNECTED_ITEM*, int> itemNewNets;
274 std::vector<PAD*> nonSelectedPadsToChange;
276 for(
size_t i = 0; i < padsCount; ++i )
279 int fromNet = originalNets[i];
280 int toNet = newNetForIndex( i );
297 if( ci->GetNetCode() != fromNet )
301 itemNewNets[ci] = toNet;
305 PAD* otherPad =
static_cast<PAD*
>( ci );
307 if( !selectedPads.count( otherPad ) )
308 nonSelectedPadsToChange.push_back( otherPad );
313 bool includeConnectedPads =
true;
322 for(
size_t i = 0; i < padsCount; ++i )
324 commit->
Modify( pads[i] );
325 pads[i]->SetNetCode( newNetForIndex( i ) );
329 for(
const auto& itemNewNet : itemNewNets )
332 int newNet = itemNewNet.second;
336 PAD* p =
static_cast<PAD*
>( item );
338 if( selectedPads.count( p ) )
341 if( !includeConnectedPads )
349 if( !localCommit.
Empty() )
350 localCommit.
Push(
_(
"Swap Pad Nets" ) );
368 auto showError = [
this]()
370 frame()->ShowInfoBarError(
_(
"Gate swapping must be performed on pads within one multi-gate footprint." ) );
392 else if( fp && targetFp != fp )
399 if( fail || !targetFp || targetFp->
GetUnitInfo().size() < 2 )
409 std::vector<bool> unitHit( units.size(),
false );
410 std::vector<int> unitOrder;
412 std::vector<EDA_ITEM*> orderedPads =
selection.GetItemsSortedBySelectionOrder();
418 const wxString& padNum =
pad->GetNumber();
421 for(
size_t i = 0; i < units.size(); ++i )
423 for(
const auto& p : units[i].m_pins )
427 unitIdx =
static_cast<int>( i );
430 unitOrder.push_back( unitIdx );
443 std::vector<int> activeUnitIdx;
446 if( unitOrder.size() >= 2 )
448 activeUnitIdx = unitOrder;
449 sourceIdx = unitOrder.front();
452 else if( unitOrder.size() == 1 && aEvent.
HasParameter() )
454 sourceIdx = unitOrder.front();
455 wxString targetUnitByName = aEvent.
Parameter<wxString>();
459 for(
size_t i = 0; i < units.size(); ++i )
461 if(
static_cast<int>( i ) == sourceIdx )
464 if( units[i].m_pins.size() == units[sourceIdx].m_pins.size() && units[i].m_unitName == targetUnitByName )
466 targetIdx =
static_cast<int>( i );
476 activeUnitIdx.push_back( sourceIdx );
477 activeUnitIdx.push_back( targetIdx );
486 const size_t pinCount = units[activeUnitIdx.front()].m_pins.size();
488 for(
int idx : activeUnitIdx )
490 if( units[idx].m_pins.size() != pinCount )
492 frame()->ShowInfoBarError(
_(
"Gate swapping must be performed on gates with equal pin counts." ) );
498 const size_t unitCount = activeUnitIdx.size();
499 std::vector<std::vector<PAD*>> unitPads( unitCount );
500 std::vector<std::vector<int>> unitNets( unitCount );
502 for(
size_t ui = 0; ui < unitCount; ++ui )
504 int uidx = activeUnitIdx[ui];
505 const auto& pins = units[uidx].m_pins;
507 for(
size_t pi = 0; pi < pinCount; ++pi )
513 frame()->ShowInfoBarError(
_(
"Gate swapping failed: pad in unit missing from footprint." ) );
517 unitPads[ui].push_back( p );
525 for(
size_t pi = 0; pi < pinCount && allSame; ++pi )
527 int refNet = unitNets[0][pi];
529 for(
size_t ui = 1; ui < unitCount; ++ui )
531 if( unitNets[ui][pi] != refNet )
541 frame()->ShowInfoBarError(
_(
"Gate swapping has no effect: all selected gates have identical nets." ) );
550 commit = &localCommit;
552 std::shared_ptr<CONNECTIVITY_DATA> connectivity =
board()->GetConnectivity();
555 std::unordered_map<BOARD_CONNECTED_ITEM*, int> itemNewNets;
556 std::vector<PAD*> nonSelectedPadsToChange;
559 std::unordered_set<PAD*> swapPads;
561 for(
const auto& v : unitPads )
562 swapPads.insert( v.begin(), v.end() );
565 auto scheduleForPad = [&](
PAD*
pad,
int fromNet,
int toNet )
581 if( ci->GetNetCode() != fromNet )
584 itemNewNets[ ci ] = toNet;
588 PAD* other =
static_cast<PAD*
>( ci );
590 if( !swapPads.count( other ) )
591 nonSelectedPadsToChange.push_back( other );
597 for(
size_t pi = 0; pi < pinCount; ++pi )
599 for(
size_t ui = 0; ui < unitCount; ++ui )
602 size_t toIdx = ( ui + 1 ) % unitCount;
604 PAD* padFrom = unitPads[fromIdx][pi];
605 int fromNet = unitNets[fromIdx][pi];
606 int toNet = unitNets[toIdx][pi];
608 scheduleForPad( padFrom, fromNet, toNet );
612 bool includeConnectedPads =
true;
620 for(
size_t pi = 0; pi < pinCount; ++pi )
623 for(
size_t ui = 0; ui < unitCount; ++ui )
625 size_t toIdx = ( ui + 1 ) % unitCount;
626 PAD*
pad = unitPads[ui][pi];
627 int newNet = unitNets[toIdx][pi];
630 pad->SetNetCode( newNet );
635 for(
const auto&
kv : itemNewNets )
638 int newNet =
kv.second;
642 PAD* p =
static_cast<PAD*
>( item );
644 if( swapPads.count( p ) )
647 if( !includeConnectedPads )
655 if( !localCommit.
Empty() )
656 localCommit.
Push(
_(
"Swap Gate Nets" ) );
682 for(
int i = aCollector.
GetCount() - 1; i >= 0; --i )
687 aCollector.
Remove( item );
693 std::vector<FOOTPRINT*> footprintsToPack;
696 footprintsToPack.push_back(
static_cast<FOOTPRINT*
>( item ) );
698 if( footprintsToPack.empty() )
701 BOX2I footprintsBbox;
707 footprintsBbox.
Merge( fp->GetBoundingBox(
false ) );
713 commit.
Push(
_(
"Pack Footprints" ) );
750 localCommit.
Push(
_(
"Move" ) );
767 typedef std::numeric_limits<int> coord_limits;
769 static const double max = coord_limits::max() - (int)
COORDS_PADDING;
770 static const double min = -max;
773 testBox.
Offset( aBBoxOffset );
782 testBox.
Offset( aMovement );
790 if( testBox.
GetTop() < min )
811 std::unique_ptr<STATUS_TEXT_POPUP> statusPopup;
837 controls->ForceCursorPosition(
false );
839 auto displayConstraintsMessage =
847 msg =
_(
"Angle snap lines: 45°" );
851 msg =
_(
"Angle snap lines: 90°" );
862 auto updateStatusPopup =
863 [&](
EDA_ITEM* item,
size_t ii,
size_t count )
865 wxString popuptext =
_(
"Click to place %s (item %zu of %zu)\n"
866 "Press <esc> to cancel all; double-click to finish" );
878 msg = wxString::Format(
_(
"%s pad %s" ), fp->
GetReference(),
pad->GetNumber() );
886 statusPopup = std::make_unique<STATUS_TEXT_POPUP>(
frame() );
888 statusPopup->SetText( wxString::Format( popuptext, msg, ii, count ) );
891 std::vector<BOARD_ITEM*> sel_items;
892 std::vector<BOARD_ITEM*> orig_items;
901 orig_items.push_back( boardItem );
903 sel_items.push_back( boardItem );
911 sel_items.push_back(
pad );
921 if( moveWithReference && !
pickReferencePoint(
_(
"Select reference point for move..." ),
"",
"",
922 pickedReferencePoint ) )
927 editFrame->
PopTool( pushedEvent );
931 if( moveIndividually )
938 orig_items.push_back(
static_cast<BOARD_ITEM*
>( item ) );
941 updateStatusPopup( orig_items[ itemIdx ], itemIdx + 1, orig_items.size() );
942 statusPopup->Popup();
944 canvas()->SetStatusPopup( statusPopup->GetPanel() );
950 sel_items.push_back( orig_items[ itemIdx ] );
953 bool restore_state =
false;
957 bool updateBBox =
true;
963 bool enableLocalRatsnest =
true;
966 bool eatFirstMouseUp =
true;
971 std::unique_ptr<DRC_INTERACTIVE_COURTYARD_CLEARANCE> drc_on_move =
nullptr;
973 if( showCourtyardConflicts )
975 std::shared_ptr<DRC_ENGINE> drcEngine =
m_toolMgr->GetTool<
DRC_TOOL>()->GetDRCEngine();
977 drc_on_move->Init(
board );
980 auto configureAngleSnap =
983 std::vector<VECTOR2I> directions;
999 grid.SetSnapLineDirections( directions );
1001 if( directions.empty() )
1003 grid.ClearSnapLine();
1007 grid.SetSnapLineOrigin( originalPos );
1011 configureAngleSnap( angleSnapMode );
1012 displayConstraintsMessage( angleSnapMode );
1028 eatFirstMouseUp =
false;
1041 bool redraw3D =
false;
1045 if(
controls->GetSettings().m_lastKeyboardCursorPositionValid )
1047 VECTOR2I keyboardPos(
controls->GetSettings().m_lastKeyboardCursorPosition );
1049 grid.SetSnap(
false );
1056 m_cursor =
grid.BestSnapAnchor( mousePos, layers, selectionGrid, sel_items );
1064 originalBBox =
BOX2I();
1083 bboxMovement += movement;
1090 item->Move( movement );
1102 if( redraw3D && allowRedraw3D )
1105 if( showCourtyardConflicts && drc_on_move->m_FpInMove.size() )
1108 drc_on_move->UpdateConflicts(
m_toolMgr->GetView(),
true );
1129 enableLocalRatsnest =
false;
1142 static_cast<PCB_SHAPE*
>( item )->UpdateHatching();
1144 item->RunOnChildren(
1150 static_cast<PCB_SHAPE*
>( child )->UpdateHatching();
1161 grid.SetAuxAxes(
false );
1182 if( showCourtyardConflicts )
1184 std::vector<FOOTPRINT*>& FPs = drc_on_move->m_FpInMove;
1189 FPs.push_back(
static_cast<FOOTPRINT*
>( item ) );
1191 item->RunOnChildren(
1195 FPs.push_back(
static_cast<FOOTPRINT*
>( child ) );
1208 if( moveWithReference )
1210 selection.SetReferencePoint( pickedReferencePoint );
1215 controls->ForceCursorPosition(
true, pickedReferencePoint );
1230 item->Move(
delta );
1239 grid.SetAuxAxes(
true, snapped );
1247 originalPos =
selection.GetReferencePoint();
1263 if( enableLocalRatsnest )
1271 restore_state =
true;
1280 restore_state =
true;
1300 eatFirstMouseUp =
false;
1308 eatFirstMouseUp =
false;
1315 orig_items[itemIdx]->SetPosition( originalPos );
1317 view()->Update( orig_items[itemIdx] );
1320 if( ++itemIdx < orig_items.size() )
1328 selection.SetReferencePoint( originalPos );
1333 sel_items.push_back( nextItem );
1334 updateStatusPopup( nextItem, itemIdx + 1, orig_items.size() );
1349 if( moveIndividually )
1350 orig_items[itemIdx]->SetPosition( originalPos );
1357 configureAngleSnap( angleSnapMode );
1358 displayConstraintsMessage( angleSnapMode );
1383 }
while( ( evt =
Wait() ) );
1386 if( showCourtyardConflicts )
1387 drc_on_move->ClearConflicts(
m_toolMgr->GetView() );
1389 controls->ForceCursorPosition(
false );
1404 if( sel_items.size() == 1 && sel_items.back()->Type() ==
PCB_GENERATOR_T )
1412 if( sel_items.size() == 1 && sel_items.back()->Type() ==
PCB_GENERATOR_T )
1418 EDA_ITEMS oItems( orig_items.begin(), orig_items.end() );
1425 editFrame->
PopTool( pushedEvent );
1428 return !restore_state;
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
static TOOL_ACTION duplicate
static TOOL_ACTION doDelete
static TOOL_ACTION cursorClick
static TOOL_ACTION increment
static TOOL_ACTION selectionClear
Clear the current selection.
static TOOL_ACTION refreshPreview
static TOOL_ACTION selectItems
Select a list of items (specified as the event parameter)
virtual void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Execute the changes.
virtual void Revert() override
Revert the commit by restoring the modified items state.
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
bool SetNetCode(int aNetCode, bool aNoAssert)
Set net using a net code.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
virtual void Move(const VECTOR2I &aMoveVector)
Move this object.
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Information pertinent to a Pcbnew printed circuit board.
constexpr const Vec & GetPosition() const
constexpr BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
constexpr coord_type GetLeft() const
constexpr const Vec & GetOrigin() const
constexpr coord_type GetRight() const
constexpr const SizeVec & GetSize() const
constexpr coord_type GetTop() const
constexpr void Offset(coord_type dx, coord_type dy)
constexpr coord_type GetBottom() const
int GetCount() const
Return the number of objects in the list.
void Remove(int aIndex)
Remove the item at aIndex (first position is 0).
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr, RECURSE_MODE aRecurse=RECURSE_MODE::NO_RECURSE)
Modify a given item in the model.
void DisplayConstraintsMsg(const wxString &msg)
void SetCurrentCursor(KICURSOR aCursor)
Set the current cursor shape for this panel.
A base class for most all the KiCad significant classes used in schematics and boards.
virtual VECTOR2I GetPosition() const
virtual void SetPosition(const VECTOR2I &aPos)
wxString GetTypeDesc() const
Return a translated description of the type for this EDA_ITEM for display in user facing messages.
void SetFlags(EDA_ITEM_FLAGS aMask)
KICAD_T Type() const
Returns the type of object.
EDA_ITEM * GetParent() const
virtual const BOX2I ViewBBox() const override
Return the bounding box of the item covering all its layers.
static const TOOL_EVENT SelectedEvent
static const TOOL_EVENT SelectedItemsModified
Selected items were moved, this can be very high frequency on the canvas, use with care.
static const TOOL_EVENT SelectedItemsMoved
Used to inform tools that the selection should temporarily be non-editable.
Used when the right click button is pressed, or when the select tool is in effect.
An interface for classes handling user events controlling the view behavior such as zooming,...
bool IsBOARD_ITEM() const
LSET is a set of PCB_LAYER_IDs.
DISPLAY_OPTIONS m_Display
bool m_ShowCourtyardCollisions
static TOOL_ACTION mirrorH
Mirroring of selected items.
static TOOL_ACTION genFinishEdit
static TOOL_ACTION hideLocalRatsnest
static TOOL_ACTION genStartEdit
static TOOL_ACTION moveWithReference
move with a reference point
static TOOL_ACTION angleSnapModeChanged
Notification event when angle mode changes.
static TOOL_ACTION moveExact
Activation of the exact move tool.
static TOOL_ACTION copyWithReference
copy command with manual reference point selection
static TOOL_ACTION genCancelEdit
static TOOL_ACTION positionRelativeInteractively
static TOOL_ACTION genUpdateEdit
static TOOL_ACTION updateLocalRatsnest
static TOOL_ACTION moveIndividually
move items one-by-one
static TOOL_ACTION positionRelative
static TOOL_ACTION move
move or drag an item
static TOOL_ACTION mirrorV
static TOOL_ACTION flip
Flipping of selected objects.
static TOOL_ACTION rotateCw
Rotation of selected objects.
static TOOL_ACTION rotateCcw
Common, abstract interface for edit frames.
PCBNEW_SETTINGS * GetPcbNewSettings() const
virtual PCB_LAYER_ID GetActiveLayer() const
virtual MAGNETIC_SETTINGS * GetMagneticItemsSettings()
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
virtual void Update3DView(bool aMarkDirty, bool aRefresh, const wxString *aTitle=nullptr)
Update the 3D view, if the viewer is opened by this frame.
std::vector< EDA_ITEM * > EDA_ITEMS
Define list of drawing items for screens.
#define IS_MOVING
Item being moved.
a few functions useful in geometry calculations.
LEADER_MODE
The kind of the leader line.
@ DIRECT
Unconstrained point-to-point.
PCB_LAYER_ID
A quick note on layer IDs:
@ TOP_BOTTOM
Flip top to bottom (around the X axis)
Class to handle a set of BOARD_ITEMs.
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
@ PCB_GENERATOR_T
class PCB_GENERATOR, generator on a layer
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
@ PCB_GROUP_T
class PCB_GROUP, a set of BOARD_ITEMs
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
@ PCB_PAD_T
class PAD, a pad in a footprint
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
VECTOR2< int32_t > VECTOR2I
VECTOR2< double > VECTOR2D