43 m_selectionTool( nullptr ),
44 m_placementMenu( nullptr ),
59 m_frame = getEditFrame<PCB_BASE_FRAME>();
95 return static_cast<FOOTPRINT*
>( aItem )->GetBoundingBox(
false );
101template<
typename T >
103 std::vector<std::pair<BOARD_ITEM*, BOX2I>>& aLocked,
111 if( aLocked.size() >= 1 )
113 for(
const std::pair<BOARD_ITEM*, BOX2I>& item : aLocked )
115 if( item.second.Contains( curPos ) )
116 return aGetValue( item );
119 return aGetValue( aLocked.front() );
122 for(
const std::pair<BOARD_ITEM*, BOX2I>& item : aItems )
124 if( item.second.Contains( curPos ) )
125 return aGetValue( item );
128 return aGetValue( aItems.front() );
132template<
typename T >
134 std::vector<std::pair<BOARD_ITEM*, BOX2I>>& aLockedItems,
141 for(
int i = aCollector.
GetCount() - 1; i >= 0; --i )
143 BOARD_ITEM* item = aCollector[i];
145 if( item->Type() == PCB_MARKER_T )
146 aCollector.Remove( item );
152 bool differentParents =
false;
156 if( !item->IsBOARD_ITEM() )
169 currentParent = parent;
170 else if( parent != currentParent )
171 differentParents =
true;
175 []( std::vector<std::pair<BOARD_ITEM*, BOX2I>>& list,
BOARD_ITEM* item,
FOOTPRINT* parentFp )
177 BOARD_ITEM* listItem = parentFp ? parentFp : item;
179 for(
const auto& [candidate, bbox] : list )
181 if( candidate == listItem )
185 list.emplace_back( std::make_pair( listItem,
getBoundingBox( item ) ) );
190 if( !item->IsBOARD_ITEM() )
195 if( allPads && differentParents )
199 if( parentFp && parentFp->
IsLocked() )
200 addToList( aLockedItems, boardItem, parentFp );
202 addToList( aItemsToAlign, boardItem, parentFp );
208 addToList( aLockedItems, boardItem,
nullptr );
210 addToList( aItemsToAlign, boardItem,
nullptr );
213 std::sort( aItemsToAlign.begin(), aItemsToAlign.end(), aCompare );
214 std::sort( aLockedItems.begin(), aLockedItems.end(), aCompare );
216 return aItemsToAlign.size();
222 std::vector<std::pair<BOARD_ITEM*, BOX2I>> itemsToAlign;
223 std::vector<std::pair<BOARD_ITEM*, BOX2I>> locked_items;
226 [](
const std::pair<BOARD_ITEM*, BOX2I>& lhs,
const std::pair<BOARD_ITEM*, BOX2I>& rhs )
228 return ( lhs.second.GetTop() < rhs.second.GetTop() );
236 int targetTop =
selectTarget( itemsToAlign, locked_items,
237 [](
const std::pair<BOARD_ITEM*, BOX2I>& aVal )
239 return aVal.second.GetTop();
243 for(
const auto& [item, bbox] : itemsToAlign )
245 if( item->GetParent() && item->GetParent()->IsSelected() )
248 int difference = targetTop - bbox.GetTop();
251 item->Move(
VECTOR2I( 0, difference ) );
254 commit.
Push(
_(
"Align to Top" ) );
261 std::vector<std::pair<BOARD_ITEM*, BOX2I>> itemsToAlign;
262 std::vector<std::pair<BOARD_ITEM*, BOX2I>> locked_items;
265 [](
const std::pair<BOARD_ITEM*, BOX2I>& lhs,
const std::pair<BOARD_ITEM*, BOX2I>& rhs)
267 return ( lhs.second.GetBottom() > rhs.second.GetBottom() );
275 int targetBottom =
selectTarget( itemsToAlign, locked_items,
276 [](
const std::pair<BOARD_ITEM*, BOX2I>& aVal )
278 return aVal.second.GetBottom();
282 for(
const auto& [item, bbox] : itemsToAlign )
284 if( item->GetParent() && item->GetParent()->IsSelected() )
287 int difference = targetBottom - bbox.GetBottom();
290 item->Move(
VECTOR2I( 0, difference ) );
293 commit.
Push(
_(
"Align to Bottom" ) );
311 std::vector<std::pair<BOARD_ITEM*, BOX2I>> itemsToAlign;
312 std::vector<std::pair<BOARD_ITEM*, BOX2I>> locked_items;
315 [](
const std::pair<BOARD_ITEM*, BOX2I>& lhs,
const std::pair<BOARD_ITEM*, BOX2I>& rhs )
317 return ( lhs.second.GetLeft() < rhs.second.GetLeft() );
325 int targetLeft =
selectTarget( itemsToAlign, locked_items,
326 [](
const std::pair<BOARD_ITEM*, BOX2I>& aVal )
328 return aVal.second.GetLeft();
332 for(
const auto& [item, bbox] : itemsToAlign )
334 if( item->GetParent() && item->GetParent()->IsSelected() )
337 int difference = targetLeft - bbox.GetLeft();
340 item->Move(
VECTOR2I( difference, 0 ) );
343 commit.
Push(
_(
"Align to Left" ) );
361 std::vector<std::pair<BOARD_ITEM*, BOX2I>> itemsToAlign;
362 std::vector<std::pair<BOARD_ITEM*, BOX2I>> locked_items;
365 [](
const std::pair<BOARD_ITEM*, BOX2I>& lhs,
const std::pair<BOARD_ITEM*, BOX2I>& rhs )
367 return ( lhs.second.GetRight() > rhs.second.GetRight() );
375 int targetRight =
selectTarget( itemsToAlign, locked_items,
376 [](
const std::pair<BOARD_ITEM*, BOX2I>& aVal )
378 return aVal.second.GetRight();
382 for(
const auto& [item, bbox] : itemsToAlign )
384 if( item->GetParent() && item->GetParent()->IsSelected() )
387 int difference = targetRight - bbox.GetRight();
390 item->Move(
VECTOR2I( difference, 0 ) );
393 commit.
Push(
_(
"Align to Right" ) );
400 std::vector<std::pair<BOARD_ITEM*, BOX2I>> itemsToAlign;
401 std::vector<std::pair<BOARD_ITEM*, BOX2I>> locked_items;
404 [](
const std::pair<BOARD_ITEM*, BOX2I>& lhs,
const std::pair<BOARD_ITEM*, BOX2I>& rhs )
406 return ( lhs.second.Centre().x < rhs.second.Centre().x );
415 [](
const std::pair<BOARD_ITEM*, BOX2I>& aVal )
417 return aVal.second.Centre().x;
421 for(
const auto& [item, bbox] : itemsToAlign )
423 if( item->GetParent() && item->GetParent()->IsSelected() )
426 int difference = targetX - bbox.Centre().x;
429 item->Move(
VECTOR2I( difference, 0 ) );
432 commit.
Push(
_(
"Align to Middle" ) );
439 std::vector<std::pair<BOARD_ITEM*, BOX2I>> itemsToAlign;
440 std::vector<std::pair<BOARD_ITEM*, BOX2I>> locked_items;
443 [](
const std::pair<BOARD_ITEM*, BOX2I>& lhs,
const std::pair<BOARD_ITEM*, BOX2I>& rhs )
445 return ( lhs.second.Centre().y < rhs.second.Centre().y );
454 [](
const std::pair<BOARD_ITEM*, BOX2I>& aVal )
456 return aVal.second.Centre().y;
460 for(
const auto& [item, bbox] : itemsToAlign )
462 if( item->GetParent() && item->GetParent()->IsSelected() )
465 int difference = targetY - bbox.Centre().y;
468 item->Move(
VECTOR2I( 0, difference ) );
471 commit.
Push(
_(
"Align to Center" ) );
493 if( selection.
Size() < 3 )
498 std::vector<std::pair<BOARD_ITEM*, BOX2I>> itemsToDistribute;
502 if( !item->IsBOARD_ITEM() )
506 itemsToDistribute.emplace_back( std::make_pair( boardItem,
getBoundingBox( boardItem ) ) );
530 commit.
Push( commitMsg );
536 std::vector<std::pair<BOARD_ITEM*, BOX2I>>& aItems,
544 std::sort( aItems.begin(), aItems.end(),
545 [&](
const std::pair<BOARD_ITEM*, BOX2I>& a,
const std::pair<BOARD_ITEM*, BOX2I>& b )
547 return aIsXAxis ? a.second.GetLeft() < b.second.GetLeft()
548 : a.second.GetTop() < b.second.GetTop();
552 std::vector<std::pair<int, int>> itemSpans;
553 itemSpans.reserve( aItems.size() );
555 for(
const auto& [item, box] : aItems )
557 const int start = aIsXAxis ? box.GetLeft() : box.GetTop();
558 const int end = aIsXAxis ? box.GetRight() : box.GetBottom();
559 itemSpans.emplace_back( start,
end );
566 for(
size_t i = 1; i < aItems.size() - 1; ++i )
568 const auto& [item, box] = aItems[i];
569 const int delta = deltas[i];
576 item->Move( deltaVec );
583 std::vector<std::pair<BOARD_ITEM*, BOX2I>>& aItems,
587 aItems.begin(), aItems.end(),
588 [&](
const std::pair<BOARD_ITEM*, BOX2I>& lhs,
const std::pair<BOARD_ITEM*, BOX2I>& rhs )
590 const int lhsPos = aIsXAxis ? lhs.second.Centre().x : lhs.second.Centre().y;
591 const int rhsPos = aIsXAxis ? rhs.second.Centre().x : rhs.second.Centre().y;
592 return lhsPos < rhsPos;
595 std::vector<int> itemCenters;
596 itemCenters.reserve( aItems.size() );
598 for(
const auto& [item, box] : aItems )
600 itemCenters.push_back( aIsXAxis ? box.Centre().x : box.Centre().y );
606 for(
size_t i = 1; i < aItems.size() - 1; ++i )
608 const auto& [item, box] = aItems[i];
609 const int delta = deltas[i];
616 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.
bool IsType(FRAME_T aType) const
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_FOOTPRINT_T
class FOOTPRINT, a footprint
@ PCB_PAD_T
class PAD, a pad in a footprint
VECTOR2< int32_t > VECTOR2I