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