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 <collectors.h>
36#include <bitmaps.h>
37#include <pcb_edit_frame.h>
38#include <geometry/distribute.h>
39#include <view/view_controls.h>
40
41
43 TOOL_INTERACTIVE( "pcbnew.Placement" ),
44 m_selectionTool( nullptr ),
45 m_placementMenu( nullptr ),
46 m_frame( nullptr )
47{
48}
49
54
55
57{
58 // Find the selection tool, so they can cooperate
61
62 // Create a context menu and make it available through selection tool
65 m_placementMenu->SetUntranslatedTitle( _HKI( "Align/Distribute" ) );
66
67 const auto canAlign = SELECTION_CONDITIONS::MoreThan( 1 );
68 const auto canDistribute = SELECTION_CONDITIONS::MoreThan( 2 );
69
70 // Add all align/distribute commands
71 m_placementMenu->AddItem( PCB_ACTIONS::alignLeft, canAlign );
72 m_placementMenu->AddItem( PCB_ACTIONS::alignCenterX, canAlign );
73 m_placementMenu->AddItem( PCB_ACTIONS::alignRight, canAlign );
74
75 m_placementMenu->AddSeparator( canAlign );
76 m_placementMenu->AddItem( PCB_ACTIONS::alignTop, canAlign );
77 m_placementMenu->AddItem( PCB_ACTIONS::alignCenterY, canAlign );
78 m_placementMenu->AddItem( PCB_ACTIONS::alignBottom, canAlign );
79
80 m_placementMenu->AddSeparator( canDistribute );
85
86 CONDITIONAL_MENU& selToolMenu = m_selectionTool->GetToolMenu().GetMenu();
88
89 return true;
90}
91
92
94{
95 if( aItem->Type() == PCB_FOOTPRINT_T )
96 return static_cast<FOOTPRINT*>( aItem )->GetBoundingBox( false );
97 else
98 return aItem->GetBoundingBox();
99}
100
101
102template< typename T >
103int ALIGN_DISTRIBUTE_TOOL::selectTarget( std::vector<std::pair<BOARD_ITEM*, BOX2I>>& aItems,
104 std::vector<std::pair<BOARD_ITEM*, BOX2I>>& aLocked,
105 T aGetValue )
106{
108
109 // Prefer locked items to unlocked items.
110 // Secondly, prefer items under the cursor to other items.
111
112 if( aLocked.size() >= 1 )
113 {
114 for( const std::pair<BOARD_ITEM*, BOX2I>& item : aLocked )
115 {
116 if( item.second.Contains( curPos ) )
117 return aGetValue( item );
118 }
119
120 return aGetValue( aLocked.front() );
121 }
122
123 for( const std::pair<BOARD_ITEM*, BOX2I>& item : aItems )
124 {
125 if( item.second.Contains( curPos ) )
126 return aGetValue( item );
127 }
128
129 return aGetValue( aItems.front() );
130}
131
132
133template< typename T >
134size_t ALIGN_DISTRIBUTE_TOOL::GetSelections( std::vector<std::pair<BOARD_ITEM*, BOX2I>>& aItemsToAlign,
135 std::vector<std::pair<BOARD_ITEM*, BOX2I>>& aLockedItems,
136 T aCompare )
137{
138 PCB_SELECTION& selection = m_selectionTool->RequestSelection(
139 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
140 {
141 // Iterate from the back so we don't have to worry about removals.
142 for( int i = aCollector.GetCount() - 1; i >= 0; --i )
143 {
144 BOARD_ITEM* item = aCollector[i];
145
146 if( item->Type() == PCB_MARKER_T )
147 aCollector.Remove( item );
148 }
149 } );
150
151 bool allPads = true;
152 BOARD_ITEM_CONTAINER* currentParent = nullptr;
153 bool differentParents = false;
154 bool allowFreePads = m_selectionTool->IsFootprintEditor()
155 || m_frame->GetPcbNewSettings()->m_AllowFreePads;
156
157 for( EDA_ITEM* item : selection )
158 {
159 if( !item->IsBOARD_ITEM() )
160 continue;
161
162 if( item->Type() != PCB_PAD_T )
163 allPads = false;
164
165 BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( item );
166 BOARD_ITEM_CONTAINER* parent = boardItem->GetParentFootprint();
167
168 if( !parent )
169 parent = boardItem->GetBoard();
170
171 if( !currentParent )
172 currentParent = parent;
173 else if( parent != currentParent )
174 differentParents = true;
175 }
176
177 auto addToList =
178 []( std::vector<std::pair<BOARD_ITEM*, BOX2I>>& list, BOARD_ITEM* item, FOOTPRINT* parentFp )
179 {
180 BOARD_ITEM* listItem = parentFp ? parentFp : item;
181
182 for( const auto& [candidate, bbox] : list )
183 {
184 if( candidate == listItem )
185 return;
186 }
187
188 list.emplace_back( std::make_pair( listItem, getBoundingBox( item ) ) );
189 };
190
191 for( EDA_ITEM* item : selection )
192 {
193 if( !item->IsBOARD_ITEM() || item->Type() == PCB_TABLECELL_T )
194 continue;
195
196 BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( item );
197
198 if( boardItem->Type() == PCB_PAD_T && ( !allowFreePads || ( allPads && differentParents ) ) )
199 {
200 FOOTPRINT* parentFp = boardItem->GetParentFootprint();
201
202 if( parentFp && parentFp->IsLocked() )
203 addToList( aLockedItems, boardItem, parentFp );
204 else
205 addToList( aItemsToAlign, boardItem, parentFp );
206
207 continue;
208 }
209
210 if( boardItem->IsLocked() )
211 addToList( aLockedItems, boardItem, nullptr );
212 else
213 addToList( aItemsToAlign, boardItem, nullptr );
214 }
215
216 std::sort( aItemsToAlign.begin(), aItemsToAlign.end(), aCompare );
217 std::sort( aLockedItems.begin(), aLockedItems.end(), aCompare );
218
219 return aItemsToAlign.size();
220}
221
222
224{
225 std::vector<std::pair<BOARD_ITEM*, BOX2I>> itemsToAlign;
226 std::vector<std::pair<BOARD_ITEM*, BOX2I>> locked_items;
227
228 if( !GetSelections( itemsToAlign, locked_items,
229 []( const std::pair<BOARD_ITEM*, BOX2I>& lhs, const std::pair<BOARD_ITEM*, BOX2I>& rhs )
230 {
231 return ( lhs.second.GetTop() < rhs.second.GetTop() );
232 } ) )
233 {
234 return 0;
235 }
236
237 BOARD_COMMIT commit( m_frame );
238
239 int targetTop = selectTarget( itemsToAlign, locked_items,
240 []( const std::pair<BOARD_ITEM*, BOX2I>& aVal )
241 {
242 return aVal.second.GetTop();
243 } );
244
245 // Move the selected items
246 for( const auto& [item, bbox] : itemsToAlign )
247 {
248 if( item->GetParent() && item->GetParent()->IsSelected() )
249 continue;
250
251 int difference = targetTop - bbox.GetTop();
252
253 commit.Stage( item, CHT_MODIFY );
254 item->Move( VECTOR2I( 0, difference ) );
255 }
256
257 commit.Push( _( "Align to Top" ) );
258 return 0;
259}
260
261
263{
264 std::vector<std::pair<BOARD_ITEM*, BOX2I>> itemsToAlign;
265 std::vector<std::pair<BOARD_ITEM*, BOX2I>> locked_items;
266
267 if( !GetSelections( itemsToAlign, locked_items,
268 []( const std::pair<BOARD_ITEM*, BOX2I>& lhs, const std::pair<BOARD_ITEM*, BOX2I>& rhs)
269 {
270 return ( lhs.second.GetBottom() > rhs.second.GetBottom() );
271 } ) )
272 {
273 return 0;
274 }
275
276 BOARD_COMMIT commit( m_frame );
277
278 int targetBottom = selectTarget( itemsToAlign, locked_items,
279 []( const std::pair<BOARD_ITEM*, BOX2I>& aVal )
280 {
281 return aVal.second.GetBottom();
282 } );
283
284 // Move the selected items
285 for( const auto& [item, bbox] : itemsToAlign )
286 {
287 if( item->GetParent() && item->GetParent()->IsSelected() )
288 continue;
289
290 int difference = targetBottom - bbox.GetBottom();
291
292 commit.Stage( item, CHT_MODIFY );
293 item->Move( VECTOR2I( 0, difference ) );
294 }
295
296 commit.Push( _( "Align to Bottom" ) );
297 return 0;
298}
299
300
302{
303 // Because this tool uses bounding boxes and they aren't mirrored even when
304 // the view is mirrored, we need to call the other one if mirrored.
305 if( getView()->IsMirroredX() )
306 return doAlignRight();
307 else
308 return doAlignLeft();
309}
310
311
313{
314 std::vector<std::pair<BOARD_ITEM*, BOX2I>> itemsToAlign;
315 std::vector<std::pair<BOARD_ITEM*, BOX2I>> locked_items;
316
317 if( !GetSelections( itemsToAlign, locked_items,
318 []( const std::pair<BOARD_ITEM*, BOX2I>& lhs, const std::pair<BOARD_ITEM*, BOX2I>& rhs )
319 {
320 return ( lhs.second.GetLeft() < rhs.second.GetLeft() );
321 } ) )
322 {
323 return 0;
324 }
325
326 BOARD_COMMIT commit( m_frame );
327
328 int targetLeft = selectTarget( itemsToAlign, locked_items,
329 []( const std::pair<BOARD_ITEM*, BOX2I>& aVal )
330 {
331 return aVal.second.GetLeft();
332 } );
333
334 // Move the selected items
335 for( const auto& [item, bbox] : itemsToAlign )
336 {
337 if( item->GetParent() && item->GetParent()->IsSelected() )
338 continue;
339
340 int difference = targetLeft - bbox.GetLeft();
341
342 commit.Stage( item, CHT_MODIFY );
343 item->Move( VECTOR2I( difference, 0 ) );
344 }
345
346 commit.Push( _( "Align to Left" ) );
347 return 0;
348}
349
350
352{
353 // Because this tool uses bounding boxes and they aren't mirrored even when
354 // the view is mirrored, we need to call the other one if mirrored.
355 if( getView()->IsMirroredX() )
356 return doAlignLeft();
357 else
358 return doAlignRight();
359}
360
361
363{
364 std::vector<std::pair<BOARD_ITEM*, BOX2I>> itemsToAlign;
365 std::vector<std::pair<BOARD_ITEM*, BOX2I>> locked_items;
366
367 if( !GetSelections( itemsToAlign, locked_items,
368 []( const std::pair<BOARD_ITEM*, BOX2I>& lhs, const std::pair<BOARD_ITEM*, BOX2I>& rhs )
369 {
370 return ( lhs.second.GetRight() > rhs.second.GetRight() );
371 } ) )
372 {
373 return 0;
374 }
375
376 BOARD_COMMIT commit( m_frame );
377
378 int targetRight = selectTarget( itemsToAlign, locked_items,
379 []( const std::pair<BOARD_ITEM*, BOX2I>& aVal )
380 {
381 return aVal.second.GetRight();
382 } );
383
384 // Move the selected items
385 for( const auto& [item, bbox] : itemsToAlign )
386 {
387 if( item->GetParent() && item->GetParent()->IsSelected() )
388 continue;
389
390 int difference = targetRight - bbox.GetRight();
391
392 commit.Stage( item, CHT_MODIFY );
393 item->Move( VECTOR2I( difference, 0 ) );
394 }
395
396 commit.Push( _( "Align to Right" ) );
397 return 0;
398}
399
400
402{
403 std::vector<std::pair<BOARD_ITEM*, BOX2I>> itemsToAlign;
404 std::vector<std::pair<BOARD_ITEM*, BOX2I>> locked_items;
405
406 if( !GetSelections( itemsToAlign, locked_items,
407 []( const std::pair<BOARD_ITEM*, BOX2I>& lhs, const std::pair<BOARD_ITEM*, BOX2I>& rhs )
408 {
409 return ( lhs.second.Centre().x < rhs.second.Centre().x );
410 } ) )
411 {
412 return 0;
413 }
414
415 BOARD_COMMIT commit( m_frame );
416
417 int targetX = selectTarget( itemsToAlign, locked_items,
418 []( const std::pair<BOARD_ITEM*, BOX2I>& aVal )
419 {
420 return aVal.second.Centre().x;
421 } );
422
423 // Move the selected items
424 for( const auto& [item, bbox] : itemsToAlign )
425 {
426 if( item->GetParent() && item->GetParent()->IsSelected() )
427 continue;
428
429 int difference = targetX - bbox.Centre().x;
430
431 commit.Stage( item, CHT_MODIFY );
432 item->Move( VECTOR2I( difference, 0 ) );
433 }
434
435 commit.Push( _( "Align to Middle" ) );
436 return 0;
437}
438
439
441{
442 std::vector<std::pair<BOARD_ITEM*, BOX2I>> itemsToAlign;
443 std::vector<std::pair<BOARD_ITEM*, BOX2I>> locked_items;
444
445 if( !GetSelections( itemsToAlign, locked_items,
446 []( const std::pair<BOARD_ITEM*, BOX2I>& lhs, const std::pair<BOARD_ITEM*, BOX2I>& rhs )
447 {
448 return ( lhs.second.Centre().y < rhs.second.Centre().y );
449 } ) )
450 {
451 return 0;
452 }
453
454 BOARD_COMMIT commit( m_frame );
455
456 int targetY = selectTarget( itemsToAlign, locked_items,
457 []( const std::pair<BOARD_ITEM*, BOX2I>& aVal )
458 {
459 return aVal.second.Centre().y;
460 } );
461
462 // Move the selected items
463 for( const auto& [item, bbox] : itemsToAlign )
464 {
465 if( item->GetParent() && item->GetParent()->IsSelected() )
466 continue;
467
468 int difference = targetY - bbox.Centre().y;
469
470 commit.Stage( item, CHT_MODIFY );
471 item->Move( VECTOR2I( 0, difference ) );
472 }
473
474 commit.Push( _( "Align to Center" ) );
475 return 0;
476}
477
478
480{
481 PCB_SELECTION& selection = m_selectionTool->RequestSelection(
482 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
483 {
484 sTool->FilterCollectorForMarkers( aCollector );
485 sTool->FilterCollectorForHierarchy( aCollector, true );
486
487 // Don't filter for free pads. We want to allow for distributing other
488 // items (such as a via) between two pads.
489 // sTool->FilterCollectorForFreePads( aCollector );
490
491 sTool->FilterCollectorForLockedItems( aCollector );
492 } );
493
494 // Need at least 3 items to distribute - one at each end and at least on in the middle
495 if( selection.Size() < 3 )
496 return 0;
497
498 BOARD_COMMIT commit( m_frame );
499 wxString commitMsg;
500 std::vector<std::pair<BOARD_ITEM*, BOX2I>> itemsToDistribute;
501
502 for( EDA_ITEM* item : selection )
503 {
504 if( !item->IsBOARD_ITEM() )
505 continue;
506
507 BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( item );
508 itemsToDistribute.emplace_back( std::make_pair( boardItem, getBoundingBox( boardItem ) ) );
509 }
510
511 if( aEvent.Matches( PCB_ACTIONS::distributeHorizontallyCenters.MakeEvent() ) )
512 {
513 doDistributeCenters( true, itemsToDistribute, commit );
514 commitMsg = PCB_ACTIONS::distributeHorizontallyCenters.GetFriendlyName();
515 }
516 else if( aEvent.Matches( PCB_ACTIONS::distributeHorizontallyGaps.MakeEvent() ) )
517 {
518 doDistributeGaps( true, itemsToDistribute, commit );
519 commitMsg = PCB_ACTIONS::distributeHorizontallyGaps.GetFriendlyName();
520 }
521 else if( aEvent.Matches( PCB_ACTIONS::distributeVerticallyCenters.MakeEvent() ) )
522 {
523 doDistributeCenters( false, itemsToDistribute, commit );
524 commitMsg = PCB_ACTIONS::distributeVerticallyCenters.GetFriendlyName();
525 }
526 else
527 {
528 doDistributeGaps( false, itemsToDistribute, commit );
529 commitMsg = PCB_ACTIONS::distributeVerticallyGaps.GetFriendlyName();
530 }
531
532 commit.Push( commitMsg );
533 return 0;
534}
535
536
538 std::vector<std::pair<BOARD_ITEM*, BOX2I>>& aItems,
539 BOARD_COMMIT& aCommit ) const
540{
541 // Sort by start position.
542 // This is a simple way to get the items in a sensible order but it's not perfect.
543 // It will fail if, say, there's a huge items that's bigger than the total span of
544 // all the other items, but at that point a gap-equalising algorithm probably isn't
545 // well-defined anyway.
546 std::sort( aItems.begin(), aItems.end(),
547 [&]( const std::pair<BOARD_ITEM*, BOX2I>& a, const std::pair<BOARD_ITEM*, BOX2I>& b )
548 {
549 return aIsXAxis ? a.second.GetLeft() < b.second.GetLeft()
550 : a.second.GetTop() < b.second.GetTop();
551 } );
552
553 // Consruct list of item spans in the relevant axis
554 std::vector<std::pair<int, int>> itemSpans;
555 itemSpans.reserve( aItems.size() );
556
557 for( const auto& [item, box] : aItems )
558 {
559 const int start = aIsXAxis ? box.GetLeft() : box.GetTop();
560 const int end = aIsXAxis ? box.GetRight() : box.GetBottom();
561 itemSpans.emplace_back( start, end );
562 }
563
564 // Get the deltas needed to distribute the items evenly
565 const std::vector<int> deltas = GetDeltasForDistributeByGaps( itemSpans );
566
567 // Apply the deltas to the items
568 for( size_t i = 1; i < aItems.size() - 1; ++i )
569 {
570 const auto& [item, box] = aItems[i];
571 const int delta = deltas[i];
572
573 if( delta != 0 )
574 {
575 const VECTOR2I deltaVec = aIsXAxis ? VECTOR2I( delta, 0 ) : VECTOR2I( 0, delta );
576
577 aCommit.Stage( item, CHT_MODIFY );
578 item->Move( deltaVec );
579 }
580 }
581}
582
583
585 std::vector<std::pair<BOARD_ITEM*, BOX2I>>& aItems,
586 BOARD_COMMIT& aCommit ) const
587{
588 std::sort(
589 aItems.begin(), aItems.end(),
590 [&]( const std::pair<BOARD_ITEM*, BOX2I>& lhs, const std::pair<BOARD_ITEM*, BOX2I>& rhs )
591 {
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;
595 } );
596
597 std::vector<int> itemCenters;
598 itemCenters.reserve( aItems.size() );
599
600 for( const auto& [item, box] : aItems )
601 {
602 itemCenters.push_back( aIsXAxis ? box.Centre().x : box.Centre().y );
603 }
604
605 const std::vector<int> deltas = GetDeltasForDistributeByPoints( itemCenters );
606
607 // Apply the deltas to the items
608 for( size_t i = 1; i < aItems.size() - 1; ++i )
609 {
610 const auto& [item, box] = aItems[i];
611 const int delta = deltas[i];
612
613 if ( delta != 0)
614 {
615 const VECTOR2I deltaVec = aIsXAxis ? VECTOR2I( delta, 0 ) : VECTOR2I( 0, delta );
616
617 aCommit.Stage( item, CHT_MODIFY );
618 item->Move( deltaVec );
619 }
620 }
621}
622
623
BOX2I getBoundingBox(BOARD_ITEM *aItem)
BOX2< VECTOR2I > BOX2I
Definition box2.h:922
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:84
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.
Definition collector.h:83
void Remove(int aIndex)
Remove the item at aIndex (first position is 0).
Definition collector.h:111
void AddMenu(ACTION_MENU *aMenu, const SELECTION_CONDITION &aCondition=SELECTION_CONDITIONS::ShowAlways, int aOrder=ANY_ORDER)
Add a submenu to the menu.
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:99
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
Definition eda_item.cpp:120
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:111
bool IsLocked() const override
Definition footprint.h:544
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
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
The selection tool: currently supports:
void FilterCollectorForMarkers(GENERAL_COLLECTOR &aCollector) const
Drop any PCB_MARKERs from the collector.
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.
void FilterCollectorForLockedItems(GENERAL_COLLECTOR &aCollector)
In the PCB editor strip out any locked items unless the OverrideLocks checkbox is set.
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
T * getEditFrame() const
Return the application window object, casted to requested user type.
Definition tool_base.h:186
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:171
bool Matches(const TOOL_EVENT &aEvent) const
Test whether two events match in terms of category & action or command.
Definition tool_event.h:392
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_INTERACTIVE(TOOL_ID aId, const std::string &aName)
Create a tool with given id & name.
@ CHT_MODIFY
Definition commit.h:44
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)
#define _(s)
#define _HKI(x)
Definition page_info.cpp:44
Class that computes missing connections on a PCB.
VECTOR2I end
int delta
@ PCB_MARKER_T
class PCB_MARKER, a marker used to show something
Definition typeinfo.h:99
@ PCB_TABLECELL_T
class PCB_TABLECELL, PCB_TEXTBOX for use in tables
Definition typeinfo.h:95
@ 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