KiCad PCB EDA Suite
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  * @author Maciej Suminski <maciej.suminski@cern.ch>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 #include "tool/selection.h"
25 #include "placement_tool.h"
26 #include "pcb_actions.h"
27 #include "selection_tool.h"
28 #include "edit_tool.h"
29 
30 #include <ratsnest/ratsnest_data.h>
31 #include <tool/tool_manager.h>
32 
33 #include <pcb_edit_frame.h>
34 #include <class_board.h>
35 #include <board_commit.h>
36 #include <bitmaps.h>
37 
38 #include <confirm.h>
39 #include <menus_helpers.h>
40 
41 
43  TOOL_INTERACTIVE( "pcbnew.Placement" ), m_selectionTool( NULL ), m_placementMenu( NULL ),
44  m_frame( NULL )
45 {
46 }
47 
49 {
50  delete m_placementMenu;
51 }
52 
53 
55 {
56  // Find the selection tool, so they can cooperate
58 
59  wxASSERT_MSG( m_selectionTool, "pcbnew.InteractiveSelection tool is not available" );
60 
61  m_frame = getEditFrame<PCB_BASE_FRAME>();
62 
63  // Create a context menu and make it available through selection tool
64  m_placementMenu = new ACTION_MENU( true );
65  m_placementMenu->SetTool( this );
67  m_placementMenu->SetTitle( _( "Align/Distribute" ) );
68 
69  // Add all align/distribute commands
73 
74  m_placementMenu->AppendSeparator();
78 
79  m_placementMenu->AppendSeparator();
82 
85 
86  return true;
87 }
88 
89 
90 template <class T>
92 {
93  ALIGNMENT_RECTS rects;
94 
95  for( auto item : sel )
96  {
97  BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( item );
98 
99  if( item->Type() == PCB_MODULE_T )
100  rects.emplace_back( std::make_pair( boardItem, static_cast<MODULE*>( item )->GetFootprintRect() ) );
101  else
102  rects.emplace_back( std::make_pair( boardItem, item->GetBoundingBox() ) );
103  }
104 
105  return rects;
106 }
107 
108 
109 template< typename T >
111 {
112  wxPoint curPos( getViewControls()->GetCursorPosition().x, getViewControls()->GetCursorPosition().y );
113 
114  // after sorting, the fist item acts as the target for all others
115  // unless we have a locked item, in which case we use that for the target
116  int target = !aLocked.size() ? aGetValue( aItems.front() ): aGetValue( aLocked.front() );
117 
118  // We take the first target that overlaps our cursor.
119  // This is deterministic because we assume sorted arrays
120  for( auto item : aLocked )
121  {
122  if( item.second.Contains( curPos ) )
123  return aGetValue( item );
124  }
125 
126  // If there are locked items, prefer aligning to them over
127  // aligning to the cursor as they do not move
128  if( aLocked.empty() )
129  {
130  for( auto item : aItems )
131  {
132  if( item.second.Contains( curPos ) )
133  return aGetValue( item );
134  }
135  }
136 
137  return target;
138 }
139 
140 
141 template< typename T >
143 {
144 
146  []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, SELECTION_TOOL* sTool )
147  { EditToolSelectionFilter( aCollector, EXCLUDE_TRANSIENTS, sTool ); } );
148 
149  if( selection.Size() <= 1 )
150  return 0;
151 
152  std::vector<BOARD_ITEM*> lockedItems;
153  selection = m_selectionTool->RequestSelection(
154  []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, SELECTION_TOOL* sTool )
155  { EditToolSelectionFilter( aCollector, EXCLUDE_LOCKED, sTool ); }, &lockedItems );
156 
157  aItems = GetBoundingBoxes( selection );
158  aLocked = GetBoundingBoxes( lockedItems );
159  std::sort( aItems.begin(), aItems.end(), aCompare );
160  std::sort( aLocked.begin(), aLocked.end(), aCompare );
161 
162  return aItems.size();
163 }
164 
165 
167 {
168  ALIGNMENT_RECTS itemsToAlign;
169  ALIGNMENT_RECTS locked_items;
170 
171  if( !GetSelections( itemsToAlign, locked_items, []( const ALIGNMENT_RECT left, const ALIGNMENT_RECT right)
172  { return ( left.second.GetTop() < right.second.GetTop() ); } ) )
173  return 0;
174 
175  BOARD_COMMIT commit( m_frame );
177  auto targetTop = selectTarget( itemsToAlign, locked_items, []( const ALIGNMENT_RECT& aVal )
178  { return aVal.second.GetTop(); } );
179 
180  // Move the selected items
181  for( auto& i : itemsToAlign )
182  {
183  int difference = targetTop - i.second.GetTop();
184  BOARD_ITEM* item = i.first;
185 
186  // Don't move a pad by itself unless editing the footprint
187  if( item->Type() == PCB_PAD_T && m_frame->IsType( FRAME_PCB_EDITOR ) )
188  item = item->GetParent();
189 
190  item->Move( wxPoint( 0, difference ) );
191  }
192 
193  commit.Push( _( "Align to top" ) );
194 
195  return 0;
196 }
197 
198 
200 {
201  ALIGNMENT_RECTS itemsToAlign;
202  ALIGNMENT_RECTS locked_items;
203 
204  if( !GetSelections( itemsToAlign, locked_items, []( const ALIGNMENT_RECT left, const ALIGNMENT_RECT right)
205  { return ( left.second.GetBottom() < right.second.GetBottom() ); } ) )
206  return 0;
207 
208  BOARD_COMMIT commit( m_frame );
210  auto targetBottom = selectTarget( itemsToAlign, locked_items, []( const ALIGNMENT_RECT& aVal )
211  { return aVal.second.GetBottom(); } );
212 
213  // Move the selected items
214  for( auto& i : itemsToAlign )
215  {
216  int difference = targetBottom - i.second.GetBottom();
217  BOARD_ITEM* item = i.first;
218 
219  // Don't move a pad by itself unless editing the footprint
220  if( item->Type() == PCB_PAD_T && m_frame->IsType( FRAME_PCB_EDITOR ) )
221  item = item->GetParent();
222 
223  item->Move( wxPoint( 0, difference ) );
224  }
225 
226  commit.Push( _( "Align to bottom" ) );
227 
228  return 0;
229 }
230 
231 
233 {
234  // Because this tool uses bounding boxes and they aren't mirrored even when
235  // the view is mirrored, we need to call the other one if mirrored.
236  if( getView()->IsMirroredX() )
237  {
238  return doAlignRight();
239  }
240  else
241  {
242  return doAlignLeft();
243  }
244 }
245 
246 
248 {
249  ALIGNMENT_RECTS itemsToAlign;
250  ALIGNMENT_RECTS locked_items;
251 
252  if( !GetSelections( itemsToAlign, locked_items, []( const ALIGNMENT_RECT left, const ALIGNMENT_RECT right)
253  { return ( left.second.GetLeft() < right.second.GetLeft() ); } ) )
254  return 0;
255 
256  BOARD_COMMIT commit( m_frame );
258  auto targetLeft = selectTarget( itemsToAlign, locked_items, []( const ALIGNMENT_RECT& aVal )
259  { return aVal.second.GetLeft(); } );
260 
261  // Move the selected items
262  for( auto& i : itemsToAlign )
263  {
264  int difference = targetLeft - i.second.GetLeft();
265  BOARD_ITEM* item = i.first;
266 
267  // Don't move a pad by itself unless editing the footprint
268  if( item->Type() == PCB_PAD_T && m_frame->IsType( FRAME_PCB_EDITOR ) )
269  item = item->GetParent();
270 
271  item->Move( wxPoint( difference, 0 ) );
272  }
273 
274  commit.Push( _( "Align to left" ) );
275 
276  return 0;
277 }
278 
279 
281 {
282  // Because this tool uses bounding boxes and they aren't mirrored even when
283  // the view is mirrored, we need to call the other one if mirrored.
284  if( getView()->IsMirroredX() )
285  {
286  return doAlignLeft();
287  }
288  else
289  {
290  return doAlignRight();
291  }
292 }
293 
294 
296 {
297  ALIGNMENT_RECTS itemsToAlign;
298  ALIGNMENT_RECTS locked_items;
299 
300  if( !GetSelections( itemsToAlign, locked_items, []( const ALIGNMENT_RECT left, const ALIGNMENT_RECT right)
301  { return ( left.second.GetRight() < right.second.GetRight() ); } ) )
302  return 0;
303 
304  BOARD_COMMIT commit( m_frame );
306  auto targetRight = selectTarget( itemsToAlign, locked_items, []( const ALIGNMENT_RECT& aVal )
307  { return aVal.second.GetRight(); } );
308 
309  // Move the selected items
310  for( auto& i : itemsToAlign )
311  {
312  int difference = targetRight - i.second.GetRight();
313  BOARD_ITEM* item = i.first;
314 
315  // Don't move a pad by itself unless editing the footprint
316  if( item->Type() == PCB_PAD_T && m_frame->IsType( FRAME_PCB_EDITOR ) )
317  item = item->GetParent();
318 
319  item->Move( wxPoint( difference, 0 ) );
320  }
321 
322  commit.Push( _( "Align to right" ) );
323 
324  return 0;
325 }
326 
327 
329 {
330  ALIGNMENT_RECTS itemsToAlign;
331  ALIGNMENT_RECTS locked_items;
332 
333  if( !GetSelections( itemsToAlign, locked_items, []( const ALIGNMENT_RECT left, const ALIGNMENT_RECT right)
334  { return ( left.second.GetCenter().x < right.second.GetCenter().x ); } ) )
335  return 0;
336 
337  BOARD_COMMIT commit( m_frame );
339  auto targetX = selectTarget( itemsToAlign, locked_items, []( const ALIGNMENT_RECT& aVal )
340  { return aVal.second.GetCenter().x; } );
341 
342  // Move the selected items
343  for( auto& i : itemsToAlign )
344  {
345  int difference = targetX - i.second.GetCenter().x;
346  BOARD_ITEM* item = i.first;
347 
348  // Don't move a pad by itself unless editing the footprint
349  if( item->Type() == PCB_PAD_T && m_frame->IsType( FRAME_PCB_EDITOR ) )
350  item = item->GetParent();
351 
352  item->Move( wxPoint( difference, 0 ) );
353  }
354 
355  commit.Push( _( "Align to middle" ) );
356 
357  return 0;
358 }
359 
360 
362 {
363  ALIGNMENT_RECTS itemsToAlign;
364  ALIGNMENT_RECTS locked_items;
365 
366  if( !GetSelections( itemsToAlign, locked_items, []( const ALIGNMENT_RECT left, const ALIGNMENT_RECT right)
367  { return ( left.second.GetCenter().y < right.second.GetCenter().y ); } ) )
368  return 0;
369 
370  BOARD_COMMIT commit( m_frame );
372  auto targetY = selectTarget( itemsToAlign, locked_items, []( const ALIGNMENT_RECT& aVal )
373  { return aVal.second.GetCenter().y; } );
374 
375  // Move the selected items
376  for( auto& i : itemsToAlign )
377  {
378  int difference = targetY - i.second.GetCenter().y;
379  BOARD_ITEM* item = i.first;
380 
381  // Don't move a pad by itself unless editing the footprint
382  if( item->Type() == PCB_PAD_T && m_frame->IsType( FRAME_PCB_EDITOR ) )
383  item = item->GetParent();
384 
385  item->Move( wxPoint( 0, difference ) );
386  }
387 
388  commit.Push( _( "Align to center" ) );
389 
390  return 0;
391 }
392 
393 
395 {
397  []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, SELECTION_TOOL* sTool )
398  { EditToolSelectionFilter( aCollector, EXCLUDE_LOCKED | EXCLUDE_TRANSIENTS, sTool ); } );
399 
400  if( selection.Size() <= 1 )
401  return 0;
402 
403  BOARD_COMMIT commit( m_frame );
404  commit.StageItems( selection, CHT_MODIFY );
405 
406  auto itemsToDistribute = GetBoundingBoxes( selection );
407 
408  // find the last item by reverse sorting
409  std::sort( itemsToDistribute.begin(), itemsToDistribute.end(),
410  [] ( const ALIGNMENT_RECT left, const ALIGNMENT_RECT right)
411  { return ( left.second.GetRight() > right.second.GetRight() ); } );
412  const auto lastItem = itemsToDistribute.begin()->first;
413 
414  const auto maxRight = itemsToDistribute.begin()->second.GetRight();
415 
416  // sort to get starting order
417  std::sort( itemsToDistribute.begin(), itemsToDistribute.end(),
418  [] ( const ALIGNMENT_RECT left, const ALIGNMENT_RECT right)
419  { return ( left.second.GetX() < right.second.GetX() ); } );
420  const auto minX = itemsToDistribute.begin()->second.GetX();
421  auto totalGap = maxRight - minX;
422  int totalWidth = 0;
423 
424  for( auto& i : itemsToDistribute )
425  {
426  totalWidth += i.second.GetWidth();
427  }
428 
429  if( totalGap < totalWidth )
430  {
431  // the width of the items exceeds the gap (overlapping items) -> use center point spacing
432  doDistributeCentersHorizontally( itemsToDistribute );
433  }
434  else
435  {
436  totalGap -= totalWidth;
437  doDistributeGapsHorizontally( itemsToDistribute, lastItem, totalGap );
438  }
439 
440  commit.Push( _( "Distribute horizontally" ) );
441 
442  return 0;
443 }
444 
445 
447  const BOARD_ITEM* lastItem, int totalGap ) const
448 {
449  const auto itemGap = totalGap / ( itemsToDistribute.size() - 1 );
450  auto targetX = itemsToDistribute.begin()->second.GetX();
451 
452  for( auto& i : itemsToDistribute )
453  {
454  BOARD_ITEM* item = i.first;
455 
456  // cover the corner case where the last item is wider than the previous item and gap
457  if( lastItem == item )
458  continue;
459 
460  // Don't move a pad by itself unless editing the footprint
461  if( item->Type() == PCB_PAD_T && m_frame->IsType( FRAME_PCB_EDITOR ) )
462  item = item->GetParent();
463 
464  int difference = targetX - i.second.GetX();
465  item->Move( wxPoint( difference, 0 ) );
466  targetX += ( i.second.GetWidth() + itemGap );
467  }
468 }
469 
470 
472 {
473  std::sort( itemsToDistribute.begin(), itemsToDistribute.end(),
474  [] ( const ALIGNMENT_RECT left, const ALIGNMENT_RECT right)
475  { return ( left.second.GetCenter().x < right.second.GetCenter().x ); } );
476  const auto totalGap = ( itemsToDistribute.end()-1 )->second.GetCenter().x
477  - itemsToDistribute.begin()->second.GetCenter().x;
478  const auto itemGap = totalGap / ( itemsToDistribute.size() - 1 );
479  auto targetX = itemsToDistribute.begin()->second.GetCenter().x;
480 
481  for( auto& i : itemsToDistribute )
482  {
483  BOARD_ITEM* item = i.first;
484 
485  // Don't move a pad by itself unless editing the footprint
486  if( item->Type() == PCB_PAD_T && m_frame->IsType( FRAME_PCB_EDITOR ) )
487  item = item->GetParent();
488 
489  int difference = targetX - i.second.GetCenter().x;
490  item->Move( wxPoint( difference, 0 ) );
491  targetX += ( itemGap );
492  }
493 }
494 
495 
497 {
499  []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, SELECTION_TOOL* sTool )
500  { EditToolSelectionFilter( aCollector, EXCLUDE_LOCKED | EXCLUDE_TRANSIENTS, sTool ); } );
501 
502  if( selection.Size() <= 1 )
503  return 0;
504 
505  BOARD_COMMIT commit( m_frame );
506  commit.StageItems( selection, CHT_MODIFY );
507 
508  auto itemsToDistribute = GetBoundingBoxes( selection );
509 
510  // find the last item by reverse sorting
511  std::sort( itemsToDistribute.begin(), itemsToDistribute.end(),
512  [] ( const ALIGNMENT_RECT left, const ALIGNMENT_RECT right)
513  { return ( left.second.GetBottom() > right.second.GetBottom() ); } );
514  const auto maxBottom = itemsToDistribute.begin()->second.GetBottom();
515  const auto lastItem = itemsToDistribute.begin()->first;
516 
517  // sort to get starting order
518  std::sort( itemsToDistribute.begin(), itemsToDistribute.end(),
519  [] ( const ALIGNMENT_RECT left, const ALIGNMENT_RECT right)
520  { return ( left.second.GetCenter().y < right.second.GetCenter().y ); } );
521  auto minY = itemsToDistribute.begin()->second.GetY();
522 
523  auto totalGap = maxBottom - minY;
524  int totalHeight = 0;
525 
526  for( auto& i : itemsToDistribute )
527  {
528  totalHeight += i.second.GetHeight();
529  }
530 
531  if( totalGap < totalHeight )
532  {
533  // the width of the items exceeds the gap (overlapping items) -> use center point spacing
534  doDistributeCentersVertically( itemsToDistribute );
535  }
536  else
537  {
538  totalGap -= totalHeight;
539  doDistributeGapsVertically( itemsToDistribute, lastItem, totalGap );
540  }
541 
542  commit.Push( _( "Distribute vertically" ) );
543 
544  return 0;
545 }
546 
547 
549  const BOARD_ITEM* lastItem, int totalGap ) const
550 {
551  const auto itemGap = totalGap / ( itemsToDistribute.size() - 1 );
552  auto targetY = itemsToDistribute.begin()->second.GetY();
553 
554  for( auto& i : itemsToDistribute )
555  {
556  BOARD_ITEM* item = i.first;
557 
558  // cover the corner case where the last item is wider than the previous item and gap
559  if( lastItem == item )
560  continue;
561 
562  // Don't move a pad by itself unless editing the footprint
563  if( item->Type() == PCB_PAD_T && m_frame->IsType( FRAME_PCB_EDITOR ) )
564  item = item->GetParent();
565 
566  int difference = targetY - i.second.GetY();
567  i.first->Move( wxPoint( 0, difference ) );
568  targetY += ( i.second.GetHeight() + itemGap );
569  }
570 }
571 
572 
574 {
575  std::sort( itemsToDistribute.begin(), itemsToDistribute.end(),
576  [] ( const ALIGNMENT_RECT left, const ALIGNMENT_RECT right)
577  { return ( left.second.GetCenter().y < right.second.GetCenter().y ); } );
578  const auto totalGap = ( itemsToDistribute.end()-1 )->second.GetCenter().y
579  - itemsToDistribute.begin()->second.GetCenter().y;
580  const auto itemGap = totalGap / ( itemsToDistribute.size() - 1 );
581  auto targetY = itemsToDistribute.begin()->second.GetCenter().y;
582 
583  for( auto& i : itemsToDistribute )
584  {
585  BOARD_ITEM* item = i.first;
586 
587  // Don't move a pad by itself unless editing the footprint
588  if( item->Type() == PCB_PAD_T && m_frame->IsType( FRAME_PCB_EDITOR ) )
589  item = item->GetParent();
590 
591  int difference = targetY - i.second.GetCenter().y;
592  item->Move( wxPoint( 0, difference ) );
593  targetY += ( itemGap );
594  }
595 }
596 
597 
599 {
606 
609 }
static TOOL_ACTION alignRight
Definition: pcb_actions.h:211
void AddMenu(ACTION_MENU *aMenu, const SELECTION_CONDITION &aCondition=SELECTION_CONDITIONS::ShowAlways, int aOrder=ANY_ORDER)
Adds a submenu to the menu.
int AlignLeft(const TOOL_EVENT &aEvent)
Function AlignLeft() Sets X coordinate of the selected items to the value of the left-most selected i...
wxMenuItem * Add(const wxString &aLabel, int aId, const BITMAP_OPAQUE *aIcon)
Adds a wxWidgets-style entry to the menu.
void doDistributeGapsHorizontally(ALIGNMENT_RECTS &itemsToDistribute, const BOARD_ITEM *lastItem, int totalGap) const
Distributes selected items using an even spacing between their bounding boxes.
int selectTarget(ALIGNMENT_RECTS &aItems, ALIGNMENT_RECTS &aLocked, T aGetValue)
int AlignCenterY(const TOOL_EVENT &aEvent)
Function AlignCenterX() Sets the y coordinate of the midpoint of each of the selected items to the va...
void EditToolSelectionFilter(GENERAL_COLLECTOR &aCollector, int aFlags, SELECTION_TOOL *selectionTool)
Definition: edit_tool.cpp:63
Defines the structure of a menu based on ACTIONs.
Definition: action_menu.h:43
This file is part of the common library.
BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class,...
int AlignCenterX(const TOOL_EVENT &aEvent)
Function AlignCenterX() Sets the x coordinate of the midpoint of each of the selected items to the va...
static SELECTION_CONDITION MoreThan(int aNumber)
Creates a functor that tests if the number of selected items is greater than the value given as param...
virtual ~ALIGN_DISTRIBUTE_TOOL()
ACTION_MENU * m_placementMenu
SELECTION_TOOL.
void doDistributeCentersVertically(ALIGNMENT_RECTS &itemsToDistribute) const
Distributes selected items using an even spacing between the centers of their bounding boxes.
Class that computes missing connections on a PCB.
CONDITIONAL_MENU & GetMenu()
Function GetMenu.
Definition: tool_menu.cpp:46
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:219
static TOOL_ACTION alignCenterY
Definition: pcb_actions.h:213
TOOL_MENU & GetToolMenu()
int AlignBottom(const TOOL_EVENT &aEvent)
Function AlignBottom() Sets Y coordinate of the selected items to the value of the bottom-most select...
class D_PAD, a pad in a footprint
Definition: typeinfo.h:90
static TOOL_ACTION distributeVertically
Definition: pcb_actions.h:215
void Go(int(T::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
Function Go()
ALIGNMENT_RECTS GetBoundingBoxes(const T &sel)
static TOOL_ACTION alignBottom
Definition: pcb_actions.h:209
void SetTool(TOOL_INTERACTIVE *aTool)
Sets a tool that is the creator of the menu.
PCBNEW_SELECTION & GetSelection()
Function GetSelection()
static TOOL_ACTION distributeHorizontally
Definition: pcb_actions.h:214
int DistributeHorizontally(const TOOL_EVENT &aEvent)
Function DistributeHorizontally() Distributes the selected items along the X axis.
class MODULE, a footprint
Definition: typeinfo.h:89
int doAlignRight()
Aligns selected items using the right edge of their bounding boxes to the right-most item.
int doAlignLeft()
Sets X coordinate of the selected items to the value of the left-most selected item X coordinate.
int GetY() const
#define NULL
std::vector< ALIGNMENT_RECT > ALIGNMENT_RECTS
virtual void Move(const wxPoint &aMoveVector)
Function Move move this object.
const BITMAP_OPAQUE align_items_xpm[1]
Definition: align_items.cpp:21
int AlignTop(const TOOL_EVENT &aEvent)
Function AlignTop() Sets Y coordinate of the selected items to the value of the top-most selected ite...
void SetIcon(const BITMAP_OPAQUE *aIcon)
Assigns an icon for the entry.
Definition: action_menu.cpp:71
TOOL_EVENT.
Definition: tool_event.h:171
int DistributeVertically(const TOOL_EVENT &aEvent)
Function DistributeVertically() Distributes the selected items along the Y axis.
COMMIT & StageItems(const Range &aRange, CHANGE_TYPE aChangeType)
Definition: commit.h:116
static TOOL_ACTION alignLeft
Definition: pcb_actions.h:210
void doDistributeCentersHorizontally(ALIGNMENT_RECTS &itemsToDistribute) const
Distributes selected items using an even spacing between the centers of their bounding boxes.
virtual wxPoint GetCenter() const
Function GetCenter()
static TOOL_ACTION alignTop
Definition: pcb_actions.h:208
KIGFX::VIEW * getView() const
Function getView()
Definition: tool_base.cpp:36
#define EXCLUDE_TRANSIENTS
Definition: edit_tool.h:55
size_t GetSelections(ALIGNMENT_RECTS &aItems, ALIGNMENT_RECTS &aLocked, T aCompare)
Function GetSelections() Populates two vectors with the sorted selection and sorted locked items Retu...
void SetTitle(const wxString &aTitle) override
Sets title for the menu.
Definition: action_menu.cpp:89
int GetX() const
PCBNEW_SELECTION & RequestSelection(CLIENT_SELECTION_FILTER aClientFilter, std::vector< BOARD_ITEM * > *aFiltered=nullptr, bool aConfirmLockedItems=false)
Function RequestSelection()
PCB_BASE_FRAME * m_frame
bool IsType(FRAME_T aType) const
#define _(s)
Definition: 3d_actions.cpp:33
std::pair< BOARD_ITEM *, EDA_RECT > ALIGNMENT_RECT
Used when the right click button is pressed, or when the select tool is in effect.
Definition: collectors.h:240
void setTransitions() override
Sets up handlers for various events.
int Size() const
Returns the number of selected parts.
Definition: selection.h:127
void doDistributeGapsVertically(ALIGNMENT_RECTS &itemsToDistribute, const BOARD_ITEM *lastItem, int totalGap) const
Distributes selected items using an even spacing between their bounding boxes.
virtual void Push(const wxString &aMessage=wxT("A commit"), bool aCreateUndoEntry=true, bool aSetDirtyBit=true) override
Executes the changes.
SELECTION_TOOL * m_selectionTool
int AlignRight(const TOOL_EVENT &aEvent)
Function AlignRight() Sets X coordinate of the selected items to the value of the right-most selected...
#define EXCLUDE_LOCKED
Function EditToolSelectionFilter.
Definition: edit_tool.h:53
virtual const EDA_RECT GetBoundingBox() const
Function GetBoundingBox returns the orthogonal, bounding box of this object for display purposes.
Definition: base_struct.cpp:97
KIGFX::VIEW_CONTROLS * getViewControls() const
Function getViewControls()
Definition: tool_base.cpp:42
bool Init() override
Function Init() Init() is called once upon a registration of the tool.
BOARD_ITEM_CONTAINER * GetParent() const
static TOOL_ACTION alignCenterX
Definition: pcb_actions.h:212
KICAD_T Type() const
Function Type()
Definition: base_struct.h:193