KiCad PCB EDA Suite
Loading...
Searching...
No Matches
placement_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 (C) 2021-2022 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"
26#include "placement_tool.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
50{
51 delete m_placementMenu;
52}
53
54
56{
57 // Find the selection tool, so they can cooperate
59 m_frame = getEditFrame<PCB_BASE_FRAME>();
60
61 // Create a context menu and make it available through selection tool
63 m_placementMenu->SetIcon( BITMAPS::align_items );
64 m_placementMenu->SetTitle( _( "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
73
74 m_placementMenu->AddSeparator( canAlign );
78
79 m_placementMenu->AddSeparator( canDistribute );
84
87
88 return true;
89}
90
91
92template <class T>
93std::vector<std::pair<BOARD_ITEM*, BOX2I>> GetBoundingBoxes( const T& aItems )
94{
95 std::vector<std::pair<BOARD_ITEM*, BOX2I>> rects;
96
97 for( EDA_ITEM* item : aItems )
98 {
99 BOARD_ITEM* boardItem = dynamic_cast<BOARD_ITEM*>( item );
100
101 wxCHECK2( boardItem, continue );
102
103 if( item->Type() == PCB_FOOTPRINT_T )
104 {
105 FOOTPRINT* footprint = static_cast<FOOTPRINT*>( item );
106 rects.emplace_back( std::make_pair( footprint,
107 footprint->GetBoundingBox( false, false ) ) );
108 }
109 else
110 {
111 rects.emplace_back( std::make_pair( boardItem, boardItem->GetBoundingBox() ) );
112 }
113 }
114
115 return rects;
116}
117
118
119template< typename T >
120int ALIGN_DISTRIBUTE_TOOL::selectTarget( std::vector<std::pair<BOARD_ITEM*, BOX2I>>& aItems,
121 std::vector<std::pair<BOARD_ITEM*, BOX2I>>& aLocked,
122 T aGetValue )
123{
125
126 // Prefer locked items to unlocked items.
127 // Secondly, prefer items under the cursor to other items.
128
129 if( aLocked.size() >= 1 )
130 {
131 for( const std::pair<BOARD_ITEM*, BOX2I>& item : aLocked )
132 {
133 if( item.second.Contains( curPos ) )
134 return aGetValue( item );
135 }
136
137 return aGetValue( aLocked.front() );
138 }
139
140 for( const std::pair<BOARD_ITEM*, BOX2I>& item : aItems )
141 {
142 if( item.second.Contains( curPos ) )
143 return aGetValue( item );
144 }
145
146 return aGetValue( aItems.front() );
147}
148
149
150template< typename T >
151size_t ALIGN_DISTRIBUTE_TOOL::GetSelections( std::vector<std::pair<BOARD_ITEM*, BOX2I>>& aItemsToAlign,
152 std::vector<std::pair<BOARD_ITEM*, BOX2I>>& aLockedItems,
153 T aCompare )
154{
156 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
157 {
158 // Iterate from the back so we don't have to worry about removals.
159 for( int i = aCollector.GetCount() - 1; i >= 0; --i )
160 {
161 BOARD_ITEM* item = aCollector[i];
162
163 if( item->Type() == PCB_MARKER_T )
164 aCollector.Remove( item );
165 }
166 } );
167
168 std::vector<BOARD_ITEM*> lockedItems;
169 std::vector<BOARD_ITEM*> itemsToAlign;
170
171 for( EDA_ITEM* item : selection )
172 {
173 BOARD_ITEM* boardItem = dynamic_cast<BOARD_ITEM*>( item );
174 wxCHECK2( boardItem, continue );
175
176 // We do not lock items in the footprint editor
177 if( boardItem->IsLocked() && m_frame->IsType( FRAME_PCB_EDITOR ) )
178 {
179 // Locking a pad but not the footprint means that we align the footprint using
180 // the pad position. So we test for footprint locking here
181 if( boardItem->Type() == PCB_PAD_T && !boardItem->GetParent()->IsLocked() )
182 itemsToAlign.push_back( boardItem );
183 else
184 lockedItems.push_back( boardItem );
185 }
186 else
187 itemsToAlign.push_back( boardItem );
188 }
189
190 aItemsToAlign = GetBoundingBoxes( itemsToAlign );
191 aLockedItems = GetBoundingBoxes( lockedItems );
192 std::sort( aItemsToAlign.begin(), aItemsToAlign.end(), aCompare );
193 std::sort( aLockedItems.begin(), aLockedItems.end(), aCompare );
194
195 return aItemsToAlign.size();
196}
197
198
200{
201 std::vector<std::pair<BOARD_ITEM*, BOX2I>> itemsToAlign;
202 std::vector<std::pair<BOARD_ITEM*, BOX2I>> locked_items;
203
204 if( !GetSelections( itemsToAlign, locked_items,
205 []( const std::pair<BOARD_ITEM*, BOX2I>& lhs, const std::pair<BOARD_ITEM*, BOX2I>& rhs )
206 {
207 return ( lhs.second.GetTop() < rhs.second.GetTop() );
208 } ) )
209 {
210 return 0;
211 }
212
213 BOARD_COMMIT commit( m_frame );
214
215 int targetTop = selectTarget( itemsToAlign, locked_items,
216 []( const std::pair<BOARD_ITEM*, BOX2I>& aVal )
217 {
218 return aVal.second.GetTop();
219 } );
220
221 // Move the selected items
222 for( const std::pair<BOARD_ITEM*, BOX2I>& i : itemsToAlign )
223 {
224 BOARD_ITEM* item = i.first;
225 int difference = targetTop - i.second.GetTop();
226
227 if( item->GetParent() && item->GetParent()->IsSelected() )
228 continue;
229
230 // Don't move a pad by itself unless editing the footprint
231 if( item->Type() == PCB_PAD_T && m_frame->IsType( FRAME_PCB_EDITOR ) )
232 item = item->GetParent();
233
234 commit.Stage( item, CHT_MODIFY );
235 item->Move( VECTOR2I( 0, difference ) );
236 }
237
238 commit.Push( _( "Align to Top" ) );
239 return 0;
240}
241
242
244{
245 std::vector<std::pair<BOARD_ITEM*, BOX2I>> itemsToAlign;
246 std::vector<std::pair<BOARD_ITEM*, BOX2I>> locked_items;
247
248 if( !GetSelections( itemsToAlign, locked_items,
249 []( const std::pair<BOARD_ITEM*, BOX2I>& lhs, const std::pair<BOARD_ITEM*, BOX2I>& rhs)
250 {
251 return ( lhs.second.GetBottom() > rhs.second.GetBottom() );
252 } ) )
253 {
254 return 0;
255 }
256
257 BOARD_COMMIT commit( m_frame );
258
259 int targetBottom = selectTarget( itemsToAlign, locked_items,
260 []( const std::pair<BOARD_ITEM*, BOX2I>& aVal )
261 {
262 return aVal.second.GetBottom();
263 } );
264
265 // Move the selected items
266 for( const std::pair<BOARD_ITEM*, BOX2I>& i : itemsToAlign )
267 {
268 int difference = targetBottom - i.second.GetBottom();
269 BOARD_ITEM* item = i.first;
270
271 if( item->GetParent() && item->GetParent()->IsSelected() )
272 continue;
273
274 // Don't move a pad by itself unless editing the footprint
275 if( item->Type() == PCB_PAD_T && m_frame->IsType( FRAME_PCB_EDITOR ) )
276 item = item->GetParent();
277
278 commit.Stage( item, CHT_MODIFY );
279 item->Move( VECTOR2I( 0, difference ) );
280 }
281
282 commit.Push( _( "Align to Bottom" ) );
283 return 0;
284}
285
286
288{
289 // Because this tool uses bounding boxes and they aren't mirrored even when
290 // the view is mirrored, we need to call the other one if mirrored.
291 if( getView()->IsMirroredX() )
292 return doAlignRight();
293 else
294 return doAlignLeft();
295}
296
297
299{
300 std::vector<std::pair<BOARD_ITEM*, BOX2I>> itemsToAlign;
301 std::vector<std::pair<BOARD_ITEM*, BOX2I>> locked_items;
302
303 if( !GetSelections( itemsToAlign, locked_items,
304 []( const std::pair<BOARD_ITEM*, BOX2I>& lhs, const std::pair<BOARD_ITEM*, BOX2I>& rhs )
305 {
306 return ( lhs.second.GetLeft() < rhs.second.GetLeft() );
307 } ) )
308 {
309 return 0;
310 }
311
312 BOARD_COMMIT commit( m_frame );
313
314 int targetLeft = selectTarget( itemsToAlign, locked_items,
315 []( const std::pair<BOARD_ITEM*, BOX2I>& aVal )
316 {
317 return aVal.second.GetLeft();
318 } );
319
320 // Move the selected items
321 for( const std::pair<BOARD_ITEM*, BOX2I>& i : itemsToAlign )
322 {
323 int difference = targetLeft - i.second.GetLeft();
324 BOARD_ITEM* item = i.first;
325
326 if( item->GetParent() && item->GetParent()->IsSelected() )
327 continue;
328
329 // Don't move a pad by itself unless editing the footprint
330 if( item->Type() == PCB_PAD_T && m_frame->IsType( FRAME_PCB_EDITOR ) )
331 item = item->GetParent();
332
333 commit.Stage( item, CHT_MODIFY );
334 item->Move( VECTOR2I( difference, 0 ) );
335 }
336
337 commit.Push( _( "Align to Left" ) );
338 return 0;
339}
340
341
343{
344 // Because this tool uses bounding boxes and they aren't mirrored even when
345 // the view is mirrored, we need to call the other one if mirrored.
346 if( getView()->IsMirroredX() )
347 return doAlignLeft();
348 else
349 return doAlignRight();
350}
351
352
354{
355 std::vector<std::pair<BOARD_ITEM*, BOX2I>> itemsToAlign;
356 std::vector<std::pair<BOARD_ITEM*, BOX2I>> locked_items;
357
358 if( !GetSelections( itemsToAlign, locked_items,
359 []( const std::pair<BOARD_ITEM*, BOX2I>& lhs, const std::pair<BOARD_ITEM*, BOX2I>& rhs )
360 {
361 return ( lhs.second.GetRight() > rhs.second.GetRight() );
362 } ) )
363 {
364 return 0;
365 }
366
367 BOARD_COMMIT commit( m_frame );
368
369 int targetRight = selectTarget( itemsToAlign, locked_items,
370 []( const std::pair<BOARD_ITEM*, BOX2I>& aVal )
371 {
372 return aVal.second.GetRight();
373 } );
374
375 // Move the selected items
376 for( const std::pair<BOARD_ITEM*, BOX2I>& i : itemsToAlign )
377 {
378 int difference = targetRight - i.second.GetRight();
379 BOARD_ITEM* item = i.first;
380
381 if( item->GetParent() && item->GetParent()->IsSelected() )
382 continue;
383
384 // Don't move a pad by itself unless editing the footprint
385 if( item->Type() == PCB_PAD_T && m_frame->IsType( FRAME_PCB_EDITOR ) )
386 item = item->GetParent();
387
388 commit.Stage( item, CHT_MODIFY );
389 item->Move( VECTOR2I( difference, 0 ) );
390 }
391
392 commit.Push( _( "Align to Right" ) );
393 return 0;
394}
395
396
398{
399 std::vector<std::pair<BOARD_ITEM*, BOX2I>> itemsToAlign;
400 std::vector<std::pair<BOARD_ITEM*, BOX2I>> locked_items;
401
402 if( !GetSelections( itemsToAlign, locked_items,
403 []( const std::pair<BOARD_ITEM*, BOX2I>& lhs, const std::pair<BOARD_ITEM*, BOX2I>& rhs )
404 {
405 return ( lhs.second.Centre().x < rhs.second.Centre().x );
406 } ) )
407 {
408 return 0;
409 }
410
411 BOARD_COMMIT commit( m_frame );
412
413 int targetX = selectTarget( itemsToAlign, locked_items,
414 []( const std::pair<BOARD_ITEM*, BOX2I>& aVal )
415 {
416 return aVal.second.Centre().x;
417 } );
418
419 // Move the selected items
420 for( const std::pair<BOARD_ITEM*, BOX2I>& i : itemsToAlign )
421 {
422 int difference = targetX - i.second.Centre().x;
423 BOARD_ITEM* item = i.first;
424
425 if( item->GetParent() && item->GetParent()->IsSelected() )
426 continue;
427
428 // Don't move a pad by itself unless editing the footprint
429 if( item->Type() == PCB_PAD_T && m_frame->IsType( FRAME_PCB_EDITOR ) )
430 item = item->GetParent();
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 std::pair<BOARD_ITEM*, BOX2I>& i : itemsToAlign )
465 {
466 int difference = targetY - i.second.Centre().y;
467 BOARD_ITEM* item = i.first;
468
469 if( item->GetParent() && item->GetParent()->IsSelected() )
470 continue;
471
472 // Don't move a pad by itself unless editing the footprint
473 if( item->Type() == PCB_PAD_T && m_frame->IsType( FRAME_PCB_EDITOR ) )
474 item = item->GetParent();
475
476 commit.Stage( item, CHT_MODIFY );
477 item->Move( VECTOR2I( 0, difference ) );
478 }
479
480 commit.Push( _( "Align to Center" ) );
481 return 0;
482}
483
484
486{
488 []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector,
489 PCB_SELECTION_TOOL* sTool )
490 {
491 sTool->FilterCollectorForMarkers( aCollector );
492 sTool->FilterCollectorForHierarchy( aCollector, true );
493 sTool->FilterCollectorForFreePads( aCollector );
494 },
495 m_frame->IsType( FRAME_PCB_EDITOR ) /* prompt user regarding locked items */
496 );
497
498 // Need at least 3 items to distribute - one at each end and at least on in the middle
499 if( selection.Size() < 3 )
500 return 0;
501
502 BOARD_COMMIT commit( m_frame );
503 wxString commitMsg;
504 std::vector<std::pair<BOARD_ITEM*, BOX2I>> itemsToDistribute = GetBoundingBoxes( selection );
505
507 {
508 doDistributeCenters( true, itemsToDistribute, commit );
510 }
512 {
513 doDistributeGaps( true, itemsToDistribute, commit );
515 }
517 {
518 doDistributeCenters( false, itemsToDistribute, commit );
520 }
521 else
522 {
523 doDistributeGaps( false, itemsToDistribute, commit );
525 }
526
527 commit.Push( commitMsg );
528 return 0;
529}
530
531
533 std::vector<std::pair<BOARD_ITEM*, BOX2I>>& aItems,
534 BOARD_COMMIT& aCommit ) const
535{
536 // Sort by start position.
537 // This is a simple way to get the items in a sensible order but it's not perfect.
538 // It will fail if, say, there's a huge items that's bigger than the total span of
539 // all the other items, but at that point a gap-equalising algorithm probably isn't
540 // well-defined anyway.
541 std::sort( aItems.begin(), aItems.end(),
542 [&]( const std::pair<BOARD_ITEM*, BOX2I>& a, const std::pair<BOARD_ITEM*, BOX2I>& b )
543 {
544 return aIsXAxis ? a.second.GetLeft() < b.second.GetLeft()
545 : a.second.GetTop() < b.second.GetTop();
546 } );
547
548 // Consruct list of item spans in the relevant axis
549 std::vector<std::pair<int, int>> itemSpans;
550 itemSpans.reserve( aItems.size() );
551
552 for( const auto& [item, box] : aItems )
553 {
554 const int start = aIsXAxis ? box.GetLeft() : box.GetTop();
555 const int end = aIsXAxis ? box.GetRight() : box.GetBottom();
556 itemSpans.emplace_back( start, end );
557 }
558
559 // Get the deltas needed to distribute the items evenly
560 const std::vector<int> deltas = GetDeltasForDistributeByGaps( itemSpans );
561
562 // Apply the deltas to the items
563 for( size_t i = 1; i < aItems.size() - 1; ++i )
564 {
565 const auto& [item, box] = aItems[i];
566 const int delta = deltas[i];
567
568 if( delta != 0 )
569 {
570 const VECTOR2I deltaVec = aIsXAxis ? VECTOR2I( delta, 0 ) : VECTOR2I( 0, delta );
571
572 aCommit.Stage( item, CHT_MODIFY );
573 item->Move( deltaVec );
574 }
575 }
576}
577
578
580 std::vector<std::pair<BOARD_ITEM*, BOX2I>>& aItems,
581 BOARD_COMMIT& aCommit ) const
582{
583 std::sort(
584 aItems.begin(), aItems.end(),
585 [&]( const std::pair<BOARD_ITEM*, BOX2I>& lhs, const std::pair<BOARD_ITEM*, BOX2I>& rhs )
586 {
587 const int lhsPos = aIsXAxis ? lhs.second.Centre().x : lhs.second.Centre().y;
588 const int rhsPos = aIsXAxis ? rhs.second.Centre().x : rhs.second.Centre().y;
589 return lhsPos < rhsPos;
590 } );
591
592 std::vector<int> itemCenters;
593 itemCenters.reserve( aItems.size() );
594
595 for( const auto& [item, box] : aItems )
596 {
597 itemCenters.push_back( aIsXAxis ? box.Centre().x : box.Centre().y );
598 }
599
600 const std::vector<int> deltas = GetDeltasForDistributeByPoints( itemCenters );
601
602 // Apply the deltas to the items
603 for( size_t i = 1; i < aItems.size() - 1; ++i )
604 {
605 const auto& [item, box] = aItems[i];
606 const int delta = deltas[i];
607
608 if ( delta != 0)
609 {
610 const VECTOR2I deltaVec = aIsXAxis ? VECTOR2I( delta, 0 ) : VECTOR2I( 0, delta );
611
612 aCommit.Stage( item, CHT_MODIFY );
613 item->Move( deltaVec );
614 }
615 }
616}
617
618
620{
627
636}
void SetTitle(const wxString &aTitle) override
Set title for the menu.
Definition: action_menu.cpp:92
void SetIcon(BITMAPS aIcon)
Assign an icon for the entry.
Definition: action_menu.cpp:78
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...
PCB_BASE_FRAME * m_frame
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.
virtual ~ALIGN_DISTRIBUTE_TOOL()
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
Revert the commit by restoring the modified items state.
COMMIT & Stage(EDA_ITEM *aItem, CHANGE_TYPE aChangeType, BASE_SCREEN *aScreen=nullptr) override
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:77
virtual void Move(const VECTOR2I &aMoveVector)
Move this object.
Definition: board_item.h:314
virtual bool IsLocked() const
Definition: board_item.cpp:74
BOARD_ITEM_CONTAINER * GetParent() const
Definition: board_item.h:204
int GetCount() const
Return the number of objects in the list.
Definition: collector.h:81
void AddItem(const TOOL_ACTION &aAction, const SELECTION_CONDITION &aCondition, int aOrder=ANY_ORDER)
Add a menu entry to run a TOOL_ACTION on selected items.
void AddSeparator(int aOrder=ANY_ORDER)
Add a separator to the menu.
void AddMenu(ACTION_MENU *aMenu, const SELECTION_CONDITION &aCondition=SELECTION_CONDITIONS::ShowAlways, int aOrder=ANY_ORDER)
Add a submenu to the menu.
bool IsType(FRAME_T aType) const
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:88
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
Definition: eda_item.cpp:74
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:100
bool IsSelected() const
Definition: eda_item.h:109
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: footprint.cpp:1223
Used when the right click button is pressed, or when the select tool is in effect.
Definition: collectors.h:206
VECTOR2D GetCursorPosition() const
Return the current cursor position in world coordinates.
static TOOL_ACTION alignTop
Definition: pcb_actions.h:306
static TOOL_ACTION distributeHorizontallyGaps
Definition: pcb_actions.h:313
static TOOL_ACTION distributeHorizontallyCenters
Definition: pcb_actions.h:312
static TOOL_ACTION alignRight
Definition: pcb_actions.h:309
static TOOL_ACTION alignBottom
Definition: pcb_actions.h:307
static TOOL_ACTION alignLeft
Definition: pcb_actions.h:308
static TOOL_ACTION alignCenterX
Definition: pcb_actions.h:310
static TOOL_ACTION distributeVerticallyGaps
Definition: pcb_actions.h:315
static TOOL_ACTION distributeVerticallyCenters
Definition: pcb_actions.h:314
static TOOL_ACTION alignCenterY
Definition: pcb_actions.h:311
The selection tool: currently supports:
void FilterCollectorForMarkers(GENERAL_COLLECTOR &aCollector) const
Drop any PCB_MARKERs from the collector.
PCB_SELECTION & RequestSelection(CLIENT_SELECTION_FILTER aClientFilter, bool aConfirmLockedItems=false)
Return the current selection, filtered according to aClientFilter.
void FilterCollectorForFreePads(GENERAL_COLLECTOR &aCollector, bool aForcePromotion=false) const
Check the "allow free pads" setting and if disabled, replace any pads in the collector with their par...
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.
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:116
TOOL_EVENT MakeEvent() const
Return the event associated with the action (i.e.
wxString GetFriendlyName() const
Return the translated user-friendly name of the action.
KIGFX::VIEW_CONTROLS * getViewControls() const
Return the instance of VIEW_CONTROLS object used in the application.
Definition: tool_base.cpp:42
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:217
KIGFX::VIEW * getView() const
Returns the instance of #VIEW object used in the application.
Definition: tool_base.cpp:36
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:384
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_MENU & GetToolMenu()
CONDITIONAL_MENU & GetMenu()
Definition: tool_menu.cpp:44
@ 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.
Definition: distribute.cpp:25
std::vector< int > GetDeltasForDistributeByPoints(const std::vector< int > &aItemPositions)
Definition: distribute.cpp:67
#define _(s)
@ FRAME_PCB_EDITOR
Definition: frame_type.h:42
std::vector< std::pair< BOARD_ITEM *, BOX2I > > GetBoundingBoxes(const T &aItems)
Class that computes missing connections on a PCB.
constexpr int delta
@ 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< int > VECTOR2I
Definition: vector2d.h:602