KiCad PCB EDA Suite
Loading...
Searching...
No Matches
align_distribute_tool.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2014-2016 CERN
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 * @author Maciej Suminski <[email protected]>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25#include "tool/selection.h"
27#include "pcb_actions.h"
28#include "pcb_selection_tool.h"
29
31#include <tool/tool_manager.h>
32
33#include <board.h>
34#include <board_commit.h>
35#include <bitmaps.h>
36#include <pcb_edit_frame.h>
37#include <geometry/distribute.h>
38#include <view/view_controls.h>
39
40
42 TOOL_INTERACTIVE( "pcbnew.Placement" ),
43 m_selectionTool( nullptr ),
44 m_placementMenu( nullptr ),
45 m_frame( nullptr )
46{
47}
48
50{
51 delete m_placementMenu;
52}
53
54
56{
57 // Find the selection tool, so they can cooperate
59 m_frame = getEditFrame<PCB_BASE_FRAME>();
60
61 // Create a context menu and make it available through selection tool
63 m_placementMenu->SetIcon( BITMAPS::align_items );
64 m_placementMenu->SetTitle( _( "Align/Distribute" ) );
65
66 const auto canAlign = SELECTION_CONDITIONS::MoreThan( 1 );
67 const auto canDistribute = SELECTION_CONDITIONS::MoreThan( 2 );
68
69 // Add all align/distribute commands
73
74 m_placementMenu->AddSeparator( canAlign );
78
79 m_placementMenu->AddSeparator( canDistribute );
84
87
88 return true;
89}
90
91
93{
94 if( aItem->Type() == PCB_FOOTPRINT_T )
95 return static_cast<FOOTPRINT*>( aItem )->GetBoundingBox( false );
96 else
97 return aItem->GetBoundingBox();
98}
99
100
101template< typename T >
102int ALIGN_DISTRIBUTE_TOOL::selectTarget( std::vector<std::pair<BOARD_ITEM*, BOX2I>>& aItems,
103 std::vector<std::pair<BOARD_ITEM*, BOX2I>>& aLocked,
104 T aGetValue )
105{
107
108 // Prefer locked items to unlocked items.
109 // Secondly, prefer items under the cursor to other items.
110
111 if( aLocked.size() >= 1 )
112 {
113 for( const std::pair<BOARD_ITEM*, BOX2I>& item : aLocked )
114 {
115 if( item.second.Contains( curPos ) )
116 return aGetValue( item );
117 }
118
119 return aGetValue( aLocked.front() );
120 }
121
122 for( const std::pair<BOARD_ITEM*, BOX2I>& item : aItems )
123 {
124 if( item.second.Contains( curPos ) )
125 return aGetValue( item );
126 }
127
128 return aGetValue( aItems.front() );
129}
130
131
132template< typename T >
133size_t ALIGN_DISTRIBUTE_TOOL::GetSelections( std::vector<std::pair<BOARD_ITEM*, BOX2I>>& aItemsToAlign,
134 std::vector<std::pair<BOARD_ITEM*, BOX2I>>& aLockedItems,
135 T aCompare )
136{
138 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
139 {
140 // Iterate from the back so we don't have to worry about removals.
141 for( int i = aCollector.GetCount() - 1; i >= 0; --i )
142 {
143 BOARD_ITEM* item = aCollector[i];
144
145 if( item->Type() == PCB_MARKER_T )
146 aCollector.Remove( item );
147 }
148 } );
149
150 bool allPads = true;
151 BOARD_ITEM_CONTAINER* currentParent = nullptr;
152 bool differentParents = false;
153
154 for( EDA_ITEM* item : selection )
155 {
156 if( !item->IsBOARD_ITEM() )
157 continue;
158
159 if( item->Type() != PCB_PAD_T )
160 allPads = false;
161
162 BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( item );
163 BOARD_ITEM_CONTAINER* parent = boardItem->GetParentFootprint();
164
165 if( !parent )
166 parent = boardItem->GetBoard();
167
168 if( !currentParent )
169 currentParent = parent;
170 else if( parent != currentParent )
171 differentParents = true;
172 }
173
174 auto addToList =
175 []( std::vector<std::pair<BOARD_ITEM*, BOX2I>>& list, BOARD_ITEM* item, FOOTPRINT* parentFp )
176 {
177 BOARD_ITEM* listItem = parentFp ? parentFp : item;
178
179 for( const auto& [candidate, bbox] : list )
180 {
181 if( candidate == listItem )
182 return;
183 }
184
185 list.emplace_back( std::make_pair( listItem, getBoundingBox( item ) ) );
186 };
187
188 for( EDA_ITEM* item : selection )
189 {
190 if( !item->IsBOARD_ITEM() )
191 continue;
192
193 BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( item );
194
195 if( allPads && differentParents )
196 {
197 FOOTPRINT* parentFp = boardItem->GetParentFootprint();
198
199 if( parentFp && parentFp->IsLocked() )
200 addToList( aLockedItems, boardItem, parentFp );
201 else
202 addToList( aItemsToAlign, boardItem, parentFp );
203
204 continue;
205 }
206
207 if( boardItem->IsLocked() )
208 addToList( aLockedItems, boardItem, nullptr );
209 else
210 addToList( aItemsToAlign, boardItem, nullptr );
211 }
212
213 std::sort( aItemsToAlign.begin(), aItemsToAlign.end(), aCompare );
214 std::sort( aLockedItems.begin(), aLockedItems.end(), aCompare );
215
216 return aItemsToAlign.size();
217}
218
219
221{
222 std::vector<std::pair<BOARD_ITEM*, BOX2I>> itemsToAlign;
223 std::vector<std::pair<BOARD_ITEM*, BOX2I>> locked_items;
224
225 if( !GetSelections( itemsToAlign, locked_items,
226 []( const std::pair<BOARD_ITEM*, BOX2I>& lhs, const std::pair<BOARD_ITEM*, BOX2I>& rhs )
227 {
228 return ( lhs.second.GetTop() < rhs.second.GetTop() );
229 } ) )
230 {
231 return 0;
232 }
233
234 BOARD_COMMIT commit( m_frame );
235
236 int targetTop = selectTarget( itemsToAlign, locked_items,
237 []( const std::pair<BOARD_ITEM*, BOX2I>& aVal )
238 {
239 return aVal.second.GetTop();
240 } );
241
242 // Move the selected items
243 for( const auto& [item, bbox] : itemsToAlign )
244 {
245 if( item->GetParent() && item->GetParent()->IsSelected() )
246 continue;
247
248 int difference = targetTop - bbox.GetTop();
249
250 commit.Stage( item, CHT_MODIFY );
251 item->Move( VECTOR2I( 0, difference ) );
252 }
253
254 commit.Push( _( "Align to Top" ) );
255 return 0;
256}
257
258
260{
261 std::vector<std::pair<BOARD_ITEM*, BOX2I>> itemsToAlign;
262 std::vector<std::pair<BOARD_ITEM*, BOX2I>> locked_items;
263
264 if( !GetSelections( itemsToAlign, locked_items,
265 []( const std::pair<BOARD_ITEM*, BOX2I>& lhs, const std::pair<BOARD_ITEM*, BOX2I>& rhs)
266 {
267 return ( lhs.second.GetBottom() > rhs.second.GetBottom() );
268 } ) )
269 {
270 return 0;
271 }
272
273 BOARD_COMMIT commit( m_frame );
274
275 int targetBottom = selectTarget( itemsToAlign, locked_items,
276 []( const std::pair<BOARD_ITEM*, BOX2I>& aVal )
277 {
278 return aVal.second.GetBottom();
279 } );
280
281 // Move the selected items
282 for( const auto& [item, bbox] : itemsToAlign )
283 {
284 if( item->GetParent() && item->GetParent()->IsSelected() )
285 continue;
286
287 int difference = targetBottom - bbox.GetBottom();
288
289 commit.Stage( item, CHT_MODIFY );
290 item->Move( VECTOR2I( 0, difference ) );
291 }
292
293 commit.Push( _( "Align to Bottom" ) );
294 return 0;
295}
296
297
299{
300 // Because this tool uses bounding boxes and they aren't mirrored even when
301 // the view is mirrored, we need to call the other one if mirrored.
302 if( getView()->IsMirroredX() )
303 return doAlignRight();
304 else
305 return doAlignLeft();
306}
307
308
310{
311 std::vector<std::pair<BOARD_ITEM*, BOX2I>> itemsToAlign;
312 std::vector<std::pair<BOARD_ITEM*, BOX2I>> locked_items;
313
314 if( !GetSelections( itemsToAlign, locked_items,
315 []( const std::pair<BOARD_ITEM*, BOX2I>& lhs, const std::pair<BOARD_ITEM*, BOX2I>& rhs )
316 {
317 return ( lhs.second.GetLeft() < rhs.second.GetLeft() );
318 } ) )
319 {
320 return 0;
321 }
322
323 BOARD_COMMIT commit( m_frame );
324
325 int targetLeft = selectTarget( itemsToAlign, locked_items,
326 []( const std::pair<BOARD_ITEM*, BOX2I>& aVal )
327 {
328 return aVal.second.GetLeft();
329 } );
330
331 // Move the selected items
332 for( const auto& [item, bbox] : itemsToAlign )
333 {
334 if( item->GetParent() && item->GetParent()->IsSelected() )
335 continue;
336
337 int difference = targetLeft - bbox.GetLeft();
338
339 commit.Stage( item, CHT_MODIFY );
340 item->Move( VECTOR2I( difference, 0 ) );
341 }
342
343 commit.Push( _( "Align to Left" ) );
344 return 0;
345}
346
347
349{
350 // Because this tool uses bounding boxes and they aren't mirrored even when
351 // the view is mirrored, we need to call the other one if mirrored.
352 if( getView()->IsMirroredX() )
353 return doAlignLeft();
354 else
355 return doAlignRight();
356}
357
358
360{
361 std::vector<std::pair<BOARD_ITEM*, BOX2I>> itemsToAlign;
362 std::vector<std::pair<BOARD_ITEM*, BOX2I>> locked_items;
363
364 if( !GetSelections( itemsToAlign, locked_items,
365 []( const std::pair<BOARD_ITEM*, BOX2I>& lhs, const std::pair<BOARD_ITEM*, BOX2I>& rhs )
366 {
367 return ( lhs.second.GetRight() > rhs.second.GetRight() );
368 } ) )
369 {
370 return 0;
371 }
372
373 BOARD_COMMIT commit( m_frame );
374
375 int targetRight = selectTarget( itemsToAlign, locked_items,
376 []( const std::pair<BOARD_ITEM*, BOX2I>& aVal )
377 {
378 return aVal.second.GetRight();
379 } );
380
381 // Move the selected items
382 for( const auto& [item, bbox] : itemsToAlign )
383 {
384 if( item->GetParent() && item->GetParent()->IsSelected() )
385 continue;
386
387 int difference = targetRight - bbox.GetRight();
388
389 commit.Stage( item, CHT_MODIFY );
390 item->Move( VECTOR2I( difference, 0 ) );
391 }
392
393 commit.Push( _( "Align to Right" ) );
394 return 0;
395}
396
397
399{
400 std::vector<std::pair<BOARD_ITEM*, BOX2I>> itemsToAlign;
401 std::vector<std::pair<BOARD_ITEM*, BOX2I>> locked_items;
402
403 if( !GetSelections( itemsToAlign, locked_items,
404 []( const std::pair<BOARD_ITEM*, BOX2I>& lhs, const std::pair<BOARD_ITEM*, BOX2I>& rhs )
405 {
406 return ( lhs.second.Centre().x < rhs.second.Centre().x );
407 } ) )
408 {
409 return 0;
410 }
411
412 BOARD_COMMIT commit( m_frame );
413
414 int targetX = selectTarget( itemsToAlign, locked_items,
415 []( const std::pair<BOARD_ITEM*, BOX2I>& aVal )
416 {
417 return aVal.second.Centre().x;
418 } );
419
420 // Move the selected items
421 for( const auto& [item, bbox] : itemsToAlign )
422 {
423 if( item->GetParent() && item->GetParent()->IsSelected() )
424 continue;
425
426 int difference = targetX - bbox.Centre().x;
427
428 commit.Stage( item, CHT_MODIFY );
429 item->Move( VECTOR2I( difference, 0 ) );
430 }
431
432 commit.Push( _( "Align to Middle" ) );
433 return 0;
434}
435
436
438{
439 std::vector<std::pair<BOARD_ITEM*, BOX2I>> itemsToAlign;
440 std::vector<std::pair<BOARD_ITEM*, BOX2I>> locked_items;
441
442 if( !GetSelections( itemsToAlign, locked_items,
443 []( const std::pair<BOARD_ITEM*, BOX2I>& lhs, const std::pair<BOARD_ITEM*, BOX2I>& rhs )
444 {
445 return ( lhs.second.Centre().y < rhs.second.Centre().y );
446 } ) )
447 {
448 return 0;
449 }
450
451 BOARD_COMMIT commit( m_frame );
452
453 int targetY = selectTarget( itemsToAlign, locked_items,
454 []( const std::pair<BOARD_ITEM*, BOX2I>& aVal )
455 {
456 return aVal.second.Centre().y;
457 } );
458
459 // Move the selected items
460 for( const auto& [item, bbox] : itemsToAlign )
461 {
462 if( item->GetParent() && item->GetParent()->IsSelected() )
463 continue;
464
465 int difference = targetY - bbox.Centre().y;
466
467 commit.Stage( item, CHT_MODIFY );
468 item->Move( VECTOR2I( 0, difference ) );
469 }
470
471 commit.Push( _( "Align to Center" ) );
472 return 0;
473}
474
475
477{
479 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector,
480 PCB_SELECTION_TOOL* sTool )
481 {
482 sTool->FilterCollectorForMarkers( aCollector );
483 sTool->FilterCollectorForHierarchy( aCollector, true );
484
485 // Don't filter for free pads. We want to allow for distributing other
486 // items (such as a via) between two pads.
487 // sTool->FilterCollectorForFreePads( aCollector );
488 },
489 m_frame->IsType( FRAME_PCB_EDITOR ) /* prompt user regarding locked items */
490 );
491
492 // Need at least 3 items to distribute - one at each end and at least on in the middle
493 if( selection.Size() < 3 )
494 return 0;
495
496 BOARD_COMMIT commit( m_frame );
497 wxString commitMsg;
498 std::vector<std::pair<BOARD_ITEM*, BOX2I>> itemsToDistribute;
499
500 for( EDA_ITEM* item : selection )
501 {
502 if( !item->IsBOARD_ITEM() )
503 continue;
504
505 BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( item );
506 itemsToDistribute.emplace_back( std::make_pair( boardItem, getBoundingBox( boardItem ) ) );
507 }
508
510 {
511 doDistributeCenters( true, itemsToDistribute, commit );
513 }
515 {
516 doDistributeGaps( true, itemsToDistribute, commit );
518 }
520 {
521 doDistributeCenters( false, itemsToDistribute, commit );
523 }
524 else
525 {
526 doDistributeGaps( false, itemsToDistribute, commit );
528 }
529
530 commit.Push( commitMsg );
531 return 0;
532}
533
534
536 std::vector<std::pair<BOARD_ITEM*, BOX2I>>& aItems,
537 BOARD_COMMIT& aCommit ) const
538{
539 // Sort by start position.
540 // This is a simple way to get the items in a sensible order but it's not perfect.
541 // It will fail if, say, there's a huge items that's bigger than the total span of
542 // all the other items, but at that point a gap-equalising algorithm probably isn't
543 // well-defined anyway.
544 std::sort( aItems.begin(), aItems.end(),
545 [&]( const std::pair<BOARD_ITEM*, BOX2I>& a, const std::pair<BOARD_ITEM*, BOX2I>& b )
546 {
547 return aIsXAxis ? a.second.GetLeft() < b.second.GetLeft()
548 : a.second.GetTop() < b.second.GetTop();
549 } );
550
551 // Consruct list of item spans in the relevant axis
552 std::vector<std::pair<int, int>> itemSpans;
553 itemSpans.reserve( aItems.size() );
554
555 for( const auto& [item, box] : aItems )
556 {
557 const int start = aIsXAxis ? box.GetLeft() : box.GetTop();
558 const int end = aIsXAxis ? box.GetRight() : box.GetBottom();
559 itemSpans.emplace_back( start, end );
560 }
561
562 // Get the deltas needed to distribute the items evenly
563 const std::vector<int> deltas = GetDeltasForDistributeByGaps( itemSpans );
564
565 // Apply the deltas to the items
566 for( size_t i = 1; i < aItems.size() - 1; ++i )
567 {
568 const auto& [item, box] = aItems[i];
569 const int delta = deltas[i];
570
571 if( delta != 0 )
572 {
573 const VECTOR2I deltaVec = aIsXAxis ? VECTOR2I( delta, 0 ) : VECTOR2I( 0, delta );
574
575 aCommit.Stage( item, CHT_MODIFY );
576 item->Move( deltaVec );
577 }
578 }
579}
580
581
583 std::vector<std::pair<BOARD_ITEM*, BOX2I>>& aItems,
584 BOARD_COMMIT& aCommit ) const
585{
586 std::sort(
587 aItems.begin(), aItems.end(),
588 [&]( const std::pair<BOARD_ITEM*, BOX2I>& lhs, const std::pair<BOARD_ITEM*, BOX2I>& rhs )
589 {
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;
593 } );
594
595 std::vector<int> itemCenters;
596 itemCenters.reserve( aItems.size() );
597
598 for( const auto& [item, box] : aItems )
599 {
600 itemCenters.push_back( aIsXAxis ? box.Centre().x : box.Centre().y );
601 }
602
603 const std::vector<int> deltas = GetDeltasForDistributeByPoints( itemCenters );
604
605 // Apply the deltas to the items
606 for( size_t i = 1; i < aItems.size() - 1; ++i )
607 {
608 const auto& [item, box] = aItems[i];
609 const int delta = deltas[i];
610
611 if ( delta != 0)
612 {
613 const VECTOR2I deltaVec = aIsXAxis ? VECTOR2I( delta, 0 ) : VECTOR2I( 0, delta );
614
615 aCommit.Stage( item, CHT_MODIFY );
616 item->Move( deltaVec );
617 }
618 }
619}
620
621
623{
630
639}
BOX2I getBoundingBox(BOARD_ITEM *aItem)
void SetTitle(const wxString &aTitle) override
Set title for the menu.
Definition: action_menu.cpp:92
void SetIcon(BITMAPS aIcon)
Assign an icon for the entry.
Definition: action_menu.cpp:78
int AlignBottom(const TOOL_EVENT &aEvent)
Sets Y coordinate of the selected items to the value of the bottom-most selected item Y coordinate.
int DistributeItems(const TOOL_EVENT &aEvent)
Distribute the selected items in some way.
PCB_SELECTION_TOOL * m_selectionTool
size_t GetSelections(std::vector< std::pair< BOARD_ITEM *, BOX2I > > &aItemsToAlign, std::vector< std::pair< BOARD_ITEM *, BOX2I > > &aLockedItems, T aCompare)
Populate two vectors with the sorted selection and sorted locked items.
int AlignCenterX(const TOOL_EVENT &aEvent)
Set the x coordinate of the midpoint of each of the selected items to the value of the x coordinate o...
int AlignTop(const TOOL_EVENT &aEvent)
Set Y coordinate of the selected items to the value of the top-most selected item Y coordinate.
int doAlignLeft()
Sets X coordinate of the selected items to the value of the left-most selected item X coordinate.
CONDITIONAL_MENU * m_placementMenu
void doDistributeCenters(bool aIsXAxis, std::vector< std::pair< BOARD_ITEM *, BOX2I > > &aItems, BOARD_COMMIT &aCommit) const
Distribute selected items using an even spacing between the centers of their bounding boxes.
int selectTarget(std::vector< std::pair< BOARD_ITEM *, BOX2I > > &aItems, std::vector< std::pair< BOARD_ITEM *, BOX2I > > &aLocked, T aGetValue)
int AlignCenterY(const TOOL_EVENT &aEvent)
Set the y coordinate of the midpoint of each of the selected items to the value of the y coordinate o...
int AlignRight(const TOOL_EVENT &aEvent)
Sets X coordinate of the selected items to the value of the right-most selected item X coordinate.
void doDistributeGaps(bool aIsXAxis, std::vector< std::pair< BOARD_ITEM *, BOX2I > > &aItems, BOARD_COMMIT &aCommit) const
Distributes selected items using an even spacing between their bounding boxe in the x or y axis.
bool Init() override
Init() is called once upon a registration of the tool.
void setTransitions() override
This method is meant to be overridden in order to specify handlers for events.
int doAlignRight()
Align selected items using the right edge of their bounding boxes to the right-most item.
int AlignLeft(const TOOL_EVENT &aEvent)
Sets X coordinate of the selected items to the value of the left-most selected item X coordinate.
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...
Definition: board_item.h:79
bool IsLocked() const override
Definition: board_item.cpp:103
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
Definition: board_item.cpp:79
FOOTPRINT * GetParentFootprint() const
Definition: board_item.cpp:97
int GetCount() const
Return the number of objects in the list.
Definition: collector.h:83
void AddItem(const TOOL_ACTION &aAction, const SELECTION_CONDITION &aCondition, int aOrder=ANY_ORDER)
Add a menu entry to run a TOOL_ACTION on selected items.
void AddSeparator(int aOrder=ANY_ORDER)
Add a separator to the menu.
void AddMenu(ACTION_MENU *aMenu, const SELECTION_CONDITION &aCondition=SELECTION_CONDITIONS::ShowAlways, int aOrder=ANY_ORDER)
Add a submenu to the menu.
bool IsType(FRAME_T aType) const
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:98
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
Definition: eda_item.cpp:110
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:110
bool IsLocked() const override
Definition: footprint.h:420
Used when the right click button is pressed, or when the select tool is in effect.
Definition: collectors.h:207
VECTOR2D GetCursorPosition() const
Return the current cursor position in world coordinates.
static TOOL_ACTION alignTop
Definition: pcb_actions.h:294
static TOOL_ACTION distributeHorizontallyGaps
Definition: pcb_actions.h:301
static TOOL_ACTION distributeHorizontallyCenters
Definition: pcb_actions.h:300
static TOOL_ACTION alignRight
Definition: pcb_actions.h:297
static TOOL_ACTION alignBottom
Definition: pcb_actions.h:295
static TOOL_ACTION alignLeft
Definition: pcb_actions.h:296
static TOOL_ACTION alignCenterX
Definition: pcb_actions.h:298
static TOOL_ACTION distributeVerticallyGaps
Definition: pcb_actions.h:303
static TOOL_ACTION distributeVerticallyCenters
Definition: pcb_actions.h:302
static TOOL_ACTION alignCenterY
Definition: pcb_actions.h:299
The selection tool: currently supports:
void FilterCollectorForMarkers(GENERAL_COLLECTOR &aCollector) const
Drop any PCB_MARKERs from the collector.
PCB_SELECTION & RequestSelection(CLIENT_SELECTION_FILTER aClientFilter, bool aConfirmLockedItems=false)
Return the current selection, filtered according to aClientFilter.
void FilterCollectorForHierarchy(GENERAL_COLLECTOR &aCollector, bool aMultiselect) const
In general we don't want to select both a parent and any of it's children.
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.
Definition: selection.h:121
TOOL_EVENT MakeEvent() const
Return the event associated with the action (i.e.
wxString GetFriendlyName() const
Return the translated user-friendly name of the action.
KIGFX::VIEW_CONTROLS * getViewControls() const
Return the instance of VIEW_CONTROLS object used in the application.
Definition: tool_base.cpp:44
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:220
KIGFX::VIEW * getView() const
Returns the instance of #VIEW object used in the application.
Definition: tool_base.cpp:38
Generic, UI-independent tool event.
Definition: tool_event.h:168
bool Matches(const TOOL_EVENT &aEvent) const
Test whether two events match in terms of category & action or command.
Definition: tool_event.h:389
void Go(int(T::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
Define which state (aStateFunc) to go when a certain event arrives (aConditions).
TOOL_MENU & GetToolMenu()
CONDITIONAL_MENU & GetMenu()
Definition: tool_menu.cpp:44
@ CHT_MODIFY
Definition: commit.h:45
std::vector< int > GetDeltasForDistributeByGaps(const std::vector< std::pair< int, int > > &aItemExtents)
Given a list of 'n' item spans (e.g.
Definition: distribute.cpp:25
std::vector< int > GetDeltasForDistributeByPoints(const std::vector< int > &aItemPositions)
Definition: distribute.cpp:67
#define _(s)
@ FRAME_PCB_EDITOR
Definition: frame_type.h:42
Class that computes missing connections on a PCB.
VECTOR2I end
int delta
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
Definition: typeinfo.h:86
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition: typeinfo.h:87
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:695