96 return static_cast<FOOTPRINT*
>( aItem )->GetBoundingBox(
false );
102template<
typename T >
104 std::vector<std::pair<BOARD_ITEM*, BOX2I>>& aLocked,
112 if( aLocked.size() >= 1 )
114 for(
const std::pair<BOARD_ITEM*, BOX2I>& item : aLocked )
116 if( item.second.Contains( curPos ) )
117 return aGetValue( item );
120 return aGetValue( aLocked.front() );
123 for(
const std::pair<BOARD_ITEM*, BOX2I>& item : aItems )
125 if( item.second.Contains( curPos ) )
126 return aGetValue( item );
129 return aGetValue( aItems.front() );
133template<
typename T >
135 std::vector<std::pair<BOARD_ITEM*, BOX2I>>& aLockedItems,
142 for(
int i = aCollector.
GetCount() - 1; i >= 0; --i )
147 aCollector.
Remove( item );
153 bool differentParents =
false;
155 ||
m_frame->GetPcbNewSettings()->m_AllowFreePads;
159 if( !item->IsBOARD_ITEM() )
172 currentParent = parent;
173 else if( parent != currentParent )
174 differentParents =
true;
178 []( std::vector<std::pair<BOARD_ITEM*, BOX2I>>& list,
BOARD_ITEM* item,
FOOTPRINT* parentFp )
180 BOARD_ITEM* listItem = parentFp ? parentFp : item;
182 for(
const auto& [candidate, bbox] : list )
184 if( candidate == listItem )
188 list.emplace_back( std::make_pair( listItem,
getBoundingBox( item ) ) );
198 if( boardItem->
Type() ==
PCB_PAD_T && ( !allowFreePads || ( allPads && differentParents ) ) )
202 if( parentFp && parentFp->
IsLocked() )
203 addToList( aLockedItems, boardItem, parentFp );
205 addToList( aItemsToAlign, boardItem, parentFp );
211 addToList( aLockedItems, boardItem,
nullptr );
213 addToList( aItemsToAlign, boardItem,
nullptr );
216 std::sort( aItemsToAlign.begin(), aItemsToAlign.end(), aCompare );
217 std::sort( aLockedItems.begin(), aLockedItems.end(), aCompare );
219 return aItemsToAlign.size();
225 std::vector<std::pair<BOARD_ITEM*, BOX2I>> itemsToAlign;
226 std::vector<std::pair<BOARD_ITEM*, BOX2I>> locked_items;
229 [](
const std::pair<BOARD_ITEM*, BOX2I>& lhs,
const std::pair<BOARD_ITEM*, BOX2I>& rhs )
231 return ( lhs.second.GetTop() < rhs.second.GetTop() );
239 int targetTop =
selectTarget( itemsToAlign, locked_items,
240 [](
const std::pair<BOARD_ITEM*, BOX2I>& aVal )
242 return aVal.second.GetTop();
246 for(
const auto& [item, bbox] : itemsToAlign )
248 if( item->GetParent() && item->GetParent()->IsSelected() )
251 int difference = targetTop - bbox.GetTop();
254 item->Move(
VECTOR2I( 0, difference ) );
257 commit.
Push(
_(
"Align to Top" ) );
264 std::vector<std::pair<BOARD_ITEM*, BOX2I>> itemsToAlign;
265 std::vector<std::pair<BOARD_ITEM*, BOX2I>> locked_items;
268 [](
const std::pair<BOARD_ITEM*, BOX2I>& lhs,
const std::pair<BOARD_ITEM*, BOX2I>& rhs)
270 return ( lhs.second.GetBottom() > rhs.second.GetBottom() );
278 int targetBottom =
selectTarget( itemsToAlign, locked_items,
279 [](
const std::pair<BOARD_ITEM*, BOX2I>& aVal )
281 return aVal.second.GetBottom();
285 for(
const auto& [item, bbox] : itemsToAlign )
287 if( item->GetParent() && item->GetParent()->IsSelected() )
290 int difference = targetBottom - bbox.GetBottom();
293 item->Move(
VECTOR2I( 0, difference ) );
296 commit.
Push(
_(
"Align to Bottom" ) );
314 std::vector<std::pair<BOARD_ITEM*, BOX2I>> itemsToAlign;
315 std::vector<std::pair<BOARD_ITEM*, BOX2I>> locked_items;
318 [](
const std::pair<BOARD_ITEM*, BOX2I>& lhs,
const std::pair<BOARD_ITEM*, BOX2I>& rhs )
320 return ( lhs.second.GetLeft() < rhs.second.GetLeft() );
328 int targetLeft =
selectTarget( itemsToAlign, locked_items,
329 [](
const std::pair<BOARD_ITEM*, BOX2I>& aVal )
331 return aVal.second.GetLeft();
335 for(
const auto& [item, bbox] : itemsToAlign )
337 if( item->GetParent() && item->GetParent()->IsSelected() )
340 int difference = targetLeft - bbox.GetLeft();
343 item->Move(
VECTOR2I( difference, 0 ) );
346 commit.
Push(
_(
"Align to Left" ) );
364 std::vector<std::pair<BOARD_ITEM*, BOX2I>> itemsToAlign;
365 std::vector<std::pair<BOARD_ITEM*, BOX2I>> locked_items;
368 [](
const std::pair<BOARD_ITEM*, BOX2I>& lhs,
const std::pair<BOARD_ITEM*, BOX2I>& rhs )
370 return ( lhs.second.GetRight() > rhs.second.GetRight() );
378 int targetRight =
selectTarget( itemsToAlign, locked_items,
379 [](
const std::pair<BOARD_ITEM*, BOX2I>& aVal )
381 return aVal.second.GetRight();
385 for(
const auto& [item, bbox] : itemsToAlign )
387 if( item->GetParent() && item->GetParent()->IsSelected() )
390 int difference = targetRight - bbox.GetRight();
393 item->Move(
VECTOR2I( difference, 0 ) );
396 commit.
Push(
_(
"Align to Right" ) );
403 std::vector<std::pair<BOARD_ITEM*, BOX2I>> itemsToAlign;
404 std::vector<std::pair<BOARD_ITEM*, BOX2I>> locked_items;
407 [](
const std::pair<BOARD_ITEM*, BOX2I>& lhs,
const std::pair<BOARD_ITEM*, BOX2I>& rhs )
409 return ( lhs.second.Centre().x < rhs.second.Centre().x );
418 [](
const std::pair<BOARD_ITEM*, BOX2I>& aVal )
420 return aVal.second.Centre().x;
424 for(
const auto& [item, bbox] : itemsToAlign )
426 if( item->GetParent() && item->GetParent()->IsSelected() )
429 int difference = targetX - bbox.Centre().x;
432 item->Move(
VECTOR2I( difference, 0 ) );
435 commit.
Push(
_(
"Align to Middle" ) );
442 std::vector<std::pair<BOARD_ITEM*, BOX2I>> itemsToAlign;
443 std::vector<std::pair<BOARD_ITEM*, BOX2I>> locked_items;
446 [](
const std::pair<BOARD_ITEM*, BOX2I>& lhs,
const std::pair<BOARD_ITEM*, BOX2I>& rhs )
448 return ( lhs.second.Centre().y < rhs.second.Centre().y );
457 [](
const std::pair<BOARD_ITEM*, BOX2I>& aVal )
459 return aVal.second.Centre().y;
463 for(
const auto& [item, bbox] : itemsToAlign )
465 if( item->GetParent() && item->GetParent()->IsSelected() )
468 int difference = targetY - bbox.Centre().y;
471 item->Move(
VECTOR2I( 0, difference ) );
474 commit.
Push(
_(
"Align to Center" ) );
495 if( selection.
Size() < 3 )
500 std::vector<std::pair<BOARD_ITEM*, BOX2I>> itemsToDistribute;
504 if( !item->IsBOARD_ITEM() )
508 itemsToDistribute.emplace_back( std::make_pair( boardItem,
getBoundingBox( boardItem ) ) );
532 commit.
Push( commitMsg );
538 std::vector<std::pair<BOARD_ITEM*, BOX2I>>& aItems,
546 std::sort( aItems.begin(), aItems.end(),
547 [&](
const std::pair<BOARD_ITEM*, BOX2I>& a,
const std::pair<BOARD_ITEM*, BOX2I>& b )
549 return aIsXAxis ? a.second.GetLeft() < b.second.GetLeft()
550 : a.second.GetTop() < b.second.GetTop();
554 std::vector<std::pair<int, int>> itemSpans;
555 itemSpans.reserve( aItems.size() );
557 for(
const auto& [item, box] : aItems )
559 const int start = aIsXAxis ? box.GetLeft() : box.GetTop();
560 const int end = aIsXAxis ? box.GetRight() : box.GetBottom();
561 itemSpans.emplace_back( start,
end );
568 for(
size_t i = 1; i < aItems.size() - 1; ++i )
570 const auto& [item, box] = aItems[i];
571 const int delta = deltas[i];
578 item->Move( deltaVec );
585 std::vector<std::pair<BOARD_ITEM*, BOX2I>>& aItems,
589 aItems.begin(), aItems.end(),
590 [&](
const std::pair<BOARD_ITEM*, BOX2I>& lhs,
const std::pair<BOARD_ITEM*, BOX2I>& rhs )
592 const int lhsPos = aIsXAxis ? lhs.second.Centre().x : lhs.second.Centre().y;
593 const int rhsPos = aIsXAxis ? rhs.second.Centre().x : rhs.second.Centre().y;
594 return lhsPos < rhsPos;
597 std::vector<int> itemCenters;
598 itemCenters.reserve( aItems.size() );
600 for(
const auto& [item, box] : aItems )
602 itemCenters.push_back( aIsXAxis ? box.Centre().x : box.Centre().y );
608 for(
size_t i = 1; i < aItems.size() - 1; ++i )
610 const auto& [item, box] = aItems[i];
611 const int delta = deltas[i];
618 item->Move( deltaVec );
virtual void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Execute the changes.
COMMIT & Stage(EDA_ITEM *aItem, CHANGE_TYPE aChangeType, BASE_SCREEN *aScreen=nullptr, RECURSE_MODE aRecurse=RECURSE_MODE::NO_RECURSE) override
Add a change of the item aItem of type aChangeType to the change list.
Abstract interface for BOARD_ITEMs capable of storing other items inside.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
bool IsLocked() const override
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
FOOTPRINT * GetParentFootprint() 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).
A base class for most all the KiCad significant classes used in schematics and boards.
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
KICAD_T Type() const
Returns the type of object.
Used when the right click button is pressed, or when the select tool is in effect.
VECTOR2D GetCursorPosition() const
Return the current cursor position in world coordinates.
static TOOL_ACTION alignTop
static TOOL_ACTION distributeHorizontallyGaps
static TOOL_ACTION distributeHorizontallyCenters
static TOOL_ACTION alignRight
static TOOL_ACTION alignBottom
static TOOL_ACTION alignLeft
static TOOL_ACTION alignCenterX
static TOOL_ACTION distributeVerticallyGaps
static TOOL_ACTION distributeVerticallyCenters
static TOOL_ACTION alignCenterY
static SELECTION_CONDITION MoreThan(int aNumber)
Create a functor that tests if the number of selected items is greater than the value given as parame...
int Size() const
Returns the number of selected parts.
std::vector< int > GetDeltasForDistributeByGaps(const std::vector< std::pair< int, int > > &aItemExtents)
Given a list of 'n' item spans (e.g.
std::vector< int > GetDeltasForDistributeByPoints(const std::vector< int > &aItemPositions)
Class that computes missing connections on a PCB.
@ PCB_MARKER_T
class PCB_MARKER, a marker used to show something
@ PCB_TABLECELL_T
class PCB_TABLECELL, PCB_TEXTBOX for use in tables
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
@ PCB_PAD_T
class PAD, a pad in a footprint
VECTOR2< int32_t > VECTOR2I