KiCad PCB EDA Suite
selection_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) 2013-2017 CERN
5  * @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
6  * @author Maciej Suminski <maciej.suminski@cern.ch>
7  * Copyright (C) 2018-2020 KiCad Developers, see AUTHORS.txt for contributors.
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, you may find one here:
21  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
22  * or you may search the http://www.gnu.org website for the version 2 license,
23  * or you may write to the Free Software Foundation, Inc.,
24  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25  */
26 
27 #include <limits>
28 #include <functional>
29 using namespace std::placeholders;
30 #include <class_board.h>
31 #include <class_board_item.h>
32 #include <class_track.h>
33 #include <class_module.h>
34 #include <class_edge_mod.h>
35 #include <class_drawsegment.h>
36 #include <class_zone.h>
37 #include <collectors.h>
38 #include <confirm.h>
39 #include <dialog_find.h>
41 #include <class_draw_panel_gal.h>
42 #include <view/view_controls.h>
44 #include <painter.h>
45 #include <bitmaps.h>
46 #include <pcbnew_settings.h>
47 #include <tool/tool_event.h>
48 #include <tool/tool_manager.h>
49 #include <router/router_tool.h>
51 #include <footprint_viewer_frame.h>
52 #include <id.h>
53 #include "tool_event_utils.h"
54 #include "selection_tool.h"
55 #include "pcb_bright_box.h"
56 #include "pcb_actions.h"
57 
58 #include "kicad_plugin.h"
59 
60 
61 class SELECT_MENU : public ACTION_MENU
62 {
63 public:
65  ACTION_MENU( true )
66  {
67  SetTitle( _( "Select" ) );
68  SetIcon( options_generic_xpm );
69 
71 
72  AppendSeparator();
73 
76  // This could be enabled if we have better logic for picking the target net with the mouse
77  // Add( PCB_ACTIONS::deselectNet );
79  }
80 
81 private:
82  ACTION_MENU* create() const override
83  {
84  return new SELECT_MENU();
85  }
86 };
87 
88 
93 {
94 public:
96 };
97 
98 
100  PCB_TOOL_BASE( "pcbnew.InteractiveSelection" ),
101  m_frame( NULL ),
102  m_additive( false ),
103  m_subtractive( false ),
104  m_exclusive_or( false ),
105  m_multiple( false ),
106  m_skip_heuristics( false ),
107  m_locked( true ),
108  m_enteredGroup( NULL ),
109  m_priv( std::make_unique<PRIV>() )
110 {
111  m_filter.lockedItems = true;
112  m_filter.footprints = true;
113  m_filter.text = true;
114  m_filter.tracks = true;
115  m_filter.vias = true;
116  m_filter.pads = true;
117  m_filter.graphics = true;
118  m_filter.zones = true;
119  m_filter.keepouts = true;
120  m_filter.dimensions = true;
121  m_filter.otherItems = true;
122 }
123 
124 
126 {
127  getView()->Remove( &m_selection );
128 }
129 
130 
132 {
133  auto frame = getEditFrame<PCB_BASE_FRAME>();
134 
137  {
139  return true;
140  }
141 
142  auto selectMenu = std::make_shared<SELECT_MENU>();
143  selectMenu->SetTool( this );
144  m_menu.AddSubMenu( selectMenu );
145 
146  auto& menu = m_menu.GetMenu();
147 
148  auto activeToolCondition =
149  [ frame ] ( const SELECTION& aSel )
150  {
151  return !frame->ToolStackIsEmpty();
152  };
153 
154  auto inGroupCondition =
155  [this] ( const SELECTION& )
156  {
157  return m_enteredGroup != nullptr;
158  };
159 
160  menu.AddMenu( selectMenu.get(), SELECTION_CONDITIONS::NotEmpty );
161  menu.AddSeparator( 1000 );
162 
163  // "Cancel" goes at the top of the context menu when a tool is active
164  menu.AddItem( ACTIONS::cancelInteractive, activeToolCondition, 1 );
165  menu.AddItem( PCB_ACTIONS::groupLeave, inGroupCondition, 1);
166  menu.AddSeparator( 1 );
167 
168  if( frame )
170 
171  return true;
172 }
173 
174 
176 {
177  m_frame = getEditFrame<PCB_BASE_FRAME>();
178  m_locked = true;
179 
180  if( m_enteredGroup != NULL )
181  ExitGroup();
182 
183  if( aReason == TOOL_BASE::MODEL_RELOAD )
184  {
185  // Deselect any item being currently in edit, to avoid unexpected behavior
186  // and remove pointers to the selected items from containers
187  // without changing their properties (as they are already deleted
188  // while a new board is loaded)
189  ClearSelection( true );
190 
191  getView()->GetPainter()->GetSettings()->SetHighlight( false );
192  }
193  else
194  {
195  // Restore previous properties of selected items and remove them from containers
196  ClearSelection( true );
197  }
198 
199  // Reinsert the VIEW_GROUP, in case it was removed from the VIEW
200  view()->Remove( &m_selection );
201  view()->Add( &m_selection );
202 }
203 
204 
205 int SELECTION_TOOL::Main( const TOOL_EVENT& aEvent )
206 {
207  // Main loop: keep receiving events
208  while( TOOL_EVENT* evt = Wait() )
209  {
210  if( m_frame->ToolStackIsEmpty() )
211  m_frame->GetCanvas()->SetCurrentCursor( wxCURSOR_ARROW );
212 
213  bool dragAlwaysSelects = getEditFrame<PCB_BASE_FRAME>()->GetDragSelects();
214  TRACK_DRAG_ACTION dragAction = getEditFrame<PCB_BASE_FRAME>()->Settings().m_TrackDragAction;
216 
217  // OSX uses CTRL for context menu, and SHIFT is exclusive-or
218 #ifdef __WXOSX_MAC__
219  if( evt->Modifier( MD_SHIFT ) )
220  m_exclusive_or = true;
221 #else
222  if( evt->Modifier( MD_SHIFT ) && evt->Modifier( MD_CTRL ) )
223  m_subtractive = true;
224  else if( evt->Modifier( MD_SHIFT ) )
225  m_additive = true;
226  else if( evt->Modifier( MD_CTRL ) )
227  m_exclusive_or = true;
228 #endif
229 
230  // Is the user requesting that the selection list include all possible
231  // items without removing less likely selection candidates
232  m_skip_heuristics = !!evt->Modifier( MD_ALT );
233 
234  // Single click? Select single object
235  if( evt->IsClick( BUT_LEFT ) )
236  {
237  m_frame->FocusOnItem( nullptr );
238 
239  selectPoint( evt->Position() );
240  }
241 
242  // right click? if there is any object - show the context menu
243  else if( evt->IsClick( BUT_RIGHT ) )
244  {
245  bool selectionCancelled = false;
246 
247  if( m_selection.Empty() ||
248  !m_selection.GetBoundingBox().Contains( wxPoint( evt->Position() ) ) )
249  {
250  ClearSelection();
251  selectPoint( evt->Position(), false, &selectionCancelled );
252  m_selection.SetIsHover( true );
253  }
254 
255  if( !selectionCancelled )
257  }
258 
259  // double click? Display the properties window
260  else if( evt->IsDblClick( BUT_LEFT ) )
261  {
262  m_frame->FocusOnItem( nullptr );
263 
264  if( m_selection.Empty() )
265  selectPoint( evt->Position() );
266 
267  if( m_selection.GetSize() == 1 && m_selection[0]->Type() == PCB_GROUP_T )
268  {
269  EnterGroup();
270  }
271  else
272  {
274  }
275  }
276 
277  // drag with LMB? Select multiple objects (or at least draw a selection box) or drag them
278  else if( evt->IsDrag( BUT_LEFT ) )
279  {
280  m_frame->FocusOnItem( nullptr );
281 
282  if( m_additive || m_subtractive || m_exclusive_or || dragAlwaysSelects )
283  {
284  selectMultiple();
285  }
286  else
287  {
288  // selection is empty? try to start dragging the item under the point where drag
289  // started
290  if( m_selection.Empty() && selectCursor() )
291  m_selection.SetIsHover( true );
292 
293  // Check if dragging has started within any of selected items bounding box.
294  // We verify "HasPosition()" first to protect against edge case involving
295  // moving off menus that causes problems (issue #5250)
296  if( evt->HasPosition() && selectionContains( evt->Position() ) )
297  {
298  // Yes -> run the move tool and wait till it finishes
299  TRACK* track = dynamic_cast<TRACK*>( m_selection.GetItem( 0 ) );
300 
301  if( track && dragAction == TRACK_DRAG_ACTION::DRAG )
303  else if( track && dragAction == TRACK_DRAG_ACTION::DRAG_FREE_ANGLE )
305  else
307  }
308  else
309  {
310  // No -> drag a selection box
311  selectMultiple();
312  }
313  }
314  }
315 
316  else if( evt->IsCancel() )
317  {
318  m_frame->FocusOnItem( nullptr );
319 
320  if( m_enteredGroup != NULL )
321  ExitGroup();
322 
323  ClearSelection();
324 
325  if( evt->FirstResponder() == this )
327  }
328 
329  else
330  evt->SetPassEvent();
331  }
332 
333  return 0;
334 }
335 
336 
338 {
339  wxCHECK_RET( m_selection.GetSize() == 1 && m_selection[0]->Type() == PCB_GROUP_T,
340  "EnterGroup called when selection is not a single group" );
341  PCB_GROUP* aGroup = static_cast<PCB_GROUP*>( m_selection[0] );
342 
343  if( m_enteredGroup != NULL )
344  ExitGroup();
345 
346  ClearSelection();
347  m_enteredGroup = aGroup;
348  m_enteredGroup->RunOnChildren( [&]( BOARD_ITEM* titem ) { select( titem ); } );
349 }
350 
351 
352 void SELECTION_TOOL::ExitGroup( bool aSelectGroup )
353 {
354  // Only continue if there is a group entered
355  if( m_enteredGroup == nullptr )
356  return;
357 
358  ClearSelection();
359 
360  if( aSelectGroup )
362 
364 }
365 
366 
368 {
369  return m_selection;
370 }
371 
372 
374  std::vector<BOARD_ITEM*>* aFiltered,
375  bool aConfirmLockedItems )
376 {
377  bool selectionEmpty = m_selection.Empty();
378  m_selection.SetIsHover( selectionEmpty );
379 
380  if( selectionEmpty )
381  {
382  m_toolMgr->RunAction( PCB_ACTIONS::selectionCursor, true, aClientFilter );
384  }
385 
386  if ( aConfirmLockedItems && CheckLock() == SELECTION_LOCKED )
387  {
388  ClearSelection();
389  return m_selection;
390  }
391 
392  if( aClientFilter )
393  {
394  enum DISPOSITION { BEFORE = 1, AFTER, BOTH };
395 
396  std::map<EDA_ITEM*, DISPOSITION> itemDispositions;
397  GENERAL_COLLECTOR collector;
398 
399  for( EDA_ITEM* item : m_selection )
400  {
401  collector.Append( item );
402  itemDispositions[ item ] = BEFORE;
403  }
404 
405  aClientFilter( VECTOR2I(), collector, this );
406 
407  for( EDA_ITEM* item : collector )
408  {
409  if( itemDispositions.count( item ) )
410  itemDispositions[ item ] = BOTH;
411  else
412  itemDispositions[ item ] = AFTER;
413  }
414 
415  // Unhighlight the BEFORE items before highlighting the AFTER items.
416  // This is so that in the case of groups, if aClientFilter replaces a selection
417  // with the enclosing group, the unhighlight of the element doesn't undo the
418  // recursive highlighting of that elemetn by the group.
419 
420  for( std::pair<EDA_ITEM* const, DISPOSITION> itemDisposition : itemDispositions )
421  {
422  BOARD_ITEM* item = static_cast<BOARD_ITEM*>( itemDisposition.first );
423  DISPOSITION disposition = itemDisposition.second;
424 
425  if( disposition == BEFORE )
426  {
427  if( aFiltered )
428  aFiltered->push_back( item );
429 
430  unhighlight( item, SELECTED, &m_selection );
431  }
432  }
433 
434  for( std::pair<EDA_ITEM* const, DISPOSITION> itemDisposition : itemDispositions )
435  {
436  BOARD_ITEM* item = static_cast<BOARD_ITEM*>( itemDisposition.first );
437  DISPOSITION disposition = itemDisposition.second;
438 
439  if( disposition == AFTER )
440  {
441  highlight( item, SELECTED, &m_selection );
442  }
443  else if( disposition == BOTH )
444  {
445  // nothing to do
446  }
447  }
448 
450  }
451 
452  return m_selection;
453 }
454 
455 
457 {
458  GENERAL_COLLECTORS_GUIDE guide( board()->GetVisibleLayers(),
459  (PCB_LAYER_ID) view()->GetTopLayer(), view() );
460 
461  bool padsDisabled = !board()->IsElementVisible( LAYER_PADS );
462 
463  // account for the globals
464  guide.SetIgnoreMTextsMarkedNoShow( ! board()->IsElementVisible( LAYER_MOD_TEXT_INVISIBLE ) );
465  guide.SetIgnoreMTextsOnBack( ! board()->IsElementVisible( LAYER_MOD_TEXT_BK ) );
466  guide.SetIgnoreMTextsOnFront( ! board()->IsElementVisible( LAYER_MOD_TEXT_FR ) );
467  guide.SetIgnoreModulesOnBack( ! board()->IsElementVisible( LAYER_MOD_BK ) );
468  guide.SetIgnoreModulesOnFront( ! board()->IsElementVisible( LAYER_MOD_FR ) );
469  guide.SetIgnorePadsOnBack( padsDisabled || ! board()->IsElementVisible( LAYER_PAD_BK ) );
470  guide.SetIgnorePadsOnFront( padsDisabled || ! board()->IsElementVisible( LAYER_PAD_FR ) );
471  guide.SetIgnoreThroughHolePads( padsDisabled || ! board()->IsElementVisible( LAYER_PADS_TH ) );
472  guide.SetIgnoreModulesVals( ! board()->IsElementVisible( LAYER_MOD_VALUES ) );
473  guide.SetIgnoreModulesRefs( ! board()->IsElementVisible( LAYER_MOD_REFERENCES ) );
474  guide.SetIgnoreThroughVias( ! board()->IsElementVisible( LAYER_VIAS ) );
475  guide.SetIgnoreBlindBuriedVias( ! board()->IsElementVisible( LAYER_VIAS ) );
476  guide.SetIgnoreMicroVias( ! board()->IsElementVisible( LAYER_VIAS ) );
477  guide.SetIgnoreTracks( ! board()->IsElementVisible( LAYER_TRACKS ) );
478 
479  return guide;
480 }
481 
482 
483 bool SELECTION_TOOL::selectPoint( const VECTOR2I& aWhere, bool aOnDrag,
484  bool* aSelectionCancelledFlag,
485  CLIENT_SELECTION_FILTER aClientFilter )
486 {
488  GENERAL_COLLECTOR collector;
489  const PCB_DISPLAY_OPTIONS& displayOpts = m_frame->GetDisplayOptions();
490 
492 
493  if( m_enteredGroup &&
494  !m_enteredGroup->GetBoundingBox().Contains( wxPoint( aWhere.x, aWhere.y ) ) )
495  {
496  ExitGroup();
497  }
498 
501  (wxPoint) aWhere, guide );
502 
503  // Remove unselectable items
504  for( int i = collector.GetCount() - 1; i >= 0; --i )
505  {
506  if( !Selectable( collector[ i ] ) || ( aOnDrag && collector[i]->IsLocked() ) )
507  collector.Remove( i );
508  }
509 
511 
512  // Allow the client to do tool- or action-specific filtering to see if we
513  // can get down to a single item
514  if( aClientFilter )
515  aClientFilter( aWhere, collector, this );
516 
517  // Apply the stateful filter
518  filterCollectedItems( collector );
519 
520  // Apply some ugly heuristics to avoid disambiguation menus whenever possible
521  if( collector.GetCount() > 1 && !m_skip_heuristics )
522  {
523  GuessSelectionCandidates( collector, aWhere );
524  }
525 
526  // If still more than one item we're going to have to ask the user.
527  if( collector.GetCount() > 1 )
528  {
529  if( aOnDrag )
531 
532  if( !doSelectionMenu( &collector, wxEmptyString ) )
533  {
534  if( aSelectionCancelledFlag )
535  *aSelectionCancelledFlag = true;
536 
537  return false;
538  }
539  }
540 
541  bool anyAdded = false;
542  bool anySubtracted = false;
543 
545  {
546  if( m_selection.GetSize() > 0 )
547  {
548  ClearSelection( true /*quiet mode*/ );
549  anySubtracted = true;
550  }
551  }
552 
553  if( collector.GetCount() > 0 )
554  {
555  for( int i = 0; i < collector.GetCount(); ++i )
556  {
557  if( m_subtractive || ( m_exclusive_or && collector[i]->IsSelected() ) )
558  {
559  unselect( collector[i] );
560  anySubtracted = true;
561  }
562  else
563  {
564  select( collector[i] );
565  anyAdded = true;
566  }
567  }
568  }
569 
570  if( anyAdded )
571  {
573  return true;
574  }
575  else if( anySubtracted )
576  {
578  return true;
579  }
580 
581  return false;
582 }
583 
584 
585 bool SELECTION_TOOL::selectCursor( bool aForceSelect, CLIENT_SELECTION_FILTER aClientFilter )
586 {
587  if( aForceSelect || m_selection.Empty() )
588  {
589  ClearSelection( true /*quiet mode*/ );
590  selectPoint( getViewControls()->GetCursorPosition( false ), false, NULL, aClientFilter );
591  }
592 
593  return !m_selection.Empty();
594 }
595 
596 
598 {
599  bool cancelled = false; // Was the tool cancelled while it was running?
600  m_multiple = true; // Multiple selection mode is active
601  KIGFX::VIEW* view = getView();
602 
604  view->Add( &area );
605 
606  bool anyAdded = false;
607  bool anySubtracted = false;
608 
609  while( TOOL_EVENT* evt = Wait() )
610  {
611  if( evt->IsCancelInteractive() || evt->IsActivate() )
612  {
613  cancelled = true;
614  break;
615  }
616 
617  if( evt->IsDrag( BUT_LEFT ) )
618  {
620  {
621  if( m_selection.GetSize() > 0 )
622  {
623  anySubtracted = true;
624  ClearSelection( true /*quiet mode*/ );
625  }
626  }
627 
628  // Start drawing a selection box
629  area.SetOrigin( evt->DragOrigin() );
630  area.SetEnd( evt->Position() );
631  area.SetAdditive( m_additive );
634 
635  view->SetVisible( &area, true );
636  view->Update( &area );
637  getViewControls()->SetAutoPan( true );
638  }
639 
640  if( evt->IsMouseUp( BUT_LEFT ) )
641  {
642  getViewControls()->SetAutoPan( false );
643 
644  // End drawing the selection box
645  view->SetVisible( &area, false );
646 
647  // Mark items within the selection box as selected
648  std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> selectedItems;
649 
650  // Filter the view items based on the selection box
651  BOX2I selectionBox = area.ViewBBox();
652  view->Query( selectionBox, selectedItems ); // Get the list of selected items
653 
654  std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR>::iterator it, it_end;
655 
656  int width = area.GetEnd().x - area.GetOrigin().x;
657  int height = area.GetEnd().y - area.GetOrigin().y;
658 
659  /* Selection mode depends on direction of drag-selection:
660  * Left > Right : Select objects that are fully enclosed by selection
661  * Right > Left : Select objects that are crossed by selection
662  */
663  bool windowSelection = width >= 0 ? true : false;
664 
665  if( view->IsMirroredX() )
666  windowSelection = !windowSelection;
667 
668  // Construct an EDA_RECT to determine BOARD_ITEM selection
669  EDA_RECT selectionRect( (wxPoint) area.GetOrigin(), wxSize( width, height ) );
670 
671  selectionRect.Normalize();
672 
673  for( it = selectedItems.begin(), it_end = selectedItems.end(); it != it_end; ++it )
674  {
675  BOARD_ITEM* item = static_cast<BOARD_ITEM*>( it->first );
676 
677  if( !item || !Selectable( item ) || !itemPassesFilter( item ) )
678  continue;
679 
680  if( item->HitTest( selectionRect, windowSelection ) )
681  {
682  if( m_subtractive || ( m_exclusive_or && item->IsSelected() ) )
683  {
684  unselect( item );
685  anySubtracted = true;
686  }
687  else
688  {
689  select( item );
690  anyAdded = true;
691  }
692  }
693  }
694 
695  m_selection.SetIsHover( false );
696 
697  // Inform other potentially interested tools
698  if( anyAdded )
700  else if( anySubtracted )
702 
703  break; // Stop waiting for events
704  }
705  }
706 
707  getViewControls()->SetAutoPan( false );
708 
709  // Stop drawing the selection box
710  view->Remove( &area );
711  m_multiple = false; // Multiple selection mode is inactive
712 
713  if( !cancelled )
715 
716  return cancelled;
717 }
718 
719 
721 {
722  if( !m_locked || m_editModules )
723  return SELECTION_UNLOCKED;
724 
725  bool containsLocked = false;
726 
727  // Check if the selection contains locked items
728  for( EDA_ITEM* item : m_selection )
729  {
730  switch( item->Type() )
731  {
732  case PCB_MODULE_T:
733  if( static_cast<MODULE*>( item )->IsLocked() )
734  containsLocked = true;
735  break;
736 
737  case PCB_MODULE_EDGE_T:
738  case PCB_MODULE_TEXT_T:
740  if( static_cast<MODULE*>( item->GetParent() )->IsLocked() )
741  containsLocked = true;
742  break;
743 
744  default: // suppress warnings
745  break;
746  }
747  }
748 
749  if( containsLocked )
750  {
751  if( IsOK( m_frame, _( "Selection contains locked items. Do you want to continue?" ) ) )
752  {
753  m_locked = false;
755  }
756  else
757  return SELECTION_LOCKED;
758  }
759 
760  return SELECTION_UNLOCKED;
761 }
762 
763 
765 {
767 
768  selectCursor( false, aClientFilter );
769 
770  return 0;
771 }
772 
773 
775 {
776  ClearSelection();
777 
778  return 0;
779 }
780 
781 
783 {
784  std::vector<BOARD_ITEM*>* items = aEvent.Parameter<std::vector<BOARD_ITEM*>*>();
785 
786  if( items )
787  {
788  // Perform individual selection of each item before processing the event.
789  for( BOARD_ITEM* item : *items )
790  select( item );
791 
793  }
794 
795  return 0;
796 }
797 
798 
800 {
801  AddItemToSel( aEvent.Parameter<BOARD_ITEM*>() );
802  return 0;
803 }
804 
805 
807 {
808  KIGFX::VIEW* view = getView();
809 
810  // hold all visible items
811  std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> selectedItems;
812 
813  // Filter the view items based on the selection box
814  BOX2I selectionBox;
815 
816  selectionBox.SetMaximum();
817  view->Query( selectionBox, selectedItems ); // Get the list of selected items
818 
819  for( const KIGFX::VIEW::LAYER_ITEM_PAIR& item_pair : selectedItems )
820  {
821  BOARD_ITEM* item = static_cast<BOARD_ITEM*>( item_pair.first );
822 
823  if( !item || !Selectable( item ) || !itemPassesFilter( item ) )
824  continue;
825 
826  select( item );
827  }
828 
829  return 0;
830 }
831 
832 
833 void SELECTION_TOOL::AddItemToSel( BOARD_ITEM* aItem, bool aQuietMode )
834 {
835  if( aItem )
836  {
837  select( aItem );
838 
839  // Inform other potentially interested tools
840  if( !aQuietMode )
842  }
843 }
844 
845 
847 {
848  std::vector<BOARD_ITEM*>* items = aEvent.Parameter<std::vector<BOARD_ITEM*>*>();
849 
850  if( items )
851  {
852  // Perform individual unselection of each item before processing the event
853  for( auto item : *items )
854  unselect( item );
855 
857  }
858 
859  return 0;
860 }
861 
862 
864 {
865  RemoveItemFromSel( aEvent.Parameter<BOARD_ITEM*>() );
866  return 0;
867 }
868 
869 
870 void SELECTION_TOOL::RemoveItemFromSel( BOARD_ITEM* aItem, bool aQuietMode )
871 {
872  if( aItem )
873  {
874  unselect( aItem );
875 
876  // Inform other potentially interested tools
878  }
879 }
880 
881 
883 {
884  highlight( aItem, BRIGHTENED );
885 }
886 
887 
889 {
890  unhighlight( aItem, BRIGHTENED );
891 }
892 
893 
895 {
896  // Narrow the collection down to a single BOARD_CONNECTED_ITEM for each represented net.
897  // All other items types are removed.
898  std::set<int> representedNets;
899 
900  for( int i = aCollector.GetCount() - 1; i >= 0; i-- )
901  {
902  BOARD_CONNECTED_ITEM* item = dynamic_cast<BOARD_CONNECTED_ITEM*>( aCollector[i] );
903  if( !item )
904  aCollector.Remove( i );
905  else if ( representedNets.count( item->GetNetCode() ) )
906  aCollector.Remove( i );
907  else
908  representedNets.insert( item->GetNetCode() );
909  }
910 }
911 
912 
914 {
915  unsigned initialCount = 0;
916 
917  for( auto item : m_selection.GetItems() )
918  {
919  if( dynamic_cast<BOARD_CONNECTED_ITEM*>( item ) )
920  initialCount++;
921  }
922 
923  if( initialCount == 0 )
925 
926  for( STOP_CONDITION stopCondition : { STOP_AT_JUNCTION, STOP_AT_PAD, STOP_NEVER } )
927  {
928  // copy the selection, since we're going to iterate and modify
929  std::deque<EDA_ITEM*> selectedItems = m_selection.GetItems();
930 
931  for( EDA_ITEM* item : selectedItems )
932  item->ClearTempFlags();
933 
934  for( EDA_ITEM* item : selectedItems )
935  {
936  TRACK* trackItem = dynamic_cast<TRACK*>( item );
937 
938  // Track items marked SKIP_STRUCT have already been visited
939  if( trackItem && !( trackItem->GetFlags() & SKIP_STRUCT ) )
940  selectConnectedTracks( *trackItem, stopCondition );
941  }
942 
943  if( m_selection.GetItems().size() > initialCount )
944  break;
945  }
946 
947  // Inform other potentially interested tools
948  if( m_selection.Size() > 0 )
950 
951  return 0;
952 }
953 
954 
956  STOP_CONDITION aStopCondition )
957 {
958  constexpr KICAD_T types[] = { PCB_TRACE_T, PCB_ARC_T, PCB_VIA_T, PCB_PAD_T, EOT };
959 
960  auto connectivity = board()->GetConnectivity();
961  auto connectedItems = connectivity->GetConnectedItems( &aStartItem, types );
962 
963  std::map<wxPoint, std::vector<TRACK*>> trackMap;
964  std::map<wxPoint, VIA*> viaMap;
965  std::map<wxPoint, D_PAD*> padMap;
966 
967  // Build maps of connected items
968  for( BOARD_CONNECTED_ITEM* item : connectedItems )
969  {
970  switch( item->Type() )
971  {
972  case PCB_TRACE_T:
973  {
974  TRACK* track = static_cast<TRACK*>( item );
975  trackMap[ track->GetStart() ].push_back( track );
976  trackMap[ track->GetEnd() ].push_back( track );
977  }
978  break;
979 
980  case PCB_VIA_T:
981  {
982  VIA* via = static_cast<VIA*>( item );
983  viaMap[ via->GetStart() ] = via;
984  }
985  break;
986 
987  case PCB_PAD_T:
988  {
989  D_PAD* pad = static_cast<D_PAD*>( item );
990  padMap[ pad->GetPosition() ] = pad;
991  }
992  break;
993 
994  default:
995  break;
996  }
997 
998  item->SetState( SKIP_STRUCT, false );
999  }
1000 
1001  std::vector<wxPoint> activePts;
1002 
1003  // Set up the initial active points
1004  switch( aStartItem.Type() )
1005  {
1006  case PCB_TRACE_T:
1007  activePts.push_back( static_cast<TRACK*>( &aStartItem )->GetStart() );
1008  activePts.push_back( static_cast<TRACK*>( &aStartItem )->GetEnd() );
1009  break;
1010 
1011  case PCB_VIA_T:
1012  activePts.push_back( static_cast<TRACK*>( &aStartItem )->GetStart() );
1013  break;
1014 
1015  case PCB_PAD_T:
1016  activePts.push_back( aStartItem.GetPosition() );
1017  break;
1018 
1019  default:
1020  break;
1021  }
1022 
1023  bool expand = true;
1024 
1025  // Iterative push from all active points
1026  while( expand )
1027  {
1028  expand = false;
1029 
1030  for( int i = activePts.size() - 1; i >= 0; --i )
1031  {
1032  wxPoint pt = activePts[i];
1033 
1034  if( trackMap[ pt ].size() > 2 && aStopCondition == STOP_AT_JUNCTION )
1035  {
1036  activePts.erase( activePts.begin() + i );
1037  continue;
1038  }
1039 
1040  if( padMap.count( pt ) && aStopCondition != STOP_NEVER )
1041  {
1042  activePts.erase( activePts.begin() + i );
1043  continue;
1044  }
1045 
1046  for( TRACK* track : trackMap[ pt ] )
1047  {
1048  if( track->GetState( SKIP_STRUCT ) )
1049  continue;
1050 
1051  track->SetState( SKIP_STRUCT, true );
1052  select( track );
1053 
1054  if( track->GetStart() == pt )
1055  activePts.push_back( track->GetEnd() );
1056  else
1057  activePts.push_back( track->GetStart() );
1058 
1059  expand = true;
1060  }
1061 
1062  if( viaMap.count( pt ) && !viaMap[ pt ]->IsSelected() )
1063  select( viaMap[ pt ] );
1064 
1065  activePts.erase( activePts.begin() + i );
1066  }
1067  }
1068 }
1069 
1070 
1071 void SELECTION_TOOL::selectAllItemsOnNet( int aNetCode, bool aSelect )
1072 {
1073  constexpr KICAD_T types[] = { PCB_TRACE_T, PCB_VIA_T, EOT };
1074  auto connectivity = board()->GetConnectivity();
1075 
1076  for( BOARD_CONNECTED_ITEM* item : connectivity->GetNetItems( aNetCode, types ) )
1077  if( itemPassesFilter( item ) )
1078  aSelect ? select( item ) : unselect( item );
1079 }
1080 
1081 
1083 {
1084  bool select = aEvent.IsAction( &PCB_ACTIONS::selectNet );
1085 
1086  // If we've been passed an argument, just select that netcode1
1087  int netcode = aEvent.Parameter<intptr_t>();
1088 
1089  if( netcode > 0 )
1090  {
1091  selectAllItemsOnNet( netcode, select );
1092  return 0;
1093  }
1094 
1095  if( !selectCursor() )
1096  return 0;
1097 
1098  // copy the selection, since we're going to iterate and modify
1099  auto selection = m_selection.GetItems();
1100 
1101  for( EDA_ITEM* i : selection )
1102  {
1103  BOARD_CONNECTED_ITEM* connItem = dynamic_cast<BOARD_CONNECTED_ITEM*>( i );
1104 
1105  if( connItem )
1106  selectAllItemsOnNet( connItem->GetNetCode(), select );
1107  }
1108 
1109  // Inform other potentially interested tools
1110  if( m_selection.Size() > 0 )
1112 
1113  return 0;
1114 }
1115 
1116 
1117 void SELECTION_TOOL::selectAllItemsOnSheet( wxString& aSheetPath )
1118 {
1119  std::list<MODULE*> modList;
1120 
1121  // store all modules that are on that sheet path
1122  for( MODULE* module : board()->Modules() )
1123  {
1124  if( module == nullptr )
1125  continue;
1126 
1127  wxString footprint_path = module->GetPath().AsString().BeforeLast('/');
1128 
1129  if( aSheetPath.IsEmpty() )
1130  aSheetPath += '/';
1131 
1132  if( footprint_path == aSheetPath )
1133  modList.push_back( module );
1134  }
1135 
1136  //Generate a list of all pads, and of all nets they belong to.
1137  std::list<int> netcodeList;
1138  std::list<D_PAD*> padList;
1139  for( MODULE* mmod : modList )
1140  {
1141  for( D_PAD* pad : mmod->Pads() )
1142  {
1143  if( pad->IsConnected() )
1144  {
1145  netcodeList.push_back( pad->GetNetCode() );
1146  padList.push_back( pad );
1147  }
1148  }
1149  }
1150  // remove all duplicates
1151  netcodeList.sort();
1152  netcodeList.unique();
1153 
1154  // auto select trivial connections segments which are launched from the pads
1155  std::list<TRACK*> launchTracks;
1156 
1157  for( D_PAD* pad : padList )
1159 
1160  // now we need to find all modules that are connected to each of these nets
1161  // then we need to determine if these modules are in the list of modules
1162  // belonging to this sheet ( modList )
1163  std::list<int> removeCodeList;
1164  constexpr KICAD_T padType[] = { PCB_PAD_T, EOT };
1165 
1166  for( int netCode : netcodeList )
1167  {
1168  for( BOARD_CONNECTED_ITEM* mitem : board()->GetConnectivity()->GetNetItems( netCode, padType ) )
1169  {
1170  if( mitem->Type() == PCB_PAD_T)
1171  {
1172  bool found = std::find( modList.begin(), modList.end(), mitem->GetParent() ) != modList.end();
1173 
1174  if( !found )
1175  {
1176  // if we cannot find the module of the pad in the modList
1177  // then we can assume that that module is not located in the same
1178  // schematic, therefore invalidate this netcode.
1179  removeCodeList.push_back( netCode );
1180  break;
1181  }
1182  }
1183  }
1184  }
1185 
1186  // remove all duplicates
1187  removeCodeList.sort();
1188  removeCodeList.unique();
1189 
1190  for( int removeCode : removeCodeList )
1191  {
1192  netcodeList.remove( removeCode );
1193  }
1194 
1195  std::list<BOARD_CONNECTED_ITEM*> localConnectionList;
1196  constexpr KICAD_T trackViaType[] = { PCB_TRACE_T, PCB_VIA_T, EOT };
1197 
1198  for( int netCode : netcodeList )
1199  {
1200  for( BOARD_CONNECTED_ITEM* item : board()->GetConnectivity()->GetNetItems( netCode, trackViaType ) )
1201  localConnectionList.push_back( item );
1202  }
1203 
1204  for( BOARD_ITEM* i : modList )
1205  {
1206  if( i != NULL )
1207  select( i );
1208  }
1209 
1210  for( BOARD_CONNECTED_ITEM* i : localConnectionList )
1211  {
1212  if( i != NULL )
1213  select( i );
1214  }
1215 }
1216 
1217 
1219 {
1220  //Should recalculate the view to zoom in on the selection
1221  auto selectionBox = m_selection.GetBoundingBox();
1222  auto view = getView();
1223 
1224  VECTOR2D screenSize = view->ToWorld( m_frame->GetCanvas()->GetClientSize(), false );
1225  screenSize.x = std::max( 10.0, screenSize.x );
1226  screenSize.y = std::max( 10.0, screenSize.y );
1227 
1228  if( selectionBox.GetWidth() != 0 || selectionBox.GetHeight() != 0 )
1229  {
1230  VECTOR2D vsize = selectionBox.GetSize();
1231  double scale = view->GetScale() / std::max( fabs( vsize.x / screenSize.x ),
1232  fabs( vsize.y / screenSize.y ) );
1233  view->SetScale( scale );
1234  view->SetCenter( selectionBox.Centre() );
1235  view->Add( &m_selection );
1236  }
1237 
1239 }
1240 
1241 
1243 {
1244  ClearSelection( true /*quiet mode*/ );
1245  wxString sheetPath = *aEvent.Parameter<wxString*>();
1246 
1247  selectAllItemsOnSheet( sheetPath );
1248 
1249  zoomFitSelection();
1250 
1251  if( m_selection.Size() > 0 )
1253 
1254  return 0;
1255 }
1256 
1257 
1259 {
1260  if( !selectCursor( true ) )
1261  return 0;
1262 
1263  // this function currently only supports modules since they are only
1264  // on one sheet.
1265  auto item = m_selection.Front();
1266 
1267  if( !item )
1268  return 0;
1269 
1270  if( item->Type() != PCB_MODULE_T )
1271  return 0;
1272 
1273  auto mod = dynamic_cast<MODULE*>( item );
1274 
1275  if( mod->GetPath().empty() )
1276  return 0;
1277 
1278  ClearSelection( true /*quiet mode*/ );
1279 
1280  // get the sheet path only.
1281  wxString sheetPath = mod->GetPath().AsString().BeforeLast( '/' );
1282 
1283  if( sheetPath.IsEmpty() )
1284  sheetPath += '/';
1285 
1286  selectAllItemsOnSheet( sheetPath );
1287 
1288  // Inform other potentially interested tools
1289  if( m_selection.Size() > 0 )
1291 
1292  return 0;
1293 }
1294 
1295 
1297 {
1298  bool cleared = false;
1299 
1300  if( m_selection.GetSize() > 0 )
1301  {
1302  // Don't fire an event now; most of the time it will be redundant as we're about to
1303  // fire a SelectedEvent.
1304  cleared = true;
1305  ClearSelection( true /*quiet mode*/ );
1306  }
1307 
1308  if( aItem )
1309  {
1310  select( aItem );
1311  m_frame->FocusOnLocation( aItem->GetPosition() );
1312 
1313  // Inform other potentially interested tools
1315  }
1316  else if( cleared )
1317  {
1319  }
1320 
1322 }
1323 
1324 
1325 int SELECTION_TOOL::find( const TOOL_EVENT& aEvent )
1326 {
1327  DIALOG_FIND dlg( m_frame );
1328  dlg.SetCallback( std::bind( &SELECTION_TOOL::findCallback, this, _1 ) );
1329  dlg.ShowModal();
1330 
1331  return 0;
1332 }
1333 
1334 
1342 static bool itemIsIncludedByFilter( const BOARD_ITEM& aItem, const BOARD& aBoard,
1343  const DIALOG_FILTER_SELECTION::OPTIONS& aFilterOptions )
1344 {
1345  bool include = true;
1346  const PCB_LAYER_ID layer = aItem.GetLayer();
1347 
1348  // if the item needs to be checked against the options
1349  if( include )
1350  {
1351  switch( aItem.Type() )
1352  {
1353  case PCB_MODULE_T:
1354  {
1355  const auto& module = static_cast<const MODULE&>( aItem );
1356 
1357  include = aFilterOptions.includeModules;
1358 
1359  if( include && !aFilterOptions.includeLockedModules )
1360  {
1361  include = !module.IsLocked();
1362  }
1363 
1364  break;
1365  }
1366  case PCB_TRACE_T:
1367  case PCB_ARC_T:
1368  {
1369  include = aFilterOptions.includeTracks;
1370  break;
1371  }
1372  case PCB_VIA_T:
1373  {
1374  include = aFilterOptions.includeVias;
1375  break;
1376  }
1377  case PCB_ZONE_AREA_T:
1378  {
1379  include = aFilterOptions.includeZones;
1380  break;
1381  }
1382  case PCB_LINE_T:
1383  case PCB_TARGET_T:
1384  case PCB_DIM_ALIGNED_T:
1385  case PCB_DIM_CENTER_T:
1386  case PCB_DIM_ORTHOGONAL_T:
1387  case PCB_DIM_LEADER_T:
1388  {
1389  if( layer == Edge_Cuts )
1390  include = aFilterOptions.includeBoardOutlineLayer;
1391  else
1392  include = aFilterOptions.includeItemsOnTechLayers;
1393  break;
1394  }
1395  case PCB_TEXT_T:
1396  {
1397  include = aFilterOptions.includePcbTexts;
1398  break;
1399  }
1400  default:
1401  {
1402  // no filtering, just select it
1403  break;
1404  }
1405  }
1406  }
1407 
1408  return include;
1409 }
1410 
1411 
1413 {
1414  const BOARD& board = *getModel<BOARD>();
1415  DIALOG_FILTER_SELECTION::OPTIONS& opts = m_priv->m_filterOpts;
1416  DIALOG_FILTER_SELECTION dlg( m_frame, opts );
1417 
1418  const int cmd = dlg.ShowModal();
1419 
1420  if( cmd != wxID_OK )
1421  return 0;
1422 
1423  // copy current selection
1424  std::deque<EDA_ITEM*> selection = m_selection.GetItems();
1425 
1426  ClearSelection( true /*quiet mode*/ );
1427 
1428  // re-select items from the saved selection according to the dialog options
1429  for( EDA_ITEM* i : selection )
1430  {
1431  BOARD_ITEM* item = static_cast<BOARD_ITEM*>( i );
1432  bool include = itemIsIncludedByFilter( *item, board, opts );
1433 
1434  if( include )
1435  select( item );
1436  }
1437 
1439 
1440  return 0;
1441 }
1442 
1443 
1445 {
1446  if( aCollector.GetCount() == 0 )
1447  return;
1448 
1449  std::set<BOARD_ITEM*> rejected;
1450 
1451  for( EDA_ITEM* i : aCollector )
1452  {
1453  BOARD_ITEM* item = static_cast<BOARD_ITEM*>( i );
1454 
1455  if( !itemPassesFilter( item ) )
1456  rejected.insert( item );
1457  }
1458 
1459  for( BOARD_ITEM* item : rejected )
1460  aCollector.Remove( item );
1461 }
1462 
1463 
1465 {
1466  if( aItem->IsLocked() && !m_filter.lockedItems )
1467  return false;
1468 
1469  switch( aItem->Type() )
1470  {
1471  case PCB_MODULE_T:
1472  if( !m_filter.footprints )
1473  return false;
1474 
1475  break;
1476 
1477  case PCB_PAD_T:
1478  if( !m_filter.pads )
1479  return false;
1480 
1481  break;
1482 
1483  case PCB_TRACE_T:
1484  case PCB_ARC_T:
1485  if( !m_filter.tracks )
1486  return false;
1487 
1488  break;
1489 
1490  case PCB_VIA_T:
1491  if( !m_filter.vias )
1492  return false;
1493 
1494  break;
1495 
1496  case PCB_ZONE_AREA_T:
1497  {
1498  ZONE_CONTAINER* zone = static_cast<ZONE_CONTAINER*>( aItem );
1499 
1500  if( ( !m_filter.zones && !zone->GetIsRuleArea() )
1501  || ( !m_filter.keepouts && zone->GetIsRuleArea() ) )
1502  {
1503  return false;
1504  }
1505 
1506  break;
1507  }
1508  case PCB_LINE_T:
1509  case PCB_TARGET_T:
1510  if( !m_filter.graphics )
1511  return false;
1512 
1513  break;
1514 
1515  case PCB_MODULE_TEXT_T:
1516  case PCB_TEXT_T:
1517  if( !m_filter.text )
1518  return false;
1519 
1520  break;
1521 
1522  case PCB_DIM_ALIGNED_T:
1523  case PCB_DIM_CENTER_T:
1524  case PCB_DIM_ORTHOGONAL_T:
1525  case PCB_DIM_LEADER_T:
1526  if( !m_filter.dimensions )
1527  return false;
1528 
1529  break;
1530 
1531  default:
1532  if( !m_filter.otherItems )
1533  return false;
1534  }
1535 
1536  if( m_enteredGroup != NULL )
1537  {
1538  return m_enteredGroup->GetItems().find( aItem ) != m_enteredGroup->GetItems().end();
1539  }
1540 
1541  return true;
1542 }
1543 
1544 
1545 void SELECTION_TOOL::ClearSelection( bool aQuietMode )
1546 {
1547  if( m_selection.Empty() )
1548  return;
1549 
1550  while( m_selection.GetSize() )
1551  unhighlight( static_cast<BOARD_ITEM*>( m_selection.Front() ), SELECTED, &m_selection );
1552 
1553  view()->Update( &m_selection );
1554 
1555  m_selection.SetIsHover( false );
1557 
1558  m_locked = true;
1559 
1560  // Inform other potentially interested tools
1561  if( !aQuietMode )
1562  {
1565  }
1566 }
1567 
1568 
1570 {
1571  m_selection.Clear();
1572 
1573  INSPECTOR_FUNC inspector = [&] ( EDA_ITEM* item, void* testData )
1574  {
1575  if( item->IsSelected() )
1576  {
1577  EDA_ITEM* parent = item->GetParent();
1578 
1579  // Flags on module children might be set only because the parent is selected.
1580  if( parent && parent->Type() == PCB_MODULE_T && parent->IsSelected() )
1581  return SEARCH_RESULT::CONTINUE;
1582 
1583  highlight( (BOARD_ITEM*) item, SELECTED, &m_selection );
1584  }
1585 
1586  return SEARCH_RESULT::CONTINUE;
1587  };
1588 
1589  board()->Visit( inspector, nullptr, m_editModules ? GENERAL_COLLECTOR::ModuleItems
1591 }
1592 
1593 
1595 {
1596  GENERAL_COLLECTOR* collector = aEvent.Parameter<GENERAL_COLLECTOR*>();
1597 
1598  doSelectionMenu( collector, wxEmptyString );
1599 
1600  return 0;
1601 }
1602 
1603 
1604 bool SELECTION_TOOL::doSelectionMenu( GENERAL_COLLECTOR* aCollector, const wxString& aTitle )
1605 {
1606  BOARD_ITEM* current = nullptr;
1607  PCBNEW_SELECTION highlightGroup;
1608  bool selectAll = false;
1609  bool expandSelection = false;
1610 
1611  highlightGroup.SetLayer( LAYER_SELECT_OVERLAY );
1612  getView()->Add( &highlightGroup );
1613 
1614  do
1615  {
1617  if( expandSelection )
1618  aCollector->Combine();
1619 
1620  expandSelection = false;
1621 
1622  int limit = std::min( 9, aCollector->GetCount() );
1623  ACTION_MENU menu( true );
1624 
1625  for( int i = 0; i < limit; ++i )
1626  {
1627  wxString text;
1628  BOARD_ITEM* item = ( *aCollector )[i];
1629  text = item->GetSelectMenuText( m_frame->GetUserUnits() );
1630 
1631  wxString menuText = wxString::Format( "&%d. %s\t%d", i + 1, text, i + 1 );
1632  menu.Add( menuText, i + 1, item->GetMenuImage() );
1633  }
1634 
1635  menu.AppendSeparator();
1636  menu.Add( _( "Select &All\tA" ), limit + 1, net_highlight_xpm );
1637 
1638  if( !expandSelection && aCollector->HasAdditionalItems() )
1639  menu.Add( _( "&Expand Selection\tE" ), limit + 2, nullptr );
1640 
1641  if( aTitle.Length() )
1642  {
1643  menu.SetTitle( aTitle );
1644  menu.SetIcon( info_xpm );
1645  menu.DisplayTitle( true );
1646  }
1647  else
1648  menu.DisplayTitle( false );
1649 
1650  SetContextMenu( &menu, CMENU_NOW );
1651 
1652  while( TOOL_EVENT* evt = Wait() )
1653  {
1654  if( evt->Action() == TA_CHOICE_MENU_UPDATE )
1655  {
1656  if( selectAll )
1657  {
1658  for( int i = 0; i < aCollector->GetCount(); ++i )
1659  unhighlight( ( *aCollector )[i], BRIGHTENED, &highlightGroup );
1660  }
1661  else if( current )
1662  unhighlight( current, BRIGHTENED, &highlightGroup );
1663 
1664  int id = *evt->GetCommandId();
1665 
1666  // User has pointed an item, so show it in a different way
1667  if( id > 0 && id <= limit )
1668  {
1669  current = ( *aCollector )[id - 1];
1670  highlight( current, BRIGHTENED, &highlightGroup );
1671  }
1672  else
1673  current = nullptr;
1674 
1675  // User has pointed on the "Select All" option
1676  if( id == limit + 1 )
1677  {
1678  for( int i = 0; i < aCollector->GetCount(); ++i )
1679  highlight( ( *aCollector )[i], BRIGHTENED, &highlightGroup );
1680  selectAll = true;
1681  }
1682  else
1683  selectAll = false;
1684  }
1685  else if( evt->Action() == TA_CHOICE_MENU_CHOICE )
1686  {
1687  if( selectAll )
1688  {
1689  for( int i = 0; i < aCollector->GetCount(); ++i )
1690  unhighlight( ( *aCollector )[i], BRIGHTENED, &highlightGroup );
1691  }
1692  else if( current )
1693  unhighlight( current, BRIGHTENED, &highlightGroup );
1694 
1695  OPT<int> id = evt->GetCommandId();
1696 
1697  // User has selected the "Select All" option
1698  if( id == limit + 1 )
1699  {
1700  selectAll = true;
1701  current = nullptr;
1702  }
1703  else if( id == limit + 2 )
1704  {
1705  expandSelection = true;
1706  selectAll = false;
1707  current = nullptr;
1708  }
1709  // User has selected an item, so this one will be returned
1710  else if( id && ( *id > 0 ) && ( *id <= limit ) )
1711  {
1712  selectAll = false;
1713  current = ( *aCollector )[*id - 1];
1714  }
1715  else
1716  {
1717  selectAll = false;
1718  current = nullptr;
1719  }
1720  }
1721  else if( evt->Action() == TA_CHOICE_MENU_CLOSED )
1722  {
1723  break;
1724  }
1725  }
1726  } while( expandSelection );
1727 
1728  getView()->Remove( &highlightGroup );
1729 
1730  if( selectAll )
1731  return true;
1732  else if( current )
1733  {
1734  aCollector->Empty();
1735  aCollector->Append( current );
1736  return true;
1737  }
1738 
1739  return false;
1740 }
1741 
1742 
1744 {
1745  int count = aCollector->GetPrimaryCount(); // try to use preferred layer
1746 
1747  if( 0 == count )
1748  count = aCollector->GetCount();
1749 
1750  for( int i = 0; i < count; ++i )
1751  {
1752  if( ( *aCollector )[i]->Type() != PCB_MODULE_T )
1753  return NULL;
1754  }
1755 
1756  // All are modules, now find smallest MODULE
1757  int minDim = 0x7FFFFFFF;
1758  int minNdx = 0;
1759 
1760  for( int i = 0; i < count; ++i )
1761  {
1762  MODULE* module = (MODULE*) ( *aCollector )[i];
1763 
1764  int lx = module->GetFootprintRect().GetWidth();
1765  int ly = module->GetFootprintRect().GetHeight();
1766 
1767  int lmin = std::min( lx, ly );
1768 
1769  if( lmin < minDim )
1770  {
1771  minDim = lmin;
1772  minNdx = i;
1773  }
1774  }
1775 
1776  return (*aCollector)[minNdx];
1777 }
1778 
1779 
1780 bool SELECTION_TOOL::Selectable( const BOARD_ITEM* aItem, bool checkVisibilityOnly ) const
1781 {
1782  const RENDER_SETTINGS* settings = getView()->GetPainter()->GetSettings();
1783 
1784  if( settings->GetHighContrast() )
1785  {
1786  std::set<unsigned int> activeLayers = settings->GetActiveLayers();
1787  bool onActiveLayer = false;
1788 
1789  for( unsigned int layer : activeLayers )
1790  {
1791  // NOTE: Only checking the regular layers (not GAL meta-layers)
1792  if( layer < PCB_LAYER_ID_COUNT && aItem->IsOnLayer( ToLAYER_ID( layer ) ) )
1793  {
1794  onActiveLayer = true;
1795  break;
1796  }
1797  }
1798 
1799  if( !onActiveLayer ) // We do not want to select items that are in the background
1800  return false;
1801  }
1802 
1803  switch( aItem->Type() )
1804  {
1805  case PCB_ZONE_AREA_T:
1807  {
1808  const ZONE_CONTAINER* zone = static_cast<const ZONE_CONTAINER*>( aItem );
1809 
1810  // Check to see if this keepout is part of a footprint
1811  // If it is, and we are not editing the footprint, it should not be selectable
1812  bool zoneInFootprint = zone->GetParent() && zone->GetParent()->Type() == PCB_MODULE_T;
1813 
1814  if( zoneInFootprint && !m_editModules && !checkVisibilityOnly )
1815  return false;
1816 
1817  // zones can exist on multiple layers!
1818  return ( zone->GetLayerSet() & board()->GetVisibleLayers() ).any();
1819  }
1820  break;
1821 
1822  case PCB_TRACE_T:
1823  case PCB_ARC_T:
1824  if( !board()->IsElementVisible( LAYER_TRACKS ) )
1825  return false;
1826  break;
1827 
1828  case PCB_VIA_T:
1829  {
1830  if( !board()->IsElementVisible( LAYER_VIAS ) )
1831  return false;
1832 
1833  const VIA* via = static_cast<const VIA*>( aItem );
1834 
1835  // For vias it is enough if only one of its layers is visible
1836  return ( board()->GetVisibleLayers() & via->GetLayerSet() ).any();
1837  }
1838 
1839  case PCB_MODULE_T:
1840  {
1841  // In modedit, we do not want to select the module itself.
1842  if( m_editModules )
1843  return false;
1844 
1845  // Allow selection of footprints if some part of the footprint is visible.
1846 
1847  MODULE* module = const_cast<MODULE*>( static_cast<const MODULE*>( aItem ) );
1848 
1849  for( BOARD_ITEM* item : module->GraphicalItems() )
1850  {
1851  if( Selectable( item, true ) )
1852  return true;
1853  }
1854 
1855  for( D_PAD* pad : module->Pads() )
1856  {
1857  if( Selectable( pad, true ) )
1858  return true;
1859  }
1860 
1861  for( ZONE_CONTAINER* zone : module->Zones() )
1862  {
1863  if( Selectable( zone, true ) )
1864  return true;
1865  }
1866 
1867  return false;
1868  }
1869 
1870  case PCB_MODULE_TEXT_T:
1871  // Multiple selection is only allowed in modedit mode. In pcbnew, you have to select
1872  // module subparts one by one, rather than with a drag selection. This is so you can
1873  // pick up items under an (unlocked) module without also moving the module's sub-parts.
1874  if( !m_editModules && !checkVisibilityOnly )
1875  {
1876  if( m_multiple && !settings->GetHighContrast() )
1877  return false;
1878  }
1879 
1880  if( !m_editModules && !view()->IsVisible( aItem ) )
1881  return false;
1882 
1883  break;
1884 
1885  case PCB_MODULE_EDGE_T:
1886  // Module edge selections are only allowed in modedit mode.
1887  if( !m_editModules && !checkVisibilityOnly )
1888  return false;
1889 
1890  break;
1891 
1892  case PCB_PAD_T:
1893  {
1894  // Multiple selection is only allowed in modedit mode. In pcbnew, you have to select
1895  // module subparts one by one, rather than with a drag selection. This is so you can
1896  // pick up items under an (unlocked) module without also moving the module's sub-parts.
1897  if( !m_editModules && !checkVisibilityOnly )
1898  {
1899  if( m_multiple )
1900  return false;
1901  }
1902 
1903  if( aItem->Type() == PCB_PAD_T )
1904  {
1905  auto pad = static_cast<const D_PAD*>( aItem );
1906 
1907  // In pcbnew, locked modules prevent individual pad selection.
1908  // In modedit, we don't enforce this as the module is assumed to be edited by design.
1909  if( !m_editModules && !checkVisibilityOnly )
1910  {
1911  if( pad->GetParent() && pad->GetParent()->IsLocked() )
1912  return false;
1913  }
1914 
1915  // Check render mode (from the Items tab) first
1916  switch( pad->GetAttribute() )
1917  {
1918  case PAD_ATTRIB_STANDARD:
1920  if( !board()->IsElementVisible( LAYER_PADS_TH ) )
1921  return false;
1922  break;
1923 
1924  case PAD_ATTRIB_CONN:
1925  case PAD_ATTRIB_SMD:
1926  if( pad->IsOnLayer( F_Cu ) && !board()->IsElementVisible( LAYER_PAD_FR ) )
1927  return false;
1928  else if( pad->IsOnLayer( B_Cu ) && !board()->IsElementVisible( LAYER_PAD_BK ) )
1929  return false;
1930  break;
1931  }
1932 
1933  // Otherwise, pads are selectable if any draw layer is visible
1934  return ( pad->GetLayerSet() & board()->GetVisibleLayers() ).any();
1935  }
1936 
1937  break;
1938  }
1939 
1940  case PCB_GROUP_T:
1941  {
1942  PCB_GROUP* group = const_cast<PCB_GROUP*>( static_cast<const PCB_GROUP*>( aItem ) );
1943 
1944  // Similar to logic for module, a group is selectable if any of its
1945  // members are. (This recurses)
1946  for( BOARD_ITEM* item : group->GetItems() )
1947  {
1948  if( Selectable( item, true ) )
1949  return true;
1950  }
1951 
1952  return false;
1953  }
1954 
1955  case PCB_MARKER_T: // Always selectable
1956  return true;
1957 
1958  // These are not selectable
1959  case PCB_NETINFO_T:
1960  case NOT_USED:
1961  case TYPE_NOT_INIT:
1962  return false;
1963 
1964  default: // Suppress warnings
1965  break;
1966  }
1967 
1968  // All other items are selected only if the layer on which they exist is visible
1969  return board()->IsLayerVisible( aItem->GetLayer() )
1970  && aItem->ViewGetLOD( aItem->GetLayer(), view() ) < view()->GetScale();
1971 }
1972 
1973 
1975 {
1976  if( aItem->IsSelected() )
1977  {
1978  return;
1979  }
1980 
1981  if( aItem->Type() == PCB_PAD_T )
1982  {
1983  MODULE* module = static_cast<MODULE*>( aItem->GetParent() );
1984 
1985  if( m_selection.Contains( module ) )
1986  return;
1987  }
1988 
1989  highlight( aItem, SELECTED, &m_selection );
1990 }
1991 
1992 
1994 {
1995  unhighlight( aItem, SELECTED, &m_selection );
1996 
1997  if( m_selection.Empty() )
1998  m_locked = true;
1999 }
2000 
2001 void SELECTION_TOOL::highlight( BOARD_ITEM* aItem, int aMode, PCBNEW_SELECTION* aGroup )
2002 {
2003  highlightInternal( aItem, aMode, aGroup, false );
2004 
2005  view()->Update( aItem );
2006 
2007  // Many selections are very temporal and updating the display each time just
2008  // creates noise.
2009  if( aMode == BRIGHTENED )
2011 }
2012 
2013 void SELECTION_TOOL::highlightInternal( BOARD_ITEM* aItem, int aMode, PCBNEW_SELECTION* aGroup, bool isChild )
2014 {
2015  wxLogTrace( "GRP", wxString::Format( "highlight() of %s %p",
2016  aItem->GetSelectMenuText( m_frame->GetUserUnits() ) ), aItem );
2017  if( aMode == SELECTED )
2018  aItem->SetSelected();
2019  else if( aMode == BRIGHTENED )
2020  aItem->SetBrightened();
2021 
2022  if( aGroup )
2023  {
2024  // Hide the original item, so it is shown only on overlay
2025  view()->Hide( aItem, true );
2026 
2027  if( !isChild || aMode == BRIGHTENED )
2028  aGroup->Add( aItem );
2029  }
2030 
2031  // Modules are treated in a special way - when they are highlighted, we have to
2032  // highlight all the parts that make the module, not the module itself
2033  if( aItem->Type() == PCB_MODULE_T )
2034  {
2035  static_cast<MODULE*>( aItem )->RunOnChildren( [&]( BOARD_ITEM* titem ) {
2036  highlightInternal( titem, aMode, aGroup, true ); } );
2037  }
2038  else if( aItem->Type() == PCB_GROUP_T )
2039  {
2040  static_cast<PCB_GROUP*>( aItem )->RunOnChildren( [&]( BOARD_ITEM* titem ) {
2041  highlightInternal( titem, aMode, aGroup, true ); } );
2042  }
2043 }
2044 
2045 
2046 void SELECTION_TOOL::unhighlight( BOARD_ITEM* aItem, int aMode, PCBNEW_SELECTION* aGroup )
2047 {
2048  unhighlightInternal( aItem, aMode, aGroup, false );
2049 
2050  view()->Update( aItem );
2051 
2052  // Many selections are very temporal and updating the display each time just
2053  // creates noise.
2054  if( aMode == BRIGHTENED )
2056 }
2057 
2058 
2059 void SELECTION_TOOL::unhighlightInternal( BOARD_ITEM* aItem, int aMode, PCBNEW_SELECTION* aGroup, bool isChild )
2060 {
2061  wxLogTrace( "GRP", wxString::Format( "unhighlight() of %s %p",
2062  aItem->GetSelectMenuText( m_frame->GetUserUnits() ) ), aItem );
2063  if( aMode == SELECTED )
2064  aItem->ClearSelected();
2065  else if( aMode == BRIGHTENED )
2066  aItem->ClearBrightened();
2067 
2068  if( aGroup )
2069  {
2070  aGroup->Remove( aItem );
2071 
2072  // Restore original item visibility
2073  view()->Hide( aItem, false );
2074 
2075  // N.B. if we clear the selection flag for sub-elements, we need to also
2076  // remove the element from the selection group (if it exists)
2077  if( isChild )
2078  view()->Update( aItem );
2079  }
2080 
2081  // Modules are treated in a special way - when they are highlighted, we have to
2082  // highlight all the parts that make the module, not the module itself
2083  if( aItem->Type() == PCB_MODULE_T )
2084  {
2085  static_cast<MODULE*>( aItem )->RunOnChildren( [&]( BOARD_ITEM* titem ) {
2086  unhighlightInternal( titem, aMode, aGroup, true ); } );
2087  }
2088  else if( aItem->Type() == PCB_GROUP_T )
2089  {
2090  static_cast<PCB_GROUP*>( aItem )->RunOnChildren( [&]( BOARD_ITEM* titem ) {
2091  unhighlightInternal( titem, aMode, aGroup, true ); } );
2092  }
2093 }
2094 
2095 
2096 bool SELECTION_TOOL::selectionContains( const VECTOR2I& aPoint ) const
2097 {
2098  const unsigned GRIP_MARGIN = 20;
2099  VECTOR2I margin = getView()->ToWorld( VECTOR2I( GRIP_MARGIN, GRIP_MARGIN ), false );
2100 
2101  // Check if the point is located within any of the currently selected items bounding boxes
2102  for( auto item : m_selection )
2103  {
2104  BOX2I itemBox = item->ViewBBox();
2105  itemBox.Inflate( margin.x, margin.y ); // Give some margin for gripping an item
2106 
2107  if( itemBox.Contains( aPoint ) )
2108  return true;
2109  }
2110 
2111  return false;
2112 }
2113 
2114 
2115 static EDA_RECT getRect( const BOARD_ITEM* aItem )
2116 {
2117  if( aItem->Type() == PCB_MODULE_T )
2118  return static_cast<const MODULE*>( aItem )->GetFootprintRect();
2119 
2120  return aItem->GetBoundingBox();
2121 }
2122 
2123 
2124 static double calcArea( const BOARD_ITEM* aItem )
2125 {
2126  if( aItem->Type() == PCB_TRACE_T )
2127  {
2128  const TRACK* t = static_cast<const TRACK*>( aItem );
2129  return ( t->GetWidth() + t->GetLength() ) * t->GetWidth();
2130  }
2131 
2132  return getRect( aItem ).GetArea();
2133 }
2134 
2135 
2136 /*static double calcMinArea( GENERAL_COLLECTOR& aCollector, KICAD_T aType )
2137 {
2138  double best = std::numeric_limits<double>::max();
2139 
2140  if( !aCollector.GetCount() )
2141  return 0.0;
2142 
2143  for( int i = 0; i < aCollector.GetCount(); i++ )
2144  {
2145  BOARD_ITEM* item = aCollector[i];
2146  if( item->Type() == aType )
2147  best = std::min( best, calcArea( item ) );
2148  }
2149 
2150  return best;
2151 }*/
2152 
2153 
2154 static double calcMaxArea( GENERAL_COLLECTOR& aCollector, KICAD_T aType )
2155 {
2156  double best = 0.0;
2157 
2158  for( int i = 0; i < aCollector.GetCount(); i++ )
2159  {
2160  BOARD_ITEM* item = aCollector[i];
2161  if( item->Type() == aType )
2162  best = std::max( best, calcArea( item ) );
2163  }
2164 
2165  return best;
2166 }
2167 
2168 
2169 static inline double calcCommonArea( const BOARD_ITEM* aItem, const BOARD_ITEM* aOther )
2170 {
2171  if( !aItem || !aOther )
2172  return 0;
2173 
2174  return getRect( aItem ).Common( getRect( aOther ) ).GetArea();
2175 }
2176 
2177 
2178 double calcRatio( double a, double b )
2179 {
2180  if( a == 0.0 && b == 0.0 )
2181  return 1.0;
2182 
2183  if( b == 0.0 )
2184  return std::numeric_limits<double>::max();
2185 
2186  return a / b;
2187 }
2188 
2189 
2190 // The general idea here is that if the user clicks directly on a small item inside a larger
2191 // one, then they want the small item. The quintessential case of this is clicking on a pad
2192 // within a footprint, but we also apply it for text within a footprint, footprints within
2193 // larger footprints, and vias within either larger pads or longer tracks.
2194 //
2195 // These "guesses" presume there is area within the larger item to click in to select it. If
2196 // an item is mostly covered by smaller items within it, then the guesses are inappropriate as
2197 // there might not be any area left to click to select the larger item. In this case we must
2198 // leave the items in the collector and bring up a Selection Clarification menu.
2199 //
2200 // We currently check for pads and text mostly covering a footprint, but we don’t check for
2201 // smaller footprints mostly covering a larger footprint.
2202 //
2204  const VECTOR2I& aWhere ) const
2205 {
2206  std::set<BOARD_ITEM*> preferred;
2207  std::set<BOARD_ITEM*> rejected;
2208  std::set<BOARD_ITEM*> forced;
2209  wxPoint where( aWhere.x, aWhere.y );
2210 
2211  // footprints which are below this percentage of the largest footprint will be considered
2212  // for selection; all others will not
2213  constexpr double footprintToFootprintMinRatio = 0.20;
2214  // pads which are below this percentage of their parent's area will exclude their parent
2215  constexpr double padToFootprintMinRatio = 0.45;
2216  // footprints containing items with items-to-footprint area ratio higher than this will be
2217  // forced to stay on the list
2218  constexpr double footprintMaxCoverRatio = 0.90;
2219  constexpr double viaToPadMinRatio = 0.50;
2220  constexpr double trackViaLengthRatio = 2.0;
2221  constexpr double trackTrackLengthRatio = 0.3;
2222  constexpr double textToFeatureMinRatio = 0.2;
2223  constexpr double textToFootprintMinRatio = 0.4;
2224  // If the common area of two compared items is above the following threshold, they cannot
2225  // be rejected (it means they overlap and it might be hard to pick one by selecting
2226  // its unique area).
2227  constexpr double commonAreaRatio = 0.6;
2228 
2229  PCB_LAYER_ID activeLayer = (PCB_LAYER_ID) view()->GetTopLayer();
2230  LSET silkLayers( 2, B_SilkS, F_SilkS );
2231 
2232  if( silkLayers[activeLayer] )
2233  {
2234  for( int i = 0; i < aCollector.GetCount(); ++i )
2235  {
2236  BOARD_ITEM* item = aCollector[i];
2237  KICAD_T type = item->Type();
2238 
2239  if( ( type == PCB_MODULE_TEXT_T || type == PCB_TEXT_T || type == PCB_LINE_T )
2240  && silkLayers[item->GetLayer()] )
2241  {
2242  preferred.insert( item );
2243  }
2244  }
2245 
2246  if( preferred.size() > 0 )
2247  {
2248  aCollector.Empty();
2249 
2250  for( BOARD_ITEM* item : preferred )
2251  aCollector.Append( item );
2252  return;
2253  }
2254  }
2255 
2256  // Zone edges are very specific; zone fills much less so.
2257  if( aCollector.CountType( PCB_ZONE_AREA_T ) > 0 )
2258  {
2259  for( int i = aCollector.GetCount() - 1; i >= 0; i-- )
2260  {
2261  if( aCollector[i]->Type() == PCB_ZONE_AREA_T )
2262  {
2263  auto zone = static_cast<ZONE_CONTAINER*>( aCollector[i] );
2264 
2265  if( zone->HitTestForEdge( where, 5 * aCollector.GetGuide()->OnePixelInIU() ) )
2266  preferred.insert( zone );
2267  else
2268  rejected.insert( zone );
2269  }
2270  }
2271 
2272  if( preferred.size() > 0 )
2273  {
2274  aCollector.Empty();
2275 
2276  for( BOARD_ITEM* item : preferred )
2277  aCollector.Append( item );
2278  return;
2279  }
2280  }
2281 
2282  if( aCollector.CountType( PCB_MODULE_TEXT_T ) > 0 )
2283  {
2284  for( int i = 0; i < aCollector.GetCount(); ++i )
2285  {
2286  if( TEXTE_MODULE* txt = dyn_cast<TEXTE_MODULE*>( aCollector[i] ) )
2287  {
2288  double textArea = calcArea( txt );
2289 
2290  for( int j = 0; j < aCollector.GetCount(); ++j )
2291  {
2292  if( i == j )
2293  continue;
2294 
2295  BOARD_ITEM* item = aCollector[j];
2296  double itemArea = calcArea( item );
2297  double areaRatio = calcRatio( textArea, itemArea );
2298  double commonArea = calcCommonArea( txt, item );
2299  double itemCommonRatio = calcRatio( commonArea, itemArea );
2300  double txtCommonRatio = calcRatio( commonArea, textArea );
2301 
2302  if( item->Type() == PCB_MODULE_T )
2303  {
2304  // when text area is small compared to an overlapping footprint,
2305  // then it's a clear sign the text is the selection target
2306  if( areaRatio < textToFootprintMinRatio && itemCommonRatio < commonAreaRatio )
2307  rejected.insert( item );
2308  }
2309 
2310  switch( item->Type() )
2311  {
2312  case PCB_TRACE_T:
2313  case PCB_ARC_T:
2314  case PCB_PAD_T:
2315  case PCB_LINE_T:
2316  case PCB_VIA_T:
2317  case PCB_MODULE_T:
2318  if( areaRatio > textToFeatureMinRatio && txtCommonRatio < commonAreaRatio )
2319  rejected.insert( txt );
2320  break;
2321  default:
2322  break;
2323  }
2324  }
2325  }
2326  }
2327  }
2328 
2329  if( aCollector.CountType( PCB_MODULE_EDGE_T ) + aCollector.CountType( PCB_LINE_T ) > 1 )
2330  {
2331  // Prefer exact hits to sloppy ones
2332  int accuracy = KiROUND( 5 * aCollector.GetGuide()->OnePixelInIU() );
2333  bool found = false;
2334 
2335  for( int dist = 0; dist < accuracy; ++dist )
2336  {
2337  for( int i = 0; i < aCollector.GetCount(); ++i )
2338  {
2339  if( DRAWSEGMENT* drawSegment = dynamic_cast<DRAWSEGMENT*>( aCollector[i] ) )
2340  {
2341  if( drawSegment->HitTest( where, dist ) )
2342  {
2343  found = true;
2344  break;
2345  }
2346  }
2347  }
2348 
2349  if( found )
2350  {
2351  // throw out everything that is more sloppy than what we found
2352  for( int i = 0; i < aCollector.GetCount(); ++i )
2353  {
2354  if( DRAWSEGMENT* drawSegment = dynamic_cast<DRAWSEGMENT*>( aCollector[i] ) )
2355  {
2356  if( !drawSegment->HitTest( where, dist ) )
2357  rejected.insert( drawSegment );
2358  }
2359  }
2360 
2361  // we're done now
2362  break;
2363  }
2364  }
2365  }
2366 
2367  if( aCollector.CountType( PCB_PAD_T ) > 0 )
2368  {
2369  for( int i = 0; i < aCollector.GetCount(); ++i )
2370  {
2371  if( D_PAD* pad = dyn_cast<D_PAD*>( aCollector[i] ) )
2372  {
2373  MODULE* parent = pad->GetParent();
2374  double ratio = calcRatio( calcArea( pad ), calcArea( parent ) );
2375 
2376  // when pad area is small compared to the parent footprint,
2377  // then it is a clear sign the pad is the selection target
2378  if( ratio < padToFootprintMinRatio )
2379  rejected.insert( pad->GetParent() );
2380  }
2381  }
2382  }
2383 
2384  bool hasNonModules = false;
2385 
2386  for( int i = 0; i < aCollector.GetCount(); ++i )
2387  {
2388  if( aCollector[i]->Type() != PCB_MODULE_T )
2389  {
2390  hasNonModules = true;
2391  break;
2392  }
2393  }
2394 
2395  if( aCollector.CountType( PCB_MODULE_T ) > 0 )
2396  {
2397  double maxArea = calcMaxArea( aCollector, PCB_MODULE_T );
2398  BOX2D viewportD = getView()->GetViewport();
2399  BOX2I viewport( VECTOR2I( viewportD.GetPosition() ), VECTOR2I( viewportD.GetSize() ) );
2400  double maxCoverRatio = footprintMaxCoverRatio;
2401 
2402  // MODULE::CoverageRatio() doesn't take zone handles & borders into account so just
2403  // use a more aggressive cutoff point if zones are involved.
2404  if( aCollector.CountType( PCB_ZONE_AREA_T ) )
2405  maxCoverRatio /= 2;
2406 
2407  for( int i = 0; i < aCollector.GetCount(); ++i )
2408  {
2409  if( MODULE* mod = dyn_cast<MODULE*>( aCollector[i] ) )
2410  {
2411  // filter out components larger than the viewport
2412  if( mod->ViewBBox().GetHeight() > viewport.GetHeight() ||
2413  mod->ViewBBox().GetWidth() > viewport.GetWidth() )
2414  rejected.insert( mod );
2415  // footprints completely covered with other features have no other
2416  // means of selection, so must be kept
2417  else if( mod->CoverageRatio( aCollector ) > maxCoverRatio )
2418  rejected.erase( mod );
2419  // if a footprint is much smaller than the largest overlapping
2420  // footprint then it should be considered for selection
2421  else if( calcRatio( calcArea( mod ), maxArea ) <= footprintToFootprintMinRatio )
2422  continue;
2423  // reject ALL OTHER footprints if there's still something else left
2424  // to select
2425  else if( hasNonModules )
2426  rejected.insert( mod );
2427  }
2428  }
2429  }
2430 
2431  if( aCollector.CountType( PCB_VIA_T ) > 0 )
2432  {
2433  for( int i = 0; i < aCollector.GetCount(); ++i )
2434  {
2435  if( VIA* via = dyn_cast<VIA*>( aCollector[i] ) )
2436  {
2437  double viaArea = calcArea( via );
2438 
2439  for( int j = 0; j < aCollector.GetCount(); ++j )
2440  {
2441  if( i == j )
2442  continue;
2443 
2444  BOARD_ITEM* item = aCollector[j];
2445  double areaRatio = calcRatio( viaArea, calcArea( item ) );
2446 
2447  if( item->Type() == PCB_MODULE_T && areaRatio < padToFootprintMinRatio )
2448  rejected.insert( item );
2449 
2450  if( item->Type() == PCB_PAD_T && areaRatio < viaToPadMinRatio )
2451  rejected.insert( item );
2452 
2453  if( TRACK* track = dyn_cast<TRACK*>( item ) )
2454  {
2455  if( track->GetNetCode() != via->GetNetCode() )
2456  continue;
2457 
2458  double lenRatio = (double) ( track->GetLength() + track->GetWidth() ) /
2459  (double) via->GetWidth();
2460 
2461  if( lenRatio > trackViaLengthRatio )
2462  rejected.insert( track );
2463  }
2464  }
2465  }
2466  }
2467  }
2468 
2469  int nTracks = aCollector.CountType( PCB_TRACE_T );
2470 
2471  if( nTracks > 0 )
2472  {
2473  double maxLength = 0.0;
2474  double minLength = std::numeric_limits<double>::max();
2475  double maxArea = 0.0;
2476  const TRACK* maxTrack = nullptr;
2477 
2478  for( int i = 0; i < aCollector.GetCount(); ++i )
2479  {
2480  if( TRACK* track = dyn_cast<TRACK*>( aCollector[i] ) )
2481  {
2482  maxLength = std::max( track->GetLength(), maxLength );
2483  maxLength = std::max( (double) track->GetWidth(), maxLength );
2484 
2485  minLength = std::min( std::max( track->GetLength(), (double) track->GetWidth() ), minLength );
2486 
2487  double area = track->GetLength() * track->GetWidth();
2488 
2489  if( area > maxArea )
2490  {
2491  maxArea = area;
2492  maxTrack = track;
2493  }
2494  }
2495  }
2496 
2497  if( maxLength > 0.0 && minLength / maxLength < trackTrackLengthRatio && nTracks > 1 )
2498  {
2499  for( int i = 0; i < aCollector.GetCount(); ++i )
2500  {
2501  if( TRACK* track = dyn_cast<TRACK*>( aCollector[i] ) )
2502  {
2503  double ratio = std::max( (double) track->GetWidth(), track->GetLength() ) / maxLength;
2504 
2505  if( ratio > trackTrackLengthRatio )
2506  rejected.insert( track );
2507  }
2508  }
2509  }
2510 
2511  for( int j = 0; j < aCollector.GetCount(); ++j )
2512  {
2513  if( MODULE* mod = dyn_cast<MODULE*>( aCollector[j] ) )
2514  {
2515  double ratio = calcRatio( maxArea, mod->GetFootprintRect().GetArea() );
2516 
2517  if( ratio < padToFootprintMinRatio && calcCommonArea( maxTrack, mod ) < commonAreaRatio )
2518  rejected.insert( mod );
2519  }
2520  }
2521  }
2522 
2523  if( (unsigned) aCollector.GetCount() > rejected.size() ) // do not remove everything
2524  {
2525  for( BOARD_ITEM* item : rejected )
2526  {
2527  aCollector.Transfer( item );
2528  }
2529  }
2530 
2531  FilterCollectorForGroups( aCollector );
2532 }
2533 
2534 
2536 {
2537  std::unordered_set<BOARD_ITEM*> toAdd;
2538 
2539  // If any element is a member of a group, replace those elements with the top containing group.
2540  for( int j = 0; j < aCollector.GetCount(); ++j )
2541  {
2542  PCB_GROUP* aTop = board()->TopLevelGroup( aCollector[j], m_enteredGroup );
2543 
2544  if( aTop != NULL )
2545  {
2546  if( aTop != aCollector[j] )
2547  {
2548  toAdd.insert( aTop );
2549  aCollector.Remove( aCollector[j] );
2550  }
2551  }
2552  else if( m_enteredGroup != NULL &&
2553  m_enteredGroup->GetItems().find( aCollector[j] ) == m_enteredGroup->GetItems().end() )
2554  {
2555  // If a group is entered, no selections of objects not in the group.
2556  aCollector.Remove( aCollector[j] );
2557  }
2558  }
2559 
2560  for( BOARD_ITEM* item : toAdd )
2561  {
2562  if( !aCollector.HasItem( item ) )
2563  {
2564  aCollector.Append( item );
2565  }
2566  }
2567 }
2568 
2569 
2571 {
2572  getView()->Update( &m_selection );
2573 
2574  return 0;
2575 }
2576 
2577 
2579 {
2580  ACTION_MENU* actionMenu = aEvent.Parameter<ACTION_MENU*>();
2581  CONDITIONAL_MENU* conditionalMenu = dynamic_cast<CONDITIONAL_MENU*>( actionMenu );
2582 
2583  if( conditionalMenu )
2584  conditionalMenu->Evaluate( m_selection );
2585 
2586  if( actionMenu )
2587  actionMenu->UpdateAll();
2588 
2589  return 0;
2590 }
2591 
2592 
2594 {
2596 
2600 
2606 
2607  Go( &SELECTION_TOOL::find, ACTIONS::find.MakeEvent() );
2608 
2617 
2619 }
static TOOL_ACTION selectItems
Selects a list of items (specified as the event parameter)
Definition: pcb_actions.h:69
void Empty()
Function Empty sets the list to empty.
Definition: collector.h:110
static TOOL_ACTION selectionClear
Clears the current selection.
Definition: pcb_actions.h:62
static TOOL_ACTION selectionActivate
Activation of the selection tool.
Definition: pcb_actions.h:56
void GuessSelectionCandidates(GENERAL_COLLECTOR &aCollector, const VECTOR2I &aWhere) const
Function guessSelectionCandidates() Tries to guess best selection candidates in case multiple items a...
void Hide(VIEW_ITEM *aItem, bool aHide=true)
Temporarily hides the item in the view (e.g.
Definition: view.cpp:1498
void ClearReferencePoint()
Definition: selection.h:250
int UnselectItem(const TOOL_EVENT &aEvent)
Item unselection event handler.
int Main(const TOOL_EVENT &aEvent)
Function Main()
int UpdateMenu(const TOOL_EVENT &aEvent)
Pass the selection to a conditional menu for updating.
Filled polygons are shown.
void AddStandardSubMenus(TOOL_MENU &aMenu)
Function CreateBasicMenu.
void SetIgnoreTracks(bool ignore)
Definition: collectors.h:612
bool AddItem(BOARD_ITEM *aItem)
Adds item to group.
ZONE_CONTAINER handles a list of polygons defining a copper zone.
Definition: class_zone.h:61
void Reset(RESET_REASON aReason) override
Function Reset() Brings the tool to a known, initial state.
DIALOG_FILTER_SELECTION::OPTIONS m_filterOpts
static const TOOL_EVENT SelectedEvent
Definition: actions.h:206
void selectAllItemsOnSheet(wxString &aSheetPath)
Selects all items with the given sheet timestamp/UUID name (the sheet path) The path of the root shee...
BOX2D GetViewport() const
Function GetViewport() Returns the current viewport visible area rectangle.
Definition: view.cpp:537
void SetEnd(VECTOR2I aEnd)
Set the current end of the rectangle (the corner that moves with the cursor.
TOOL_MENU m_menu
functions below are not yet implemented - their interface may change
static TOOL_ACTION move
move or drag an item
Definition: pcb_actions.h:95
static EDA_RECT getRect(const BOARD_ITEM *aItem)
class ALIGNED_DIMENSION, a linear dimension (graphic item)
Definition: typeinfo.h:101
virtual void Clear() override
Function Clear() Removes all the stored items from the group.
Definition: selection.h:95
void ForceRefresh()
Function ForceRefresh() Forces a redraw.
int GetNetCode() const
Function GetNetCode.
class LEADER, a leader dimension (graphic item)
Definition: typeinfo.h:102
static double calcCommonArea(const BOARD_ITEM *aItem, const BOARD_ITEM *aOther)
int SelectAll(const TOOL_EVENT &aEvent)
Select all items on the board
bool otherItems
Anything not fitting one of the above categories.
std::function< SEARCH_RESULT(EDA_ITEM *aItem, void *aTestData) > INSPECTOR_FUNC
Typedef INSPECTOR is used to inspect and possibly collect the (search) results of iterating over a li...
Definition: base_struct.h:80
static TOOL_ACTION groupLeave
Definition: pcb_actions.h:412
static const KICAD_T AllBoardItems[]
A scan list for all editable board items.
Definition: collectors.h:267
void SetIgnoreBlindBuriedVias(bool ignore)
Definition: collectors.h:606
TOOL_EVENT * Wait(const TOOL_EVENT_LIST &aEventList=TOOL_EVENT(TC_ANY, TA_ANY))
Function Wait()
virtual LSET GetLayerSet() const override
Function GetLayerSet returns a std::bitset of all layers on which the item physically resides.
BOARD * board() const
std::unique_ptr< PRIV > m_priv
like PAD_STANDARD, but not plated mechanical use only, no connection allowed
Definition: pad_shapes.h:85
void selectAllItemsOnNet(int aNetCode, bool aSelect=true)
Selects all items with the given net code.
RENDER_SETTINGS Contains all the knowledge about how graphical objects are drawn on any output surfac...
bool IsSelected() const
Definition: base_struct.h:203
void RunOnChildren(const std::function< void(BOARD_ITEM *)> &aFunction)
Invokes a function on all members of the group.
Model changes (required full reload)
Definition: tool_base.h:82
multilayer pads, usually with holes
static const TOOL_EVENT UnselectedEvent
Definition: actions.h:207
int selectSameSheet(const TOOL_EVENT &aEvent)
Selects all modules belonging to same hierarchical sheet as the selected footprint (same sheet path).
virtual void Update(VIEW_ITEM *aItem, int aUpdateFlags) override
For dynamic VIEWs, informs the associated VIEW that the graphical representation of this item has cha...
Definition: pcb_view.cpp:93
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,...
VECTOR2D ToWorld(const VECTOR2D &aCoord, bool aAbsolute=true) const
Function ToWorld() Converts a screen space point/vector to a point/vector in world space coordinates.
Definition: view.cpp:474
class PCB_GROUP, a set of BOARD_ITEMs
Definition: typeinfo.h:109
void SetOrigin(VECTOR2I aOrigin)
Set the origin of the rectange (the fixed corner)
wxPoint GetPosition() const override
Definition: class_pad.h:165
void ClearSelected()
Definition: base_struct.h:211
const BITMAP_OPAQUE options_generic_xpm[1]
void SetCurrentCursor(wxStockCursor aStockCursorID)
Function SetCurrentCursor Set the current cursor shape for this panel.
const wxPoint & GetStart() const
Definition: class_track.h:116
VIEW_CONTROLS class definition.
PCB_GROUP is a set of BOARD_ITEMs (i.e., without duplicates)
void Collect(BOARD_ITEM *aItem, const KICAD_T aScanList[], const wxPoint &aRefPos, const COLLECTORS_GUIDE &aGuide)
Scan a BOARD_ITEM using this class's Inspector method, which does the collection.
Definition: collectors.cpp:580
Classes BOARD_ITEM and BOARD_CONNECTED_ITEM.
virtual double OnePixelInIU() const =0
void SetIgnoreModulesVals(bool ignore)
Definition: collectors.h:594
void SetIgnoreMicroVias(bool ignore)
Definition: collectors.h:609
SELECTION_TOOL.
class CENTER_DIMENSION, a center point marking (graphic item)
Definition: typeinfo.h:103
void SetIgnoreModulesOnBack(bool ignore)
Definition: collectors.h:564
SELECTION_LOCK_FLAGS CheckLock()
Checks if the user has agreed to modify locked items for the given selection.
static TOOL_ACTION unselectItem
Definition: pcb_actions.h:66
#define SKIP_STRUCT
flag indicating that the structure should be ignored
Definition: base_struct.h:128
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
CONDITIONAL_MENU & GetMenu()
Function GetMenu.
Definition: tool_menu.cpp:46
the 3d code uses this value
Definition: typeinfo.h:80
static TOOL_ACTION selectNet
Selects all connections belonging to a single net.
Definition: pcb_actions.h:80
static TOOL_ACTION dragFreeAngle
Definition: pcb_actions.h:135
Select the entire net.
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:219
static TOOL_ACTION unselectItems
Definition: pcb_actions.h:70
const GENERAL_COLLECTORS_GUIDE getCollectorsGuide() const
int find(const TOOL_EVENT &aEvent)
Find an item.
Smd pad, appears on the solder paste layer (default)
Definition: pad_shapes.h:81
static TOOL_ACTION cancelInteractive
Definition: actions.h:65
class ZONE_CONTAINER, a zone area
Definition: typeinfo.h:106
virtual void Remove(VIEW_ITEM *aItem)
Function Remove() Removes a VIEW_ITEM from the view.
Definition: view.cpp:375
static TOOL_ACTION properties
Activation of the edit tool.
Definition: pcb_actions.h:114
int GetWidth() const
Definition: eda_rect.h:119
int UnselectItems(const TOOL_EVENT &aEvent)
Multiple item unselection event handler
PADS & Pads()
Definition: class_module.h:181
void SetBrightened()
Definition: base_struct.h:209
PCBNEW_SELECTION m_selection
class TEXTE_PCB, text on a layer
Definition: typeinfo.h:92
void SetIgnoreModulesRefs(bool ignore)
Definition: collectors.h:600
LSET GetVisibleLayers() const
Function GetVisibleLayers is a proxy function that calls the correspondent function in m_BoardSetting...
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Function RunAction() Runs the specified action.
Definition: tool_manager.h:140
static TOOL_ACTION selectionMenu
Runs a selection menu to select from a list of items.
Definition: pcb_actions.h:73
static TOOL_ACTION selectConnection
Selects tracks between junctions or expands an existing selection to pads or the entire connection.
Definition: pcb_actions.h:77
class ARC, an arc track segment on a copper layer
Definition: typeinfo.h:98
void SetExclusiveOr(bool aExclusiveOr)
show modules values (when texts are visibles)
Template specialization to enable wxStrings for certain containers (e.g. unordered_map)
Definition: bitmap.cpp:56
static TOOL_ACTION drag45Degree
Definition: pcb_actions.h:134
EDA_RECT GetFootprintRect() const
Function GetFootprintRect() Build and returns the boundary box of the module footprint excluding any ...
EDA_RECT Common(const EDA_RECT &aRect) const
Function Common returns the area that is common with another rectangle.
class D_PAD, a pad in a footprint
Definition: typeinfo.h:90
void UpdateAll()
Runs update handlers for the menu and its submenus.
const KIID_PATH & GetPath() const
Definition: class_module.h:237
Struct that will be set with the result of the user choices in the dialog.
const EDA_RECT GetBoundingBox() const override
virtual wxPoint GetPosition() const
Definition: base_struct.h:337
DRAWINGS & GraphicalItems()
Definition: class_module.h:191
const COLLECTORS_GUIDE * GetGuide()
Definition: collectors.h:352
void SetContextMenu(ACTION_MENU *aMenu, CONTEXT_MENU_TRIGGER aTrigger=CMENU_BUTTON)
Function SetContextMenu()
Stop at any place where more than two traces meet.
const BITMAP_OPAQUE net_highlight_xpm[1]
static TOOL_ACTION find
Definition: actions.h:79
PCB_GROUP * m_enteredGroup
VECTOR2< int > VECTOR2I
Definition: vector2d.h:594
int CountType(KICAD_T aType)
Function CountType counts the number of items matching aType.
Definition: collector.h:262
bool selectionContains(const VECTOR2I &aPoint) const
Function selectionContains()
const PCB_DISPLAY_OPTIONS & GetDisplayOptions() const
Function GetDisplayOptions Display options control the way tracks, vias, outlines and other things ar...
static double calcArea(const BOARD_ITEM *aItem)
BOARD_CONNECTED_ITEM is a base class derived from BOARD_ITEM for items that can be connected and have...
static bool NotEmpty(const SELECTION &aSelection)
Tests if there are any items selected.
void Go(int(T::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
Function Go()
void select(BOARD_ITEM *aItem)
Function select() Takes necessary action mark an item as selected.
class EDGE_MODULE, a footprint edge
Definition: typeinfo.h:94
bool Contains(const wxPoint &aPoint) const
Function Contains.
void Remove(int aIndex)
Function Remove removes the item at aIndex (first position is 0);.
Definition: collector.h:130
virtual void Remove(VIEW_ITEM *aItem) override
Function Remove() Removes a VIEW_ITEM from the view.
Definition: pcb_view.cpp:76
search types array terminator (End Of Types)
Definition: typeinfo.h:82
TRACK_DRAG_ACTION
KICAD_T
Enum KICAD_T is the set of class identification values, stored in EDA_ITEM::m_StructType.
Definition: typeinfo.h:78
static const TOOL_EVENT SelectedItemsModified
Definition: actions.h:211
PAINTER * GetPainter() const
Function GetPainter() Returns the painter object used by the view for drawing VIEW_ITEMS.
Definition: view.h:199
A single base class (TRACK) represents both tracks and vias, with subclasses for curved tracks (ARC) ...
bool itemPassesFilter(BOARD_ITEM *aItem)
Returns true if the given item passes the current SELECTION_FILTER_OPTIONS
class TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:96
void SetIsHover(bool aIsHover)
Definition: selection.h:66
BOARD_ITEM * pickSmallestComponent(GENERAL_COLLECTOR *aCollector)
Function pickSmallestComponent() Allows one to find the smallest (in terms of bounding box area) item...
Private implementation of firewalled private data.
virtual void Add(EDA_ITEM *aItem)
Definition: selection.h:76
bool IsAction(const TOOL_ACTION *aAction) const
Function IsAction() Tests if the event contains an action issued upon activation of the given TOOL_AC...
Definition: tool_event.cpp:67
void highlight(BOARD_ITEM *aItem, int aHighlightMode, PCBNEW_SELECTION *aGroup=nullptr)
Function highlight() Highlights the item visually.
PCBNEW_SELECTION & GetSelection()
Function GetSelection()
void ClearBrightened()
Definition: base_struct.h:212
void Append(EDA_ITEM *item)
Function Append adds an item to the end of the list.
Definition: collector.h:120
void SetAdditive(bool aAdditive)
show modules on front
PCB_BASE_EDIT_FRAME * frame() const
virtual bool HitTest(const wxPoint &aPosition, int aAccuracy=0) const
Function HitTest tests if aPosition is contained within or on the bounding box of an item.
Definition: base_struct.h:307
virtual LSET GetLayerSet() const override
Function GetLayerSet returns a std::bitset of all layers on which the item physically resides.
Definition: class_zone.cpp:287
void findCallback(BOARD_ITEM *aItem)
Find dialog callback.
SEARCH_RESULT Visit(INSPECTOR inspector, void *testData, const KICAD_T scanTypes[]) override
Function Visit may be re-implemented for each derived class in order to handle all the types given by...
int GetCount() const
Function GetCount returns the number of objects in the list.
Definition: collector.h:101
int filterSelection(const TOOL_EVENT &aEvent)
Invoke filter dialog and modify current selection
#define SELECTED
Definition: base_struct.h:124
int expandConnection(const TOOL_EVENT &aEvent)
Expands the current track selection to the next boundary (junctions, pads, or all)
class MODULE, a footprint
Definition: typeinfo.h:89
bool selectPoint(const VECTOR2I &aWhere, bool aOnDrag=false, bool *aSelectionCancelledFlag=NULL, CLIENT_SELECTION_FILTER aClientFilter=NULL)
Function selectPoint() Selects an item pointed by the parameter aWhere.
void Transfer(int aIndex)
Moves the item at aIndex (first position is 0) to the backup list.
Definition: collector.h:174
bool selectCursor(bool aForceSelect=false, CLIENT_SELECTION_FILTER aClientFilter=NULL)
Function selectCursor() Selects an item under the cursor unless there is something already selected o...
PCB_DISPLAY_OPTIONS handles display options like enable/disable some optional drawings.
PCB_LAYER_ID
A quick note on layer IDs:
void UnbrightenItem(BOARD_ITEM *aItem)
LSET is a set of PCB_LAYER_IDs.
const PCBNEW_SELECTION & selection() const
void SetCenter(const VECTOR2D &aCenter)
Function SetCenter() Sets the center point of the VIEW (i.e.
Definition: view.cpp:603
bool text
Text (free or attached to a footprint)
static double calcMaxArea(GENERAL_COLLECTOR &aCollector, KICAD_T aType)
#define NULL
void SetSelected()
Definition: base_struct.h:208
void SetIgnoreMTextsOnBack(bool ignore)
Definition: collectors.h:552
int updateSelection(const TOOL_EVENT &aEvent)
Event handler to update the selection VIEW_ITEM.
bool dimensions
Dimension items.
void SetIgnorePadsOnFront(bool ignore)
Definition: collectors.h:582
int ClearSelection(const TOOL_EVENT &aEvent)
Clear current selection event handler.
void MarkTargetDirty(int aTarget)
Function MarkTargetDirty() Sets or clears target 'dirty' flag.
Definition: view.h:574
void selectConnectedTracks(BOARD_CONNECTED_ITEM &aSourceItem, STOP_CONDITION aStopCondition)
Selects connecteed tracks and vias.
bool selectMultiple()
Function selectMultiple() Handles drawing a selection box that allows one to select many items at the...
bool ProcessEvent(const TOOL_EVENT &aEvent)
Propagates an event to tools that requested events of matching type(s).
bool IsVisible(const VIEW_ITEM *aItem) const
Returns information if the item is visible (or not).
Definition: view.cpp:1517
bool graphics
Graphic lines, shapes, polygons.
void SetIgnoreMTextsOnFront(bool ignore)
Definition: collectors.h:558
SELECTION_LOCK_FLAGS
Definition: selection.h:279
T Parameter() const
Function Parameter() Returns a non-standard parameter assigned to the event.
Definition: tool_event.h:435
virtual int GetTopLayer() const
Definition: view.cpp:847
coord_type GetWidth() const
Definition: box2.h:197
Meta control for all pads opacity/visibility (color ignored)
bool Contains(const Vec &aPoint) const
Function Contains.
Definition: box2.h:151
TOOL_EVENT.
Definition: tool_event.h:171
void AddItemToSel(BOARD_ITEM *aItem, bool aQuietMode=false)
void SetMaximum()
Definition: box2.h:73
bool Contains(EDA_ITEM *aItem) const
Definition: selection.h:113
void highlightInternal(BOARD_ITEM *aItem, int aHighlightMode, PCBNEW_SELECTION *aGroup, bool isChild)
const BOX2I ViewBBox() const override
Function ViewBBox() returns the bounding box of the item covering all its layers.
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Function GetConnectivity() returns list of missing connections between components/tracks.
Definition: class_board.h:345
const std::deque< EDA_ITEM * > GetItems() const
Definition: selection.h:132
KIGFX::PCB_VIEW * view() const
void FilterCollectorForGroups(GENERAL_COLLECTOR &aCollector) const
Stop when reaching a pad.
bool ToolStackIsEmpty()
Definition: tools_holder.h:117
bool HasItem(const EDA_ITEM *aItem) const
Function HasItem tests if aItem has already been collected.
Definition: collector.h:229
#define BRIGHTENED
item is drawn with a bright contour
Definition: base_struct.h:139
void RemoveItemFromSel(BOARD_ITEM *aItem, bool aQuietMode=false)
bool Init() override
Function Init() Init() is called once upon a registration of the tool.
EDA_ITEM * GetParent() const
Definition: base_struct.h:195
PCB_BASE_FRAME * m_frame
Items that may change while the view stays the same (noncached)
Definition: definitions.h:50
static const TOOL_EVENT ClearedEvent
Definition: actions.h:208
static const TOOL_EVENT SelectedItemsMoved
Definition: actions.h:214
int SelectionMenu(const TOOL_EVENT &aEvent)
Function SelectionMenu() Shows a popup menu to trim the COLLECTOR passed as aEvent's parameter down t...
double GetArea() const
Function GetArea returns the area of the rectangle.
static TOOL_ACTION updateMenu
Definition: actions.h:165
int selectSheetContents(const TOOL_EVENT &aEvent)
Selects all modules belonging to same sheet, from Eeschema, using crossprobing
void SetIgnoreMTextsMarkedNoShow(bool ignore)
Definition: collectors.h:546
virtual KIGFX::VIEW_ITEM * GetItem(unsigned int aIdx) const override
Definition: selection.h:105
virtual void Update(VIEW_ITEM *aItem, int aUpdateFlags)
For dynamic VIEWs, informs the associated VIEW that the graphical representation of this item has cha...
Definition: view.cpp:1531
int SelectItem(const TOOL_EVENT &aEvent)
Item selection event handler.
const std::set< unsigned int > GetActiveLayers() const
Function GetActiveLayers() Returns the set of currently active layers.
Like smd, does not appear on the solder paste layer (default) note also has a special attribute in Ge...
Definition: pad_shapes.h:82
const BITMAP_OPAQUE info_xpm[1]
Definition: info.cpp:75
virtual void SetLayer(int aLayer)
Function SetLayer() Sets layer used to draw the group.
Definition: view_group.h:115
static TOOL_ACTION hideDynamicRatsnest
Definition: pcb_actions.h:440
bool footprints
Allow selecting entire footprints.
int GetHeight() const
Definition: eda_rect.h:120
KIGFX::VIEW * getView() const
Function getView()
Definition: tool_base.cpp:36
virtual void SetAutoPan(bool aEnabled)
Function SetAutoPan Turns on/off auto panning (this feature is used when there is a tool active (eg.
int selectNet(const TOOL_EVENT &aEvent)
Selects all copper connections belonging to the same net(s) as the items in the selection.
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
Definition: class_zone.h:724
bool Empty() const
Checks if there is anything selected.
Definition: selection.h:121
class PCB_TARGET, a target (graphic item)
Definition: typeinfo.h:105
bool IsMirroredX() const
Function IsMirroredX() Returns true if view is flipped across the X axis.
Definition: view.h:230
static TOOL_ACTION clearHighlight
Definition: pcb_actions.h:429
void SetSubtractive(bool aSubtractive)
const Vec & GetPosition() const
Definition: box2.h:194
bool IsElementVisible(GAL_LAYER_ID aLayer) const
Function IsElementVisible tests whether a given element category is visible.
virtual unsigned int GetSize() const override
Function GetSize() Returns the number of stored items.
Definition: selection.h:100
virtual void SetScale(double aScale, VECTOR2D aAnchor={ 0, 0 })
Function SetScale() Sets the scaling factor, zooming around a given anchor point.
Definition: view.cpp:577
void(* CLIENT_SELECTION_FILTER)(const VECTOR2I &, GENERAL_COLLECTOR &, SELECTION_TOOL *)
class TEXTE_MODULE, text in a footprint
Definition: typeinfo.h:93
static TOOL_ACTION filterSelection
Filters the items in the current selection (invokes dialog)
Definition: pcb_actions.h:92
void Normalize()
Function Normalize ensures that the height ant width are positive.
void SetCallback(boost::function< void(BOARD_ITEM *)> aCallback)
Function to be called on each found event.
Definition: dialog_find.h:62
bool GetHighContrast() const
virtual RENDER_SETTINGS * GetSettings()=0
Function GetAdapter Returns pointer to current settings that are going to be used when drawing items.
static bool itemIsIncludedByFilter(const BOARD_ITEM &aItem, const BOARD &aBoard, const DIALOG_FILTER_SELECTION::OPTIONS &aFilterOptions)
Function itemIsIncludedByFilter()
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Function Inflate inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:302
bool IsLayerVisible(PCB_LAYER_ID aLayer) const
Function IsLayerVisible is a proxy function that calls the correspondent function in m_BoardSettings ...
virtual bool IsLocked() const
Function IsLocked.
bool lockedItems
Allow selecting locked items.
void connectedItemFilter(const VECTOR2I &, GENERAL_COLLECTOR &aCollector, SELECTION_TOOL *sTool)
class MARKER_PCB, a marker used to show something
Definition: typeinfo.h:99
PCB_GROUP * TopLevelGroup(BOARD_ITEM *item, PCB_GROUP *scope)
const int scale
smd pads, front layer
bool HasAdditionalItems()
Test if the collector has heuristic backup items.
Definition: collector.h:156
PCBNEW_SELECTION & RequestSelection(CLIENT_SELECTION_FILTER aClientFilter, std::vector< BOARD_ITEM * > *aFiltered=nullptr, bool aConfirmLockedItems=false)
Function RequestSelection()
void SetState(int type, int state)
Definition: base_struct.h:221
int GetWidth() const
Definition: class_track.h:110
Meta control for all vias opacity/visibility.
bool IsType(FRAME_T aType) const
void SetHighlight(bool aEnabled, int aNetcode=-1, bool aMulti=false)
Function SetHighlight Turns on/off highlighting - it may be done for the active layer or the specifie...
Class to handle a graphic segment.
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:201
static TOOL_ACTION selectOnSheetFromEeschema
Selects all components on sheet from Eeschema crossprobing.
Definition: pcb_actions.h:86
BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:178
MODULE * module() const
#define _(s)
Definition: 3d_actions.cpp:33
static const KICAD_T ModuleItems[]
A scan list for primary module items.
Definition: collectors.h:308
bool Selectable(const BOARD_ITEM *aItem, bool checkVisibilityOnly=false) const
Function selectable() Checks conditions for an item to be selected.
void SetIgnoreModulesOnFront(bool ignore)
Definition: collectors.h:570
Used when the right click button is pressed, or when the select tool is in effect.
Definition: collectors.h:240
void SetIgnoreThroughVias(bool ignore)
Definition: collectors.h:603
virtual wxString GetSelectMenuText(EDA_UNITS aUnits) const
Function GetSelectMenuText returns the text to display to be used in the selection clarification cont...
std::pair< VIEW_ITEM *, int > LAYER_ITEM_PAIR
Definition: view.h:66
void AddSubMenu(std::shared_ptr< ACTION_MENU > aSubMenu)
Function CreateSubMenu.
Definition: tool_menu.cpp:52
wxString AsString() const
Definition: common.h:137
class NETINFO_ITEM, a description of a net
Definition: typeinfo.h:108
void unselect(BOARD_ITEM *aItem)
Function unselect() Takes necessary action mark an item as unselected.
static TOOL_ACTION selectItem
Selects an item (specified as the event parameter).
Definition: pcb_actions.h:65
EDA_RECT handles the component boundary box.
Definition: eda_rect.h:44
ZONE_DISPLAY_MODE m_ZoneDisplayMode
int Size() const
Returns the number of selected parts.
Definition: selection.h:127
currently selected items overlay
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:68
void RebuildSelection()
Rebuilds the selection from the EDA_ITEMs' selection flags.
EDA_ITEM is a base class for most all the KiCad significant classes, used in schematics and boards.
Definition: base_struct.h:159
coord_type GetHeight() const
Definition: box2.h:198
double calcRatio(double a, double b)
RESET_REASON
Determines the reason of reset for a tool
Definition: tool_base.h:79
const wxPoint & GetEnd() const
Definition: class_track.h:113
static TOOL_ACTION deselectNet
Removes all connections belonging to a single net from the active selection.
Definition: pcb_actions.h:83
boost::optional< T > OPT
Definition: optional.h:7
virtual double GetLength() const
Function GetLength returns the length of the track using the hypotenuse calculation.
Definition: class_track.h:151
void SetVisible(VIEW_ITEM *aItem, bool aIsVisible=true)
Sets the item visibility.
Definition: view.cpp:1477
void Combine()
Re-combines the backup list into the main list of the collector.
Definition: collector.h:164
int SelectItems(const TOOL_EVENT &aEvent)
Multiple item selection event handler
MODULE_ZONE_CONTAINERS & Zones()
Definition: class_module.h:201
ACTION_MENU * create() const override
Returns an instance of this class. It has to be overridden in inheriting classes.
void zoomFitSelection()
Zooms the screen to center and fit the current selection.
class ORTHOGONAL_DIMENSION, a linear dimension constrained to x/y
Definition: typeinfo.h:104
class VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:97
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1) override
Function Add() Adds a VIEW_ITEM to the view.
Definition: pcb_view.cpp:59
SELECTION_FILTER_OPTIONS m_filter
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Function Add() Adds a VIEW_ITEM to the view.
Definition: view.cpp:345
void ExitGroup(bool aSelectGroup=false)
Leave the currently entered group.
const Vec & GetSize() const
Definition: box2.h:189
virtual int Query(const BOX2I &aRect, std::vector< LAYER_ITEM_PAIR > &aResult) const
Function Query() Finds all visible items that touch or are within the rectangle aRect.
Definition: view.cpp:451
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
class ZONE_CONTAINER, managed by a footprint
Definition: typeinfo.h:95
VIEW.
Definition: view.h:61
bool doSelectionMenu(GENERAL_COLLECTOR *aItems, const wxString &aTitle)
Allows the selection of a single item from a list via pop-up menu.
A general implementation of a COLLECTORS_GUIDE.
Definition: collectors.h:390
void BrightenItem(BOARD_ITEM *aItem)
double GetScale() const
Function GetScale()
Definition: view.h:257
EDGE_MODULE class definition.
class DRAWSEGMENT, a segment not on copper layers
Definition: typeinfo.h:91
STATUS_FLAGS GetFlags() const
Definition: base_struct.h:234
BOARD_ITEM_CONTAINER * GetParent() const
void FocusOnLocation(const wxPoint &aPos)
Useful to focus on a particular location, in find functions Move the graphic cursor (crosshair cursor...
virtual BITMAP_DEF GetMenuImage() const
Function GetMenuImage returns a pointer to an image to be used in menus.
virtual PCB_LAYER_ID GetLayer() const
Function GetLayer returns the primary layer this item is on.
static TOOL_ACTION selectAll
Definition: actions.h:73
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition: confirm.cpp:283
EDA_RECT GetBoundingBox() const
Definition: selection.h:156
void ShowContextMenu(SELECTION &aSelection)
Function ShowContextMenu.
Definition: tool_menu.cpp:59
void FocusOnItem(BOARD_ITEM *aItem)
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition: lset.cpp:856
void setTransitions() override
Sets up handlers for various events.
const BOARD_ITEM_SET & GetItems() const
int CursorSelection(const TOOL_EVENT &aEvent)
Select a single item under cursor event handler.
static TOOL_ACTION selectionCursor
Select a single item under the cursor position.
Definition: pcb_actions.h:59
void SetIgnoreThroughHolePads(bool ignore)
Definition: collectors.h:588
void unhighlight(BOARD_ITEM *aItem, int aHighlightMode, PCBNEW_SELECTION *aGroup=nullptr)
Function unhighlight() Unhighlights the item visually.
show modules references (when texts are visibles)
EDA_UNITS GetUserUnits() const
Return the user units currently in use.
void SetIgnoreZoneFills(bool ignore)
Definition: collectors.h:615
virtual double ViewGetLOD(int aLayer, VIEW *aView) const
Function ViewGetLOD() Returns the level of detail (LOD) of the item.
Definition: view_item.h:141
EDA_ITEM * Front() const
Definition: selection.h:184
void filterCollectedItems(GENERAL_COLLECTOR &aCollector)
Applies the SELECTION_FILTER_OPTIONS to a collection of items
KICAD_T Type() const
Function Type()
Definition: base_struct.h:193
void unhighlightInternal(BOARD_ITEM *aItem, int aHighlightMode, PCBNEW_SELECTION *aGroup, bool isChild)
static TOOL_ACTION selectSameSheet
Selects all components on the same sheet as the selected footprint.
Definition: pcb_actions.h:89
void SetIgnorePadsOnBack(bool ignore)
Definition: collectors.h:576
virtual void Remove(EDA_ITEM *aItem)
Definition: selection.h:87