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