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
53
54
56{
57 // Find the selection tool, so they can cooperate
60
61 // Create a context menu and make it available through selection tool
64 m_placementMenu->SetUntranslatedTitle( _HKI( "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
70 m_placementMenu->AddItem( PCB_ACTIONS::alignLeft, canAlign );
71 m_placementMenu->AddItem( PCB_ACTIONS::alignCenterX, canAlign );
72 m_placementMenu->AddItem( PCB_ACTIONS::alignRight, canAlign );
73
74 m_placementMenu->AddSeparator( canAlign );
75 m_placementMenu->AddItem( PCB_ACTIONS::alignTop, canAlign );
76 m_placementMenu->AddItem( PCB_ACTIONS::alignCenterY, canAlign );
77 m_placementMenu->AddItem( PCB_ACTIONS::alignBottom, canAlign );
78
79 m_placementMenu->AddSeparator( canDistribute );
84
85 CONDITIONAL_MENU& selToolMenu = m_selectionTool->GetToolMenu().GetMenu();
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{
137 PCB_SELECTION& selection = m_selectionTool->RequestSelection(
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 bool allowFreePads = m_selectionTool->IsFootprintEditor()
154 || m_frame->GetPcbNewSettings()->m_AllowFreePads;
155
156 for( EDA_ITEM* item : selection )
157 {
158 if( !item->IsBOARD_ITEM() )
159 continue;
160
161 if( item->Type() != PCB_PAD_T )
162 allPads = false;
163
164 BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( item );
165 BOARD_ITEM_CONTAINER* parent = boardItem->GetParentFootprint();
166
167 if( !parent )
168 parent = boardItem->GetBoard();
169
170 if( !currentParent )
171 currentParent = parent;
172 else if( parent != currentParent )
173 differentParents = true;
174 }
175
176 auto addToList =
177 []( std::vector<std::pair<BOARD_ITEM*, BOX2I>>& list, BOARD_ITEM* item, FOOTPRINT* parentFp )
178 {
179 BOARD_ITEM* listItem = parentFp ? parentFp : item;
180
181 for( const auto& [candidate, bbox] : list )
182 {
183 if( candidate == listItem )
184 return;
185 }
186
187 list.emplace_back( std::make_pair( listItem, getBoundingBox( item ) ) );
188 };
189
190 for( EDA_ITEM* item : selection )
191 {
192 if( !item->IsBOARD_ITEM() )
193 continue;
194
195 BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( item );
196
197 if( boardItem->Type() == PCB_PAD_T && ( !allowFreePads || ( allPads && differentParents ) ) )
198 {
199 FOOTPRINT* parentFp = boardItem->GetParentFootprint();
200
201 if( parentFp && parentFp->IsLocked() )
202 addToList( aLockedItems, boardItem, parentFp );
203 else
204 addToList( aItemsToAlign, boardItem, parentFp );
205
206 continue;
207 }
208
209 if( boardItem->IsLocked() )
210 addToList( aLockedItems, boardItem, nullptr );
211 else
212 addToList( aItemsToAlign, boardItem, nullptr );
213 }
214
215 std::sort( aItemsToAlign.begin(), aItemsToAlign.end(), aCompare );
216 std::sort( aLockedItems.begin(), aLockedItems.end(), aCompare );
217
218 return aItemsToAlign.size();
219}
220
221
223{
224 std::vector<std::pair<BOARD_ITEM*, BOX2I>> itemsToAlign;
225 std::vector<std::pair<BOARD_ITEM*, BOX2I>> locked_items;
226
227 if( !GetSelections( itemsToAlign, locked_items,
228 []( const std::pair<BOARD_ITEM*, BOX2I>& lhs, const std::pair<BOARD_ITEM*, BOX2I>& rhs )
229 {
230 return ( lhs.second.GetTop() < rhs.second.GetTop() );
231 } ) )
232 {
233 return 0;
234 }
235
236 BOARD_COMMIT commit( m_frame );
237
238 int targetTop = selectTarget( itemsToAlign, locked_items,
239 []( const std::pair<BOARD_ITEM*, BOX2I>& aVal )
240 {
241 return aVal.second.GetTop();
242 } );
243
244 // Move the selected items
245 for( const auto& [item, bbox] : itemsToAlign )
246 {
247 if( item->GetParent() && item->GetParent()->IsSelected() )
248 continue;
249
250 int difference = targetTop - bbox.GetTop();
251
252 commit.Stage( item, CHT_MODIFY );
253 item->Move( VECTOR2I( 0, difference ) );
254 }
255
256 commit.Push( _( "Align to Top" ) );
257 return 0;
258}
259
260
262{
263 std::vector<std::pair<BOARD_ITEM*, BOX2I>> itemsToAlign;
264 std::vector<std::pair<BOARD_ITEM*, BOX2I>> locked_items;
265
266 if( !GetSelections( itemsToAlign, locked_items,
267 []( const std::pair<BOARD_ITEM*, BOX2I>& lhs, const std::pair<BOARD_ITEM*, BOX2I>& rhs)
268 {
269 return ( lhs.second.GetBottom() > rhs.second.GetBottom() );
270 } ) )
271 {
272 return 0;
273 }
274
275 BOARD_COMMIT commit( m_frame );
276
277 int targetBottom = selectTarget( itemsToAlign, locked_items,
278 []( const std::pair<BOARD_ITEM*, BOX2I>& aVal )
279 {
280 return aVal.second.GetBottom();
281 } );
282
283 // Move the selected items
284 for( const auto& [item, bbox] : itemsToAlign )
285 {
286 if( item->GetParent() && item->GetParent()->IsSelected() )
287 continue;
288
289 int difference = targetBottom - bbox.GetBottom();
290
291 commit.Stage( item, CHT_MODIFY );
292 item->Move( VECTOR2I( 0, difference ) );
293 }
294
295 commit.Push( _( "Align to Bottom" ) );
296 return 0;
297}
298
299
301{
302 // Because this tool uses bounding boxes and they aren't mirrored even when
303 // the view is mirrored, we need to call the other one if mirrored.
304 if( getView()->IsMirroredX() )
305 return doAlignRight();
306 else
307 return doAlignLeft();
308}
309
310
312{
313 std::vector<std::pair<BOARD_ITEM*, BOX2I>> itemsToAlign;
314 std::vector<std::pair<BOARD_ITEM*, BOX2I>> locked_items;
315
316 if( !GetSelections( itemsToAlign, locked_items,
317 []( const std::pair<BOARD_ITEM*, BOX2I>& lhs, const std::pair<BOARD_ITEM*, BOX2I>& rhs )
318 {
319 return ( lhs.second.GetLeft() < rhs.second.GetLeft() );
320 } ) )
321 {
322 return 0;
323 }
324
325 BOARD_COMMIT commit( m_frame );
326
327 int targetLeft = selectTarget( itemsToAlign, locked_items,
328 []( const std::pair<BOARD_ITEM*, BOX2I>& aVal )
329 {
330 return aVal.second.GetLeft();
331 } );
332
333 // Move the selected items
334 for( const auto& [item, bbox] : itemsToAlign )
335 {
336 if( item->GetParent() && item->GetParent()->IsSelected() )
337 continue;
338
339 int difference = targetLeft - bbox.GetLeft();
340
341 commit.Stage( item, CHT_MODIFY );
342 item->Move( VECTOR2I( difference, 0 ) );
343 }
344
345 commit.Push( _( "Align to Left" ) );
346 return 0;
347}
348
349
351{
352 // Because this tool uses bounding boxes and they aren't mirrored even when
353 // the view is mirrored, we need to call the other one if mirrored.
354 if( getView()->IsMirroredX() )
355 return doAlignLeft();
356 else
357 return doAlignRight();
358}
359
360
362{
363 std::vector<std::pair<BOARD_ITEM*, BOX2I>> itemsToAlign;
364 std::vector<std::pair<BOARD_ITEM*, BOX2I>> locked_items;
365
366 if( !GetSelections( itemsToAlign, locked_items,
367 []( const std::pair<BOARD_ITEM*, BOX2I>& lhs, const std::pair<BOARD_ITEM*, BOX2I>& rhs )
368 {
369 return ( lhs.second.GetRight() > rhs.second.GetRight() );
370 } ) )
371 {
372 return 0;
373 }
374
375 BOARD_COMMIT commit( m_frame );
376
377 int targetRight = selectTarget( itemsToAlign, locked_items,
378 []( const std::pair<BOARD_ITEM*, BOX2I>& aVal )
379 {
380 return aVal.second.GetRight();
381 } );
382
383 // Move the selected items
384 for( const auto& [item, bbox] : itemsToAlign )
385 {
386 if( item->GetParent() && item->GetParent()->IsSelected() )
387 continue;
388
389 int difference = targetRight - bbox.GetRight();
390
391 commit.Stage( item, CHT_MODIFY );
392 item->Move( VECTOR2I( difference, 0 ) );
393 }
394
395 commit.Push( _( "Align to Right" ) );
396 return 0;
397}
398
399
401{
402 std::vector<std::pair<BOARD_ITEM*, BOX2I>> itemsToAlign;
403 std::vector<std::pair<BOARD_ITEM*, BOX2I>> locked_items;
404
405 if( !GetSelections( itemsToAlign, locked_items,
406 []( const std::pair<BOARD_ITEM*, BOX2I>& lhs, const std::pair<BOARD_ITEM*, BOX2I>& rhs )
407 {
408 return ( lhs.second.Centre().x < rhs.second.Centre().x );
409 } ) )
410 {
411 return 0;
412 }
413
414 BOARD_COMMIT commit( m_frame );
415
416 int targetX = selectTarget( itemsToAlign, locked_items,
417 []( const std::pair<BOARD_ITEM*, BOX2I>& aVal )
418 {
419 return aVal.second.Centre().x;
420 } );
421
422 // Move the selected items
423 for( const auto& [item, bbox] : itemsToAlign )
424 {
425 if( item->GetParent() && item->GetParent()->IsSelected() )
426 continue;
427
428 int difference = targetX - bbox.Centre().x;
429
430 commit.Stage( item, CHT_MODIFY );
431 item->Move( VECTOR2I( difference, 0 ) );
432 }
433
434 commit.Push( _( "Align to Middle" ) );
435 return 0;
436}
437
438
440{
441 std::vector<std::pair<BOARD_ITEM*, BOX2I>> itemsToAlign;
442 std::vector<std::pair<BOARD_ITEM*, BOX2I>> locked_items;
443
444 if( !GetSelections( itemsToAlign, locked_items,
445 []( const std::pair<BOARD_ITEM*, BOX2I>& lhs, const std::pair<BOARD_ITEM*, BOX2I>& rhs )
446 {
447 return ( lhs.second.Centre().y < rhs.second.Centre().y );
448 } ) )
449 {
450 return 0;
451 }
452
453 BOARD_COMMIT commit( m_frame );
454
455 int targetY = selectTarget( itemsToAlign, locked_items,
456 []( const std::pair<BOARD_ITEM*, BOX2I>& aVal )
457 {
458 return aVal.second.Centre().y;
459 } );
460
461 // Move the selected items
462 for( const auto& [item, bbox] : itemsToAlign )
463 {
464 if( item->GetParent() && item->GetParent()->IsSelected() )
465 continue;
466
467 int difference = targetY - bbox.Centre().y;
468
469 commit.Stage( item, CHT_MODIFY );
470 item->Move( VECTOR2I( 0, difference ) );
471 }
472
473 commit.Push( _( "Align to Center" ) );
474 return 0;
475}
476
477
479{
480 PCB_SELECTION& selection = m_selectionTool->RequestSelection(
481 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
482 {
483 sTool->FilterCollectorForMarkers( aCollector );
484 sTool->FilterCollectorForHierarchy( aCollector, true );
485
486 // Don't filter for free pads. We want to allow for distributing other
487 // items (such as a via) between two pads.
488 // sTool->FilterCollectorForFreePads( aCollector );
489
490 sTool->FilterCollectorForLockedItems( aCollector );
491 } );
492
493 // Need at least 3 items to distribute - one at each end and at least on in the middle
494 if( selection.Size() < 3 )
495 return 0;
496
497 BOARD_COMMIT commit( m_frame );
498 wxString commitMsg;
499 std::vector<std::pair<BOARD_ITEM*, BOX2I>> itemsToDistribute;
500
501 for( EDA_ITEM* item : selection )
502 {
503 if( !item->IsBOARD_ITEM() )
504 continue;
505
506 BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( item );
507 itemsToDistribute.emplace_back( std::make_pair( boardItem, getBoundingBox( boardItem ) ) );
508 }
509
510 if( aEvent.Matches( PCB_ACTIONS::distributeHorizontallyCenters.MakeEvent() ) )
511 {
512 doDistributeCenters( true, itemsToDistribute, commit );
513 commitMsg = PCB_ACTIONS::distributeHorizontallyCenters.GetFriendlyName();
514 }
515 else if( aEvent.Matches( PCB_ACTIONS::distributeHorizontallyGaps.MakeEvent() ) )
516 {
517 doDistributeGaps( true, itemsToDistribute, commit );
518 commitMsg = PCB_ACTIONS::distributeHorizontallyGaps.GetFriendlyName();
519 }
520 else if( aEvent.Matches( PCB_ACTIONS::distributeVerticallyCenters.MakeEvent() ) )
521 {
522 doDistributeCenters( false, itemsToDistribute, commit );
523 commitMsg = PCB_ACTIONS::distributeVerticallyCenters.GetFriendlyName();
524 }
525 else
526 {
527 doDistributeGaps( false, itemsToDistribute, commit );
528 commitMsg = PCB_ACTIONS::distributeVerticallyGaps.GetFriendlyName();
529 }
530
531 commit.Push( commitMsg );
532 return 0;
533}
534
535
537 std::vector<std::pair<BOARD_ITEM*, BOX2I>>& aItems,
538 BOARD_COMMIT& aCommit ) const
539{
540 // Sort by start position.
541 // This is a simple way to get the items in a sensible order but it's not perfect.
542 // It will fail if, say, there's a huge items that's bigger than the total span of
543 // all the other items, but at that point a gap-equalising algorithm probably isn't
544 // well-defined anyway.
545 std::sort( aItems.begin(), aItems.end(),
546 [&]( const std::pair<BOARD_ITEM*, BOX2I>& a, const std::pair<BOARD_ITEM*, BOX2I>& b )
547 {
548 return aIsXAxis ? a.second.GetLeft() < b.second.GetLeft()
549 : a.second.GetTop() < b.second.GetTop();
550 } );
551
552 // Consruct list of item spans in the relevant axis
553 std::vector<std::pair<int, int>> itemSpans;
554 itemSpans.reserve( aItems.size() );
555
556 for( const auto& [item, box] : aItems )
557 {
558 const int start = aIsXAxis ? box.GetLeft() : box.GetTop();
559 const int end = aIsXAxis ? box.GetRight() : box.GetBottom();
560 itemSpans.emplace_back( start, end );
561 }
562
563 // Get the deltas needed to distribute the items evenly
564 const std::vector<int> deltas = GetDeltasForDistributeByGaps( itemSpans );
565
566 // Apply the deltas to the items
567 for( size_t i = 1; i < aItems.size() - 1; ++i )
568 {
569 const auto& [item, box] = aItems[i];
570 const int delta = deltas[i];
571
572 if( delta != 0 )
573 {
574 const VECTOR2I deltaVec = aIsXAxis ? VECTOR2I( delta, 0 ) : VECTOR2I( 0, delta );
575
576 aCommit.Stage( item, CHT_MODIFY );
577 item->Move( deltaVec );
578 }
579 }
580}
581
582
584 std::vector<std::pair<BOARD_ITEM*, BOX2I>>& aItems,
585 BOARD_COMMIT& aCommit ) const
586{
587 std::sort(
588 aItems.begin(), aItems.end(),
589 [&]( const std::pair<BOARD_ITEM*, BOX2I>& lhs, const std::pair<BOARD_ITEM*, BOX2I>& rhs )
590 {
591 const int lhsPos = aIsXAxis ? lhs.second.Centre().x : lhs.second.Centre().y;
592 const int rhsPos = aIsXAxis ? rhs.second.Centre().x : rhs.second.Centre().y;
593 return lhsPos < rhsPos;
594 } );
595
596 std::vector<int> itemCenters;
597 itemCenters.reserve( aItems.size() );
598
599 for( const auto& [item, box] : aItems )
600 {
601 itemCenters.push_back( aIsXAxis ? box.Centre().x : box.Centre().y );
602 }
603
604 const std::vector<int> deltas = GetDeltasForDistributeByPoints( itemCenters );
605
606 // Apply the deltas to the items
607 for( size_t i = 1; i < aItems.size() - 1; ++i )
608 {
609 const auto& [item, box] = aItems[i];
610 const int delta = deltas[i];
611
612 if ( delta != 0)
613 {
614 const VECTOR2I deltaVec = aIsXAxis ? VECTOR2I( delta, 0 ) : VECTOR2I( 0, delta );
615
616 aCommit.Stage( item, CHT_MODIFY );
617 item->Move( deltaVec );
618 }
619 }
620}
621
622
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:79
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: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:454
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_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