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 // Need at least 3 items to distribute - one at each end and at least on in the middle
492 if( selection.Size() < 3 )
493 return 0;
494
495 BOARD_COMMIT commit( m_frame );
496 wxString commitMsg;
497 std::vector<std::pair<BOARD_ITEM*, BOX2I>> itemsToDistribute;
498
499 for( EDA_ITEM* item : selection )
500 {
501 if( !item->IsBOARD_ITEM() )
502 continue;
503
504 BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( item );
505 itemsToDistribute.emplace_back( std::make_pair( boardItem, getBoundingBox( boardItem ) ) );
506 }
507
508 if( aEvent.Matches( PCB_ACTIONS::distributeHorizontallyCenters.MakeEvent() ) )
509 {
510 doDistributeCenters( true, itemsToDistribute, commit );
511 commitMsg = PCB_ACTIONS::distributeHorizontallyCenters.GetFriendlyName();
512 }
513 else if( aEvent.Matches( PCB_ACTIONS::distributeHorizontallyGaps.MakeEvent() ) )
514 {
515 doDistributeGaps( true, itemsToDistribute, commit );
516 commitMsg = PCB_ACTIONS::distributeHorizontallyGaps.GetFriendlyName();
517 }
518 else if( aEvent.Matches( PCB_ACTIONS::distributeVerticallyCenters.MakeEvent() ) )
519 {
520 doDistributeCenters( false, itemsToDistribute, commit );
521 commitMsg = PCB_ACTIONS::distributeVerticallyCenters.GetFriendlyName();
522 }
523 else
524 {
525 doDistributeGaps( false, itemsToDistribute, commit );
526 commitMsg = PCB_ACTIONS::distributeVerticallyGaps.GetFriendlyName();
527 }
528
529 commit.Push( commitMsg );
530 return 0;
531}
532
533
535 std::vector<std::pair<BOARD_ITEM*, BOX2I>>& aItems,
536 BOARD_COMMIT& aCommit ) const
537{
538 // Sort by start position.
539 // This is a simple way to get the items in a sensible order but it's not perfect.
540 // It will fail if, say, there's a huge items that's bigger than the total span of
541 // all the other items, but at that point a gap-equalising algorithm probably isn't
542 // well-defined anyway.
543 std::sort( aItems.begin(), aItems.end(),
544 [&]( const std::pair<BOARD_ITEM*, BOX2I>& a, const std::pair<BOARD_ITEM*, BOX2I>& b )
545 {
546 return aIsXAxis ? a.second.GetLeft() < b.second.GetLeft()
547 : a.second.GetTop() < b.second.GetTop();
548 } );
549
550 // Consruct list of item spans in the relevant axis
551 std::vector<std::pair<int, int>> itemSpans;
552 itemSpans.reserve( aItems.size() );
553
554 for( const auto& [item, box] : aItems )
555 {
556 const int start = aIsXAxis ? box.GetLeft() : box.GetTop();
557 const int end = aIsXAxis ? box.GetRight() : box.GetBottom();
558 itemSpans.emplace_back( start, end );
559 }
560
561 // Get the deltas needed to distribute the items evenly
562 const std::vector<int> deltas = GetDeltasForDistributeByGaps( itemSpans );
563
564 // Apply the deltas to the items
565 for( size_t i = 1; i < aItems.size() - 1; ++i )
566 {
567 const auto& [item, box] = aItems[i];
568 const int delta = deltas[i];
569
570 if( delta != 0 )
571 {
572 const VECTOR2I deltaVec = aIsXAxis ? VECTOR2I( delta, 0 ) : VECTOR2I( 0, delta );
573
574 aCommit.Stage( item, CHT_MODIFY );
575 item->Move( deltaVec );
576 }
577 }
578}
579
580
582 std::vector<std::pair<BOARD_ITEM*, BOX2I>>& aItems,
583 BOARD_COMMIT& aCommit ) const
584{
585 std::sort(
586 aItems.begin(), aItems.end(),
587 [&]( const std::pair<BOARD_ITEM*, BOX2I>& lhs, const std::pair<BOARD_ITEM*, BOX2I>& rhs )
588 {
589 const int lhsPos = aIsXAxis ? lhs.second.Centre().x : lhs.second.Centre().y;
590 const int rhsPos = aIsXAxis ? rhs.second.Centre().x : rhs.second.Centre().y;
591 return lhsPos < rhsPos;
592 } );
593
594 std::vector<int> itemCenters;
595 itemCenters.reserve( aItems.size() );
596
597 for( const auto& [item, box] : aItems )
598 {
599 itemCenters.push_back( aIsXAxis ? box.Centre().x : box.Centre().y );
600 }
601
602 const std::vector<int> deltas = GetDeltasForDistributeByPoints( itemCenters );
603
604 // Apply the deltas to the items
605 for( size_t i = 1; i < aItems.size() - 1; ++i )
606 {
607 const auto& [item, box] = aItems[i];
608 const int delta = deltas[i];
609
610 if ( delta != 0)
611 {
612 const VECTOR2I deltaVec = aIsXAxis ? VECTOR2I( delta, 0 ) : VECTOR2I( 0, delta );
613
614 aCommit.Stage( item, CHT_MODIFY );
615 item->Move( deltaVec );
616 }
617 }
618}
619
620
BOX2I getBoundingBox(BOARD_ITEM *aItem)
BOX2< VECTOR2I > BOX2I
Definition box2.h:918
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:81
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:96
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
Definition eda_item.cpp:135
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:108
bool IsLocked() const override
Definition footprint.h:634
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:117
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
Returns the instance of #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:92
@ PCB_TABLECELL_T
class PCB_TABLECELL, PCB_TEXTBOX for use in tables
Definition typeinfo.h:88
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
Definition typeinfo.h:79
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition typeinfo.h:80
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683