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, see <https://www.gnu.org/licenses/>.
20 */
21#include "tool/selection.h"
23#include "pcb_actions.h"
24#include "pcb_selection_tool.h"
25
27#include <tool/tool_manager.h>
28
29#include <board.h>
30#include <board_commit.h>
31#include <footprint.h>
32#include <collectors.h>
33#include <bitmaps.h>
34#include <pcb_edit_frame.h>
35#include <geometry/distribute.h>
36#include <view/view_controls.h>
37
38
40 TOOL_INTERACTIVE( "pcbnew.Placement" ),
41 m_selectionTool( nullptr ),
42 m_placementMenu( nullptr ),
43 m_frame( nullptr )
44{
45}
46
51
52
54{
55 // Find the selection tool, so they can cooperate
58
59 // Create a context menu and make it available through selection tool
62 m_placementMenu->SetUntranslatedTitle( _HKI( "Align/Distribute" ) );
63
64 const auto canAlign = SELECTION_CONDITIONS::MoreThan( 1 );
65 const auto canDistribute = SELECTION_CONDITIONS::MoreThan( 2 );
66
67 // Add all align/distribute commands
68 m_placementMenu->AddItem( PCB_ACTIONS::alignLeft, canAlign );
69 m_placementMenu->AddItem( PCB_ACTIONS::alignCenterX, canAlign );
70 m_placementMenu->AddItem( PCB_ACTIONS::alignRight, canAlign );
71
72 m_placementMenu->AddSeparator( canAlign );
73 m_placementMenu->AddItem( PCB_ACTIONS::alignTop, canAlign );
74 m_placementMenu->AddItem( PCB_ACTIONS::alignCenterY, canAlign );
75 m_placementMenu->AddItem( PCB_ACTIONS::alignBottom, canAlign );
76
77 m_placementMenu->AddSeparator( canDistribute );
82
83 CONDITIONAL_MENU& selToolMenu = m_selectionTool->GetToolMenu().GetMenu();
85
86 return true;
87}
88
89
91{
92 if( aItem->Type() == PCB_FOOTPRINT_T )
93 return static_cast<FOOTPRINT*>( aItem )->GetBoundingBox( false );
94 else
95 return aItem->GetBoundingBox();
96}
97
98
99template< typename T >
100int ALIGN_DISTRIBUTE_TOOL::selectTarget( std::vector<std::pair<BOARD_ITEM*, BOX2I>>& aItems,
101 std::vector<std::pair<BOARD_ITEM*, BOX2I>>& aLocked,
102 T aGetValue )
103{
105
106 // Prefer locked items to unlocked items.
107 // Secondly, prefer items under the cursor to other items.
108
109 if( aLocked.size() >= 1 )
110 {
111 for( const std::pair<BOARD_ITEM*, BOX2I>& item : aLocked )
112 {
113 if( item.second.Contains( curPos ) )
114 return aGetValue( item );
115 }
116
117 return aGetValue( aLocked.front() );
118 }
119
120 for( const std::pair<BOARD_ITEM*, BOX2I>& item : aItems )
121 {
122 if( item.second.Contains( curPos ) )
123 return aGetValue( item );
124 }
125
126 return aGetValue( aItems.front() );
127}
128
129
130template< typename T >
131size_t ALIGN_DISTRIBUTE_TOOL::GetSelections( std::vector<std::pair<BOARD_ITEM*, BOX2I>>& aItemsToAlign,
132 std::vector<std::pair<BOARD_ITEM*, BOX2I>>& aLockedItems,
133 T aCompare )
134{
135 PCB_SELECTION& selection = m_selectionTool->RequestSelection(
136 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
137 {
138 // Iterate from the back so we don't have to worry about removals.
139 for( int i = aCollector.GetCount() - 1; i >= 0; --i )
140 {
141 BOARD_ITEM* item = aCollector[i];
142
143 if( item->Type() == PCB_MARKER_T )
144 aCollector.Remove( item );
145 }
146 } );
147
148 bool allPads = true;
149 BOARD_ITEM_CONTAINER* currentParent = nullptr;
150 bool differentParents = false;
151 bool allowFreePads = m_selectionTool->IsFootprintEditor()
152 || m_frame->GetPcbNewSettings()->m_AllowFreePads;
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() || item->Type() == PCB_TABLECELL_T )
191 continue;
192
193 BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( item );
194
195 if( boardItem->Type() == PCB_PAD_T && ( !allowFreePads || ( 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{
478 PCB_SELECTION& selection = m_selectionTool->RequestSelection(
479 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
480 {
481 sTool->FilterCollectorForMarkers( aCollector );
482 sTool->FilterCollectorForHierarchy( aCollector, true );
483
484 // Don't filter for free pads. We want to allow for distributing other
485 // items (such as a via) between two pads.
486 // sTool->FilterCollectorForFreePads( aCollector );
487
488 sTool->FilterCollectorForLockedItems( aCollector );
489 } );
490
491 if( m_selectionTool->ReportFilteredLockedItems() )
492 return 0;
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:914
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
Set up handlers for various 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.
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:79
void Remove(int aIndex)
Remove the item at aIndex (first position is 0).
Definition collector.h:107
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:98
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
Definition eda_item.cpp:270
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
bool IsLocked() const override
Definition footprint.h:682
Used when the right click button is pressed, or when the select tool is in effect.
Definition collectors.h:203
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:120
T * getEditFrame() const
Return the application window object, casted to requested user type.
Definition tool_base.h:182
KIGFX::VIEW_CONTROLS * getViewControls() const
Return the instance of VIEW_CONTROLS object used in the application.
Definition tool_base.cpp:40
TOOL_MANAGER * m_toolMgr
Definition tool_base.h:220
KIGFX::VIEW * getView() const
Return the instance of KIGFX::VIEW object used in the application.
Definition tool_base.cpp:34
Generic, UI-independent tool event.
Definition tool_event.h:167
bool Matches(const TOOL_EVENT &aEvent) const
Test whether two events match in terms of category & action or command.
Definition tool_event.h:388
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:40
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:40
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:91
@ PCB_TABLECELL_T
class PCB_TABLECELL, PCB_TEXTBOX for use in tables
Definition typeinfo.h:87
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
Definition typeinfo.h:78
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition typeinfo.h:79
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:708