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 "pcb_selection_tool.h"
28 
29 #include <ratsnest/ratsnest_data.h>
30 #include <tool/tool_manager.h>
31 
32 #include <pcb_edit_frame.h>
33 #include <board.h>
34 #include <board_commit.h>
35 #include <bitmaps.h>
36 
37 #include <confirm.h>
38 #include <menus_helpers.h>
39 
40 
42  TOOL_INTERACTIVE( "pcbnew.Placement" ), m_selectionTool( NULL ), m_placementMenu( NULL ),
43  m_frame( NULL )
44 {
45 }
46 
48 {
49  delete m_placementMenu;
50 }
51 
52 
54 {
55  // Find the selection tool, so they can cooperate
57  m_frame = getEditFrame<PCB_BASE_FRAME>();
58 
59  // Create a context menu and make it available through selection tool
60  m_placementMenu = new ACTION_MENU( true, this );
62  m_placementMenu->SetTitle( _( "Align/Distribute" ) );
63 
64  // Add all align/distribute commands
68 
69  m_placementMenu->AppendSeparator();
73 
74  m_placementMenu->AppendSeparator();
77 
80 
81  return true;
82 }
83 
84 
85 template <class T>
87 {
88  ALIGNMENT_RECTS rects;
89 
90  for( EDA_ITEM* item : aItems )
91  {
92  BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( item );
93 
94  if( item->Type() == PCB_FOOTPRINT_T )
95  {
96  FOOTPRINT* footprint = static_cast<FOOTPRINT*>( item );
97  rects.emplace_back( std::make_pair( boardItem,
98  footprint->GetBoundingBox( false, false ) ) );
99  }
100  else
101  {
102  rects.emplace_back( std::make_pair( boardItem, item->GetBoundingBox() ) );
103  }
104  }
105 
106  return rects;
107 }
108 
109 
110 template< typename T >
112  T aGetValue )
113 {
114  wxPoint curPos = (wxPoint) getViewControls()->GetCursorPosition();
115 
116  // Prefer locked items to unlocked items.
117  // Secondly, prefer items under the cursor to other items.
118 
119  if( aLocked.size() >= 1 )
120  {
121  for( const ALIGNMENT_RECT& item : aLocked )
122  {
123  if( item.second.Contains( curPos ) )
124  return aGetValue( item );
125  }
126 
127  return aGetValue( aLocked.front() );
128  }
129 
130  for( const ALIGNMENT_RECT& item : aItems )
131  {
132  if( item.second.Contains( curPos ) )
133  return aGetValue( item );
134  }
135 
136  return aGetValue( aItems.front() );
137 }
138 
139 
140 template< typename T >
142  ALIGNMENT_RECTS& aLockedItems, T aCompare )
143 {
145  []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
146  {
147  // Iterate from the back so we don't have to worry about removals.
148  for( int i = aCollector.GetCount() - 1; i >= 0; --i )
149  {
150  BOARD_ITEM* item = aCollector[i];
151 
152  if( item->Type() == PCB_MARKER_T )
153  aCollector.Remove( item );
154  }
155  } );
156 
157  std::vector<BOARD_ITEM*> lockedItems;
158  std::vector<BOARD_ITEM*> itemsToAlign;
159 
160  for( EDA_ITEM* item : selection )
161  {
162  BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( item );
163 
164  if( boardItem->IsLocked() )
165  {
166  // Locking a pad but not the footprint means that we align the footprint using
167  // the pad position. So we test for footprint locking here
168  if( m_frame->IsType( FRAME_PCB_EDITOR ) && boardItem->Type() == PCB_PAD_T
169  && !boardItem->GetParent()->IsLocked() )
170  {
171  itemsToAlign.push_back( boardItem );
172  }
173  else
174  {
175  lockedItems.push_back( boardItem );
176  }
177  }
178  else
179  itemsToAlign.push_back( boardItem );
180  }
181 
182  aItemsToAlign = GetBoundingBoxes( itemsToAlign );
183  aLockedItems = GetBoundingBoxes( lockedItems );
184  std::sort( aItemsToAlign.begin(), aItemsToAlign.end(), aCompare );
185  std::sort( aLockedItems.begin(), aLockedItems.end(), aCompare );
186 
187  return aItemsToAlign.size();
188 }
189 
190 
192 {
193  ALIGNMENT_RECTS itemsToAlign;
194  ALIGNMENT_RECTS locked_items;
195 
196  if( !GetSelections( itemsToAlign, locked_items,
197  []( const ALIGNMENT_RECT left, const ALIGNMENT_RECT right)
198  {
199  return ( left.second.GetTop() < right.second.GetTop() );
200  } ) )
201  {
202  return 0;
203  }
204 
205  BOARD_COMMIT commit( m_frame );
206 
207  int targetTop = selectTarget( itemsToAlign, locked_items,
208  []( const ALIGNMENT_RECT& aVal )
209  {
210  return aVal.second.GetTop();
211  } );
212 
213  // Move the selected items
214  for( std::pair<BOARD_ITEM*, EDA_RECT>& i : itemsToAlign )
215  {
216  BOARD_ITEM* item = i.first;
217  int difference = targetTop - i.second.GetTop();
218 
219  if( item->GetParent() && item->GetParent()->IsSelected() )
220  continue;
221 
222  // Don't move a pad by itself unless editing the footprint
223  if( item->Type() == PCB_PAD_T && m_frame->IsType( FRAME_PCB_EDITOR ) )
224  item = item->GetParent();
225 
226  commit.Stage( item, CHT_MODIFY );
227  item->Move( wxPoint( 0, difference ) );
228  }
229 
230  commit.Push( _( "Align to top" ) );
231 
232  return 0;
233 }
234 
235 
237 {
238  ALIGNMENT_RECTS itemsToAlign;
239  ALIGNMENT_RECTS locked_items;
240 
241  if( !GetSelections( itemsToAlign, locked_items,
242  []( const ALIGNMENT_RECT left, const ALIGNMENT_RECT right)
243  {
244  return ( left.second.GetBottom() < right.second.GetBottom() );
245  } ) )
246  {
247  return 0;
248  }
249 
250  BOARD_COMMIT commit( m_frame );
251 
252  int targetBottom = selectTarget( itemsToAlign, locked_items,
253  []( const ALIGNMENT_RECT& aVal )
254  {
255  return aVal.second.GetBottom();
256  } );
257 
258  // Move the selected items
259  for( std::pair<BOARD_ITEM*, EDA_RECT>& i : itemsToAlign )
260  {
261  int difference = targetBottom - i.second.GetBottom();
262  BOARD_ITEM* item = i.first;
263 
264  if( item->GetParent() && item->GetParent()->IsSelected() )
265  continue;
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  commit.Stage( item, CHT_MODIFY );
272  item->Move( wxPoint( 0, difference ) );
273  }
274 
275  commit.Push( _( "Align to bottom" ) );
276 
277  return 0;
278 }
279 
280 
282 {
283  // Because this tool uses bounding boxes and they aren't mirrored even when
284  // the view is mirrored, we need to call the other one if mirrored.
285  if( getView()->IsMirroredX() )
286  {
287  return doAlignRight();
288  }
289  else
290  {
291  return doAlignLeft();
292  }
293 }
294 
295 
297 {
298  ALIGNMENT_RECTS itemsToAlign;
299  ALIGNMENT_RECTS locked_items;
300 
301  if( !GetSelections( itemsToAlign, locked_items,
302  []( const ALIGNMENT_RECT left, const ALIGNMENT_RECT right)
303  {
304  return ( left.second.GetLeft() < right.second.GetLeft() );
305  } ) )
306  {
307  return 0;
308  }
309 
310  BOARD_COMMIT commit( m_frame );
311 
312  int targetLeft = selectTarget( itemsToAlign, locked_items,
313  []( const ALIGNMENT_RECT& aVal )
314  {
315  return aVal.second.GetLeft();
316  } );
317 
318  // Move the selected items
319  for( std::pair<BOARD_ITEM*, EDA_RECT>& i : itemsToAlign )
320  {
321  int difference = targetLeft - i.second.GetLeft();
322  BOARD_ITEM* item = i.first;
323 
324  if( item->GetParent() && item->GetParent()->IsSelected() )
325  continue;
326 
327  // Don't move a pad by itself unless editing the footprint
328  if( item->Type() == PCB_PAD_T && m_frame->IsType( FRAME_PCB_EDITOR ) )
329  item = item->GetParent();
330 
331  commit.Stage( item, CHT_MODIFY );
332  item->Move( wxPoint( difference, 0 ) );
333  }
334 
335  commit.Push( _( "Align to left" ) );
336 
337  return 0;
338 }
339 
340 
342 {
343  // Because this tool uses bounding boxes and they aren't mirrored even when
344  // the view is mirrored, we need to call the other one if mirrored.
345  if( getView()->IsMirroredX() )
346  {
347  return doAlignLeft();
348  }
349  else
350  {
351  return doAlignRight();
352  }
353 }
354 
355 
357 {
358  ALIGNMENT_RECTS itemsToAlign;
359  ALIGNMENT_RECTS locked_items;
360 
361  if( !GetSelections( itemsToAlign, locked_items,
362  []( const ALIGNMENT_RECT left, const ALIGNMENT_RECT right)
363  {
364  return ( left.second.GetRight() < right.second.GetRight() );
365  } ) )
366  {
367  return 0;
368  }
369 
370  BOARD_COMMIT commit( m_frame );
371 
372  int targetRight = selectTarget( itemsToAlign, locked_items,
373  []( const ALIGNMENT_RECT& aVal )
374  {
375  return aVal.second.GetRight();
376  } );
377 
378  // Move the selected items
379  for( std::pair<BOARD_ITEM*, EDA_RECT>& i : itemsToAlign )
380  {
381  int difference = targetRight - i.second.GetRight();
382  BOARD_ITEM* item = i.first;
383 
384  if( item->GetParent() && item->GetParent()->IsSelected() )
385  continue;
386 
387  // Don't move a pad by itself unless editing the footprint
388  if( item->Type() == PCB_PAD_T && m_frame->IsType( FRAME_PCB_EDITOR ) )
389  item = item->GetParent();
390 
391  commit.Stage( item, CHT_MODIFY );
392  item->Move( wxPoint( difference, 0 ) );
393  }
394 
395  commit.Push( _( "Align to right" ) );
396 
397  return 0;
398 }
399 
400 
402 {
403  ALIGNMENT_RECTS itemsToAlign;
404  ALIGNMENT_RECTS locked_items;
405 
406  if( !GetSelections( itemsToAlign, locked_items,
407  []( const ALIGNMENT_RECT left, const ALIGNMENT_RECT right)
408  {
409  return ( left.second.GetCenter().x < right.second.GetCenter().x );
410  } ) )
411  {
412  return 0;
413  }
414 
415  BOARD_COMMIT commit( m_frame );
416 
417  int targetX = selectTarget( itemsToAlign, locked_items,
418  []( const ALIGNMENT_RECT& aVal )
419  {
420  return aVal.second.GetCenter().x;
421  } );
422 
423  // Move the selected items
424  for( std::pair<BOARD_ITEM*, EDA_RECT>& i : itemsToAlign )
425  {
426  int difference = targetX - i.second.GetCenter().x;
427  BOARD_ITEM* item = i.first;
428 
429  if( item->GetParent() && item->GetParent()->IsSelected() )
430  continue;
431 
432  // Don't move a pad by itself unless editing the footprint
433  if( item->Type() == PCB_PAD_T && m_frame->IsType( FRAME_PCB_EDITOR ) )
434  item = item->GetParent();
435 
436  commit.Stage( item, CHT_MODIFY );
437  item->Move( wxPoint( difference, 0 ) );
438  }
439 
440  commit.Push( _( "Align to middle" ) );
441 
442  return 0;
443 }
444 
445 
447 {
448  ALIGNMENT_RECTS itemsToAlign;
449  ALIGNMENT_RECTS locked_items;
450 
451  if( !GetSelections( itemsToAlign, locked_items,
452  []( const ALIGNMENT_RECT left, const ALIGNMENT_RECT right)
453  {
454  return ( left.second.GetCenter().y < right.second.GetCenter().y );
455  } ) )
456  {
457  return 0;
458  }
459 
460  BOARD_COMMIT commit( m_frame );
461 
462  int targetY = selectTarget( itemsToAlign, locked_items,
463  []( const ALIGNMENT_RECT& aVal )
464  {
465  return aVal.second.GetCenter().y;
466  } );
467 
468  // Move the selected items
469  for( std::pair<BOARD_ITEM*, EDA_RECT>& i : itemsToAlign )
470  {
471  int difference = targetY - i.second.GetCenter().y;
472  BOARD_ITEM* item = i.first;
473 
474  if( item->GetParent() && item->GetParent()->IsSelected() )
475  continue;
476 
477  // Don't move a pad by itself unless editing the footprint
478  if( item->Type() == PCB_PAD_T && m_frame->IsType( FRAME_PCB_EDITOR ) )
479  item = item->GetParent();
480 
481  commit.Stage( item, CHT_MODIFY );
482  item->Move( wxPoint( 0, difference ) );
483  }
484 
485  commit.Push( _( "Align to center" ) );
486 
487  return 0;
488 }
489 
490 
492 {
494  []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
495  {
496  // Iterate from the back so we don't have to worry about removals.
497  for( int i = aCollector.GetCount() - 1; i >= 0; --i )
498  {
499  BOARD_ITEM* item = aCollector[i];
500 
501  if( item->Type() == PCB_MARKER_T )
502  aCollector.Remove( item );
503  }
504  },
505  m_frame->IsType( FRAME_PCB_EDITOR ) /* prompt user regarding locked items */ );
506 
507  if( selection.Size() <= 1 )
508  return 0;
509 
510  BOARD_COMMIT commit( m_frame );
511  ALIGNMENT_RECTS itemsToDistribute = GetBoundingBoxes( selection );
512 
513  // find the last item by reverse sorting
514  std::sort( itemsToDistribute.begin(), itemsToDistribute.end(),
515  [] ( const ALIGNMENT_RECT left, const ALIGNMENT_RECT right)
516  {
517  return ( left.second.GetRight() > right.second.GetRight() );
518  } );
519 
520  BOARD_ITEM* lastItem = itemsToDistribute.begin()->first;
521  const int maxRight = itemsToDistribute.begin()->second.GetRight();
522 
523  // sort to get starting order
524  std::sort( itemsToDistribute.begin(), itemsToDistribute.end(),
525  [] ( const ALIGNMENT_RECT left, const ALIGNMENT_RECT right)
526  {
527  return ( left.second.GetX() < right.second.GetX() );
528  } );
529 
530  const int minX = itemsToDistribute.begin()->second.GetX();
531  int totalGap = maxRight - minX;
532  int totalWidth = 0;
533 
534  for( std::pair<BOARD_ITEM*, EDA_RECT>& i : itemsToDistribute )
535  totalWidth += i.second.GetWidth();
536 
537  if( totalGap < totalWidth )
538  {
539  // the width of the items exceeds the gap (overlapping items) -> use center point spacing
540  doDistributeCentersHorizontally( itemsToDistribute, commit );
541  }
542  else
543  {
544  totalGap -= totalWidth;
545  doDistributeGapsHorizontally( itemsToDistribute, commit, lastItem, totalGap );
546  }
547 
548  commit.Push( _( "Distribute horizontally" ) );
549 
550  return 0;
551 }
552 
553 
555  BOARD_COMMIT& aCommit,
556  const BOARD_ITEM* lastItem,
557  int totalGap ) const
558 {
559  const int itemGap = totalGap / ( itemsToDistribute.size() - 1 );
560  int targetX = itemsToDistribute.begin()->second.GetX();
561 
562  for( std::pair<BOARD_ITEM*, EDA_RECT>& i : itemsToDistribute )
563  {
564  BOARD_ITEM* item = i.first;
565 
566  // cover the corner case where the last item is wider than the previous item and gap
567  if( lastItem == item )
568  continue;
569 
570  if( item->GetParent() && item->GetParent()->IsSelected() )
571  continue;
572 
573  // Don't move a pad by itself unless editing the footprint
574  if( item->Type() == PCB_PAD_T && m_frame->IsType( FRAME_PCB_EDITOR ) )
575  item = item->GetParent();
576 
577  int difference = targetX - i.second.GetX();
578  aCommit.Stage( item, CHT_MODIFY );
579  item->Move( wxPoint( difference, 0 ) );
580  targetX += ( i.second.GetWidth() + itemGap );
581  }
582 }
583 
584 
586  BOARD_COMMIT& aCommit ) const
587 {
588  std::sort( itemsToDistribute.begin(), itemsToDistribute.end(),
589  [] ( const ALIGNMENT_RECT left, const ALIGNMENT_RECT right)
590  {
591  return ( left.second.GetCenter().x < right.second.GetCenter().x );
592  } );
593 
594  const int totalGap = ( itemsToDistribute.end()-1 )->second.GetCenter().x
595  - itemsToDistribute.begin()->second.GetCenter().x;
596  const int itemGap = totalGap / ( itemsToDistribute.size() - 1 );
597  int targetX = itemsToDistribute.begin()->second.GetCenter().x;
598 
599  for( std::pair<BOARD_ITEM*, EDA_RECT>& i : itemsToDistribute )
600  {
601  BOARD_ITEM* item = i.first;
602 
603  if( item->GetParent() && item->GetParent()->IsSelected() )
604  continue;
605 
606  // Don't move a pad by itself unless editing the footprint
607  if( item->Type() == PCB_PAD_T && m_frame->IsType( FRAME_PCB_EDITOR ) )
608  item = item->GetParent();
609 
610  int difference = targetX - i.second.GetCenter().x;
611  aCommit.Stage( item, CHT_MODIFY );
612  item->Move( wxPoint( difference, 0 ) );
613  targetX += ( itemGap );
614  }
615 }
616 
617 
619 {
621  []( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
622  {
623  // Iterate from the back so we don't have to worry about removals.
624  for( int i = aCollector.GetCount() - 1; i >= 0; --i )
625  {
626  BOARD_ITEM* item = aCollector[i];
627 
628  if( item->Type() == PCB_MARKER_T )
629  aCollector.Remove( item );
630  }
631  },
632  m_frame->IsType( FRAME_PCB_EDITOR ) /* prompt user regarding locked items */ );
633 
634  if( selection.Size() <= 1 )
635  return 0;
636 
637  BOARD_COMMIT commit( m_frame );
638  ALIGNMENT_RECTS itemsToDistribute = GetBoundingBoxes( selection );
639 
640  // find the last item by reverse sorting
641  std::sort( itemsToDistribute.begin(), itemsToDistribute.end(),
642  [] ( const ALIGNMENT_RECT left, const ALIGNMENT_RECT right)
643  {
644  return ( left.second.GetBottom() > right.second.GetBottom() );
645  } );
646 
647  BOARD_ITEM* lastItem = itemsToDistribute.begin()->first;
648  const int maxBottom = itemsToDistribute.begin()->second.GetBottom();
649 
650  // sort to get starting order
651  std::sort( itemsToDistribute.begin(), itemsToDistribute.end(),
652  [] ( const ALIGNMENT_RECT left, const ALIGNMENT_RECT right)
653  {
654  return ( left.second.GetCenter().y < right.second.GetCenter().y );
655  } );
656 
657  int minY = itemsToDistribute.begin()->second.GetY();
658  int totalGap = maxBottom - minY;
659  int totalHeight = 0;
660 
661  for( std::pair<BOARD_ITEM*, EDA_RECT>& i : itemsToDistribute )
662  totalHeight += i.second.GetHeight();
663 
664  if( totalGap < totalHeight )
665  {
666  // the width of the items exceeds the gap (overlapping items) -> use center point spacing
667  doDistributeCentersVertically( itemsToDistribute, commit );
668  }
669  else
670  {
671  totalGap -= totalHeight;
672  doDistributeGapsVertically( itemsToDistribute, commit, lastItem, totalGap );
673  }
674 
675  commit.Push( _( "Distribute vertically" ) );
676 
677  return 0;
678 }
679 
680 
682  BOARD_COMMIT& aCommit,
683  const BOARD_ITEM* lastItem,
684  int totalGap ) const
685 {
686  const int itemGap = totalGap / ( itemsToDistribute.size() - 1 );
687  int targetY = itemsToDistribute.begin()->second.GetY();
688 
689  for( std::pair<BOARD_ITEM*, EDA_RECT>& i : itemsToDistribute )
690  {
691  BOARD_ITEM* item = i.first;
692 
693  // cover the corner case where the last item is wider than the previous item and gap
694  if( lastItem == item )
695  continue;
696 
697  if( item->GetParent() && item->GetParent()->IsSelected() )
698  continue;
699 
700  // Don't move a pad by itself unless editing the footprint
701  if( item->Type() == PCB_PAD_T && m_frame->IsType( FRAME_PCB_EDITOR ) )
702  item = item->GetParent();
703 
704  int difference = targetY - i.second.GetY();
705  aCommit.Stage( item, CHT_MODIFY );
706  item->Move( wxPoint( 0, difference ) );
707  targetY += ( i.second.GetHeight() + itemGap );
708  }
709 }
710 
711 
713  BOARD_COMMIT& aCommit ) const
714 {
715  std::sort( itemsToDistribute.begin(), itemsToDistribute.end(),
716  [] ( const ALIGNMENT_RECT left, const ALIGNMENT_RECT right)
717  {
718  return ( left.second.GetCenter().y < right.second.GetCenter().y );
719  } );
720 
721  const int totalGap = ( itemsToDistribute.end()-1 )->second.GetCenter().y
722  - itemsToDistribute.begin()->second.GetCenter().y;
723  const int itemGap = totalGap / ( itemsToDistribute.size() - 1 );
724  int targetY = itemsToDistribute.begin()->second.GetCenter().y;
725 
726  for( std::pair<BOARD_ITEM*, EDA_RECT>& i : itemsToDistribute )
727  {
728  BOARD_ITEM* item = i.first;
729 
730  if( item->GetParent() && item->GetParent()->IsSelected() )
731  continue;
732 
733  // Don't move a pad by itself unless editing the footprint
734  if( item->Type() == PCB_PAD_T && m_frame->IsType( FRAME_PCB_EDITOR ) )
735  item = item->GetParent();
736 
737  int difference = targetY - i.second.GetCenter().y;
738  aCommit.Stage( item, CHT_MODIFY );
739  item->Move( wxPoint( 0, difference ) );
740  targetY += ( itemGap );
741  }
742 }
743 
744 
746 {
753 
756 }
static TOOL_ACTION alignRight
Definition: pcb_actions.h:231
void AddMenu(ACTION_MENU *aMenu, const SELECTION_CONDITION &aCondition=SELECTION_CONDITIONS::ShowAlways, int aOrder=ANY_ORDER)
Add a submenu to the menu.
int AlignLeft(const TOOL_EVENT &aEvent)
Sets X coordinate of the selected items to the value of the left-most selected item X coordinate.
int selectTarget(ALIGNMENT_RECTS &aItems, ALIGNMENT_RECTS &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...
bool IsSelected() const
Definition: eda_item.h:173
Defines the structure of a menu based on ACTIONs.
Definition: action_menu.h:47
This file is part of the common library.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:82
PCB_SELECTION_TOOL * m_selectionTool
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...
void SetIcon(BITMAPS aIcon)
Assign an icon for the entry.
Definition: action_menu.cpp:72
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...
virtual ~ALIGN_DISTRIBUTE_TOOL()
ACTION_MENU * m_placementMenu
Class that computes missing connections on a PCB.
CONDITIONAL_MENU & GetMenu()
Definition: tool_menu.cpp:46
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:215
static TOOL_ACTION alignCenterY
Definition: pcb_actions.h:233
TOOL_MENU & GetToolMenu()
int AlignBottom(const TOOL_EVENT &aEvent)
Sets Y coordinate of the selected items to the value of the bottom-most selected item Y coordinate.
class PAD, a pad in a footprint
Definition: typeinfo.h:89
static TOOL_ACTION distributeVertically
Definition: pcb_actions.h:235
void doDistributeCentersHorizontally(ALIGNMENT_RECTS &itemsToDistribute, BOARD_COMMIT &aCommit) const
Distribute selected items using an even spacing between the centers of their bounding boxes.
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).
void Remove(int aIndex)
Remove the item at aIndex (first position is 0).
Definition: collector.h:115
static TOOL_ACTION alignBottom
Definition: pcb_actions.h:229
static TOOL_ACTION distributeHorizontally
Definition: pcb_actions.h:234
ALIGNMENT_RECTS GetBoundingBoxes(const T &aItems)
int GetCount() const
Return the number of objects in the list.
Definition: collector.h:87
int DistributeHorizontally(const TOOL_EVENT &aEvent)
Distribute the selected items along the X axis.
int doAlignRight()
Align selected items using the right edge of their bounding boxes to the right-most item.
void doDistributeGapsHorizontally(ALIGNMENT_RECTS &itemsToDistribute, BOARD_COMMIT &aCommit, const BOARD_ITEM *lastItem, int totalGap) const
Distributes selected items using an even spacing between their bounding boxes.
int doAlignLeft()
Sets X coordinate of the selected items to the value of the left-most selected item X coordinate.
int GetY() const
Definition: board_item.h:103
#define NULL
std::vector< ALIGNMENT_RECT > ALIGNMENT_RECTS
virtual void Move(const wxPoint &aMoveVector)
Move this object.
Definition: board_item.h:277
int AlignTop(const TOOL_EVENT &aEvent)
Set Y coordinate of the selected items to the value of the top-most selected item Y coordinate.
Generic, UI-independent tool event.
Definition: tool_event.h:173
int DistributeVertically(const TOOL_EVENT &aEvent)
Distribute the selected items along the Y axis.
static TOOL_ACTION alignLeft
Definition: pcb_actions.h:230
virtual wxPoint GetCenter() const
This defaults to the center of the bounding box if not overridden.
Definition: board_item.h:114
static TOOL_ACTION alignTop
Definition: pcb_actions.h:228
void doDistributeGapsVertically(ALIGNMENT_RECTS &itemsToDistribute, BOARD_COMMIT &aCommit, const BOARD_ITEM *lastItem, int totalGap) const
Distributes selected items using an even spacing between their bounding boxes.
KIGFX::VIEW * getView() const
Returns the instance of #VIEW object used in the application.
Definition: tool_base.cpp:36
class FOOTPRINT, a footprint
Definition: typeinfo.h:88
void doDistributeCentersVertically(ALIGNMENT_RECTS &itemsToDistribute, BOARD_COMMIT &aCommit) const
Distribute selected items using an even spacing between the centers of their bounding boxes.
virtual bool IsLocked() const
Definition: board_item.h:249
class MARKER_PCB, a marker used to show something
Definition: typeinfo.h:98
void SetTitle(const wxString &aTitle) override
Set title for the menu.
Definition: action_menu.cpp:90
PCB_SELECTION & RequestSelection(CLIENT_SELECTION_FILTER aClientFilter, bool aConfirmLockedItems=false)
Return the current selection set, filtered according to aFlags and aClientFilter.
int GetX() const
Definition: board_item.h:97
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:241
void setTransitions() override
This method is meant to be overridden in order to specify handlers for events.
const EDA_RECT GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: footprint.cpp:631
wxMenuItem * Add(const wxString &aLabel, int aId, BITMAPS aIcon)
Add a wxWidgets-style entry to the menu.
int Size() const
Returns the number of selected parts.
Definition: selection.h:128
The selection tool: currently supports:
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:150
virtual void Push(const wxString &aMessage=wxT("A commit"), bool aCreateUndoEntry=true, bool aSetDirtyBit=true) override
Revert the commit by restoring the modified items state.
int AlignRight(const TOOL_EVENT &aEvent)
Sets X coordinate of the selected items to the value of the right-most selected item X coordinate.
virtual const EDA_RECT GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
Definition: eda_item.cpp:73
KIGFX::VIEW_CONTROLS * getViewControls() const
Return the instance of VIEW_CONTROLS object used in the application.
Definition: tool_base.cpp:42
bool Init() override
Init() is called once upon a registration of the tool.
BOARD_ITEM_CONTAINER * GetParent() const
Definition: board_item.h:168
static TOOL_ACTION alignCenterX
Definition: pcb_actions.h:232
size_t GetSelections(ALIGNMENT_RECTS &aItemsToAlign, ALIGNMENT_RECTS &aLockedItems, T aCompare)
Populate two vectors with the sorted selection and sorted locked items.
VECTOR2D GetCursorPosition() const
Return the current cursor position in world coordinates.
COMMIT & Stage(EDA_ITEM *aItem, CHANGE_TYPE aChangeType) override
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:163