KiCad PCB EDA Suite
pcb_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 <clipper.hpp>
34 #include <track.h>
35 #include <footprint.h>
36 #include <pcb_shape.h>
37 #include <pcb_text.h>
38 #include <pcb_marker.h>
39 #include <zone.h>
40 #include <collectors.h>
41 #include <dialog_find.h>
44 #include <class_draw_panel_gal.h>
45 #include <view/view_controls.h>
47 #include <painter.h>
48 #include <router/router_tool.h>
49 #include <bitmaps.h>
50 #include <pcbnew_settings.h>
51 #include <tool/tool_event.h>
52 #include <tool/tool_manager.h>
54 #include <footprint_viewer_frame.h>
55 #include <id.h>
56 #include "tool_event_utils.h"
57 #include "pcb_selection_tool.h"
58 #include "pcb_bright_box.h"
59 #include "pcb_actions.h"
60 
61 
62 class SELECT_MENU : public ACTION_MENU
63 {
64 public:
66  ACTION_MENU( true )
67  {
68  SetTitle( _( "Select" ) );
69 
71 
72  AppendSeparator();
73 
76  // This could be enabled if we have better logic for picking the target net with the mouse
77  // Add( PCB_ACTIONS::deselectNet );
79  }
80 
81 private:
82  ACTION_MENU* create() const override
83  {
84  return new SELECT_MENU();
85  }
86 };
87 
88 
93 {
94 public:
96 };
97 
98 
100  PCB_TOOL_BASE( "pcbnew.InteractiveSelection" ),
101  m_frame( NULL ),
102  m_additive( false ),
103  m_subtractive( false ),
104  m_exclusive_or( false ),
105  m_multiple( false ),
106  m_skip_heuristics( false ),
107  m_enteredGroup( nullptr ),
108  m_priv( std::make_unique<PRIV>() )
109 {
110  m_filter.lockedItems = false;
111  m_filter.footprints = true;
112  m_filter.text = true;
113  m_filter.tracks = true;
114  m_filter.vias = true;
115  m_filter.pads = true;
116  m_filter.graphics = true;
117  m_filter.zones = true;
118  m_filter.keepouts = true;
119  m_filter.dimensions = true;
120  m_filter.otherItems = true;
121 }
122 
123 
125 {
126  getView()->Remove( &m_selection );
128 }
129 
130 
132 {
133  auto frame = getEditFrame<PCB_BASE_FRAME>();
134 
137  {
139  return true;
140  }
141 
142  auto selectMenu = std::make_shared<SELECT_MENU>();
143  selectMenu->SetTool( this );
144  m_menu.AddSubMenu( selectMenu );
145 
146  auto& menu = m_menu.GetMenu();
147 
148  auto activeToolCondition =
149  [ frame ] ( const SELECTION& aSel )
150  {
151  return !frame->ToolStackIsEmpty();
152  };
153 
154  auto inGroupCondition =
155  [this] ( const SELECTION& )
156  {
157  return m_enteredGroup != nullptr;
158  };
159 
160  if( frame && frame->IsType( FRAME_PCB_EDITOR ) )
161  {
162  menu.AddMenu( selectMenu.get(), SELECTION_CONDITIONS::NotEmpty );
163  menu.AddSeparator( 1000 );
164  }
165 
166  // "Cancel" goes at the top of the context menu when a tool is active
167  menu.AddItem( ACTIONS::cancelInteractive, activeToolCondition, 1 );
168  menu.AddItem( PCB_ACTIONS::groupLeave, inGroupCondition, 1 );
169  menu.AddSeparator( 1 );
170 
171  if( frame )
173 
174  return true;
175 }
176 
177 
179 {
180  m_frame = getEditFrame<PCB_BASE_FRAME>();
181 
182  if( m_enteredGroup )
183  ExitGroup();
184 
185  if( aReason == TOOL_BASE::MODEL_RELOAD )
186  {
187  // Deselect any item being currently in edit, to avoid unexpected behavior
188  // and remove pointers to the selected items from containers
189  // without changing their properties (as they are already deleted
190  // while a new board is loaded)
191  ClearSelection( true );
192 
193  getView()->GetPainter()->GetSettings()->SetHighlight( false );
194  }
195  else
196  {
197  // Restore previous properties of selected items and remove them from containers
198  ClearSelection( true );
199  }
200 
201  // Reinsert the VIEW_GROUP, in case it was removed from the VIEW
202  view()->Remove( &m_selection );
203  view()->Add( &m_selection );
204 
207 }
208 
209 
211 {
212  // Main loop: keep receiving events
213  while( TOOL_EVENT* evt = Wait() )
214  {
215  MOUSE_DRAG_ACTION dragAction = m_frame->GetDragAction();
217 
218  // on left click, a selection is made, depending on modifiers ALT, SHIFT, CTRL:
219  // Due to the fact ALT key modifier cannot be useed freely on Winows and Linux,
220  // actions are different on OSX and others OS
221  // Especially, ALT key cannot be used to force showing the full selection choice
222  // context menu (the menu is immediately closed on Windows )
223  //
224  // No modifier = select items and deselect previous selection
225  // ALT (on OSX) = skip heuristic and show full selection choice
226  // ALT (on others) = exclusive OR of selected items (inverse selection)
227  //
228  // CTRL (on OSX) = exclusive OR of selected items (inverse selection)
229  // CTRL (on others) = skip heuristic and show full selection choice
230  //
231  // SHIFT = add selected items to the current selection
232  //
233  // CTRL+SHIFT (on OSX) = remove selected items to the current selection
234  // CTRL+SHIFT (on others) = highlight net
235  //
236  // CTRL+ALT (on OSX) = highlight net
237  // CTRL+ALT (on others) = do nothing (same as no modifier)
238  //
239  // SHIFT+ALT (on OSX) = do nothing (same as no modifier)
240  // SHIFT+ALT (on others) = remove selected items to the current selection
241 
242 #ifdef __WXOSX_MAC__
243  m_subtractive = evt->Modifier( MD_CTRL ) &&
244  evt->Modifier( MD_SHIFT ) &&
245  !evt->Modifier( MD_ALT );
246 
247  m_additive = evt->Modifier( MD_SHIFT ) &&
248  !evt->Modifier( MD_CTRL ) &&
249  !evt->Modifier( MD_ALT );
250 
251  m_exclusive_or = evt->Modifier( MD_CTRL ) &&
252  !evt->Modifier( MD_SHIFT ) &&
253  !evt->Modifier( MD_ALT );
254 
255  m_skip_heuristics = evt->Modifier( MD_ALT ) &&
256  !evt->Modifier( MD_SHIFT ) &&
257  !evt->Modifier( MD_CTRL );
258 
259  bool highlight_modifier = evt->Modifier( MD_CTRL )
260  && evt->Modifier( MD_ALT )
261  && !evt->Modifier( MD_SHIFT );
262 #else
263  m_subtractive = evt->Modifier( MD_ALT ) &&
264  evt->Modifier( MD_SHIFT ) &&
265  !evt->Modifier( MD_CTRL );
266 
267  m_additive = evt->Modifier( MD_SHIFT ) &&
268  !evt->Modifier( MD_ALT ) &&
269  !evt->Modifier( MD_CTRL );
270 
271  m_exclusive_or = evt->Modifier( MD_ALT ) &&
272  !evt->Modifier( MD_SHIFT ) &&
273  !evt->Modifier( MD_CTRL );
274 
275  // Cannot use the Alt key on windows or the disambiguation context menu is immediately
276  // dismissed rendering it useless.
277  m_skip_heuristics = evt->Modifier( MD_CTRL ) &&
278  !evt->Modifier( MD_SHIFT ) &&
279  !evt->Modifier( MD_ALT );
280 
281  bool highlight_modifier = evt->Modifier( MD_CTRL )
282  && evt->Modifier( MD_SHIFT )
283  && !evt->Modifier( MD_ALT );
284 #endif
285 
286  bool modifier_enabled = m_subtractive || m_additive || m_exclusive_or;
287  PCB_BASE_FRAME* frame = getEditFrame<PCB_BASE_FRAME>();
288  bool brd_editor = frame && frame->IsType( FRAME_PCB_EDITOR );
290 
291  // If the router tool is active, don't override
292  if( router && router->IsToolActive() )
293  {
294  evt->SetPassEvent();
295  }
296  // Single click? Select single object
297  else if( evt->IsClick( BUT_LEFT ) )
298  {
299  if( highlight_modifier && brd_editor )
301  else
302  {
303  m_frame->FocusOnItem( nullptr );
304  selectPoint( evt->Position() );
305  }
306  }
307  else if( evt->IsClick( BUT_RIGHT ) )
308  {
309  // Right click? if there is any object - show the context menu
310  bool selectionCancelled = false;
311 
312  if( m_selection.Empty() )
313  {
314  selectPoint( evt->Position(), false, &selectionCancelled );
315  m_selection.SetIsHover( true );
316  }
317 
318  if( !selectionCancelled )
320  }
321  else if( evt->IsDblClick( BUT_LEFT ) )
322  {
323  // Double click? Display the properties window
324  m_frame->FocusOnItem( nullptr );
325 
326  if( m_selection.Empty() )
327  selectPoint( evt->Position() );
328 
329  if( m_selection.GetSize() == 1 && m_selection[0]->Type() == PCB_GROUP_T )
330  {
331  EnterGroup();
332  }
333  else
334  {
336  }
337  }
338  else if( evt->IsDblClick( BUT_MIDDLE ) )
339  {
340  // Middle double click? Do zoom to fit or zoom to objects
341  if( evt->Modifier( MD_CTRL ) ) // Is CTRL key down?
343  else
345  }
346  else if( evt->IsDrag( BUT_LEFT ) )
347  {
348  // Is another tool already moving a new object? Don't allow a drag start
349  if( !m_selection.Empty() && m_selection[0]->HasFlag( IS_NEW | IS_MOVED ) )
350  {
351  evt->SetPassEvent();
352  continue;
353  }
354 
355  // Drag with LMB? Select multiple objects (or at least draw a selection box)
356  // or drag them
357  m_frame->FocusOnItem( nullptr );
359 
360  if( modifier_enabled || dragAction == MOUSE_DRAG_ACTION::SELECT )
361  {
362  selectMultiple();
363  }
364  else if( m_selection.Empty() && dragAction != MOUSE_DRAG_ACTION::DRAG_ANY )
365  {
366  selectMultiple();
367  }
368  else
369  {
370  // Don't allow starting a drag from a zone filled area that isn't already selected
371  auto zoneFilledAreaFilter =
372  []( const VECTOR2I& aWhere, GENERAL_COLLECTOR& aCollector,
373  PCB_SELECTION_TOOL* aTool )
374  {
375  wxPoint location = wxPoint( aWhere );
376  int accuracy = KiROUND( 5 * aCollector.GetGuide()->OnePixelInIU() );
377  std::set<EDA_ITEM*> remove;
378 
379  for( EDA_ITEM* item : aCollector )
380  {
381  if( item->Type() == PCB_ZONE_T )
382  {
383  ZONE* zone = static_cast<ZONE*>( item );
384 
385  if( !zone->HitTestForCorner( location, accuracy * 2 ) &&
386  !zone->HitTestForEdge( location, accuracy ) )
387  remove.insert( zone );
388  }
389  }
390 
391  for( EDA_ITEM* item : remove )
392  aCollector.Remove( item );
393  };
394 
395  // Selection is empty? try to start dragging the item under the point where drag
396  // started
397  if( m_selection.Empty() && selectCursor( false, zoneFilledAreaFilter ) )
398  m_selection.SetIsHover( true );
399 
400  // Check if dragging has started within any of selected items bounding box.
401  // We verify "HasPosition()" first to protect against edge case involving
402  // moving off menus that causes problems (issue #5250)
403  if( evt->HasPosition() && selectionContains( evt->Position() ) )
404  {
405  // Yes -> run the move tool and wait till it finishes
406  TRACK* track = dynamic_cast<TRACK*>( m_selection.GetItem( 0 ) );
407 
408  // If there is only item in the selection and it's a track, then we need to route it
409  bool doRouting = ( track && ( 1 == m_selection.GetSize() ) );
410 
411  if( doRouting && trackDragAction == TRACK_DRAG_ACTION::DRAG )
413  else if( doRouting && trackDragAction == TRACK_DRAG_ACTION::DRAG_FREE_ANGLE )
415  else
417  }
418  else
419  {
420  // No -> drag a selection box
421  selectMultiple();
422  }
423  }
424  }
425  else if( evt->IsCancel() )
426  {
427  m_frame->FocusOnItem( nullptr );
428 
429  if( m_enteredGroup )
430  ExitGroup();
431 
432  ClearSelection();
433 
434  if( evt->FirstResponder() == this )
436  }
437  else
438  {
439  evt->SetPassEvent();
440  }
441 
442 
443  if( m_frame->ToolStackIsEmpty() )
444  {
445  //move cursor prediction
446  if( !modifier_enabled
447  && dragAction == MOUSE_DRAG_ACTION::DRAG_SELECTED
448  && !m_selection.Empty()
449  && evt->HasPosition()
450  && selectionContains( evt->Position() ) )
451  {
453  }
454  else
455  {
456  if( m_additive )
458  else if( m_subtractive )
460  else if( m_exclusive_or )
462  else
464  }
465  }
466  }
467 
468  // Shutting down; clear the selection
469  m_selection.Clear();
470 
471  return 0;
472 }
473 
474 
476 {
477  wxCHECK_RET( m_selection.GetSize() == 1 && m_selection[0]->Type() == PCB_GROUP_T,
478  "EnterGroup called when selection is not a single group" );
479  PCB_GROUP* aGroup = static_cast<PCB_GROUP*>( m_selection[0] );
480 
481  if( m_enteredGroup != NULL )
482  ExitGroup();
483 
484  ClearSelection();
485  m_enteredGroup = aGroup;
487  m_enteredGroup->RunOnChildren( [&]( BOARD_ITEM* titem )
488  {
489  select( titem );
490  } );
491 
493 }
494 
495 
496 void PCB_SELECTION_TOOL::ExitGroup( bool aSelectGroup )
497 {
498  // Only continue if there is a group entered
499  if( m_enteredGroup == nullptr )
500  return;
501 
503  ClearSelection();
504 
505  if( aSelectGroup )
507 
509  m_enteredGroup = nullptr;
510 }
511 
512 
514 {
515  return m_selection;
516 }
517 
518 
520  bool aConfirmLockedItems )
521 {
522  bool selectionEmpty = m_selection.Empty();
523  m_selection.SetIsHover( selectionEmpty );
524 
525  if( selectionEmpty )
526  {
527  m_toolMgr->RunAction( PCB_ACTIONS::selectionCursor, true, aClientFilter );
529  }
530 
531  if( aClientFilter )
532  {
533  enum DISPOSITION { BEFORE = 1, AFTER, BOTH };
534 
535  std::map<EDA_ITEM*, DISPOSITION> itemDispositions;
536  GENERAL_COLLECTOR collector;
537 
538  for( EDA_ITEM* item : m_selection )
539  {
540  collector.Append( item );
541  itemDispositions[ item ] = BEFORE;
542  }
543 
544  aClientFilter( VECTOR2I(), collector, this );
545 
546  for( EDA_ITEM* item : collector )
547  {
548  if( itemDispositions.count( item ) )
549  itemDispositions[ item ] = BOTH;
550  else
551  itemDispositions[ item ] = AFTER;
552  }
553 
554  // Unhighlight the BEFORE items before highlighting the AFTER items.
555  // This is so that in the case of groups, if aClientFilter replaces a selection
556  // with the enclosing group, the unhighlight of the element doesn't undo the
557  // recursive highlighting of that elemetn by the group.
558 
559  for( std::pair<EDA_ITEM* const, DISPOSITION> itemDisposition : itemDispositions )
560  {
561  BOARD_ITEM* item = static_cast<BOARD_ITEM*>( itemDisposition.first );
562  DISPOSITION disposition = itemDisposition.second;
563 
564  if( disposition == BEFORE )
565  {
566  unhighlight( item, SELECTED, &m_selection );
567  }
568  }
569 
570  for( std::pair<EDA_ITEM* const, DISPOSITION> itemDisposition : itemDispositions )
571  {
572  BOARD_ITEM* item = static_cast<BOARD_ITEM*>( itemDisposition.first );
573  DISPOSITION disposition = itemDisposition.second;
574 
575  if( disposition == AFTER )
576  {
577  highlight( item, SELECTED, &m_selection );
578  }
579  else if( disposition == BOTH )
580  {
581  // nothing to do
582  }
583  }
584 
586  }
587 
588  if( aConfirmLockedItems )
589  {
590  std::vector<BOARD_ITEM*> lockedItems;
591 
592  for( EDA_ITEM* item : m_selection )
593  {
594  BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( item );
595 
596  if( boardItem->Type() == PCB_GROUP_T )
597  {
598  PCB_GROUP* group = static_cast<PCB_GROUP*>( boardItem );
599  bool lockedDescendant = false;
600 
601  group->RunOnDescendants(
602  [&lockedDescendant]( BOARD_ITEM* child )
603  {
604  if( child->IsLocked() )
605  lockedDescendant = true;
606  } );
607 
608  if( lockedDescendant )
609  lockedItems.push_back( group );
610  }
611  else if( boardItem->IsLocked() )
612  {
613  lockedItems.push_back( boardItem );
614  }
615  }
616 
617  if( !lockedItems.empty() )
618  {
619  DIALOG_LOCKED_ITEMS_QUERY dlg( frame(), lockedItems.size() );
620 
621  switch( dlg.ShowModal() )
622  {
623  case wxID_OK:
624  // remove locked items from selection
625  for( BOARD_ITEM* item : lockedItems )
626  unselect( item );
627 
628  break;
629 
630  case wxID_CANCEL:
631  // cancel operation
632  ClearSelection();
633  break;
634 
635  case wxID_APPLY:
636  // continue with operation with current selection
637  break;
638  }
639  }
640  }
641 
642  return m_selection;
643 }
644 
645 
647 {
648  GENERAL_COLLECTORS_GUIDE guide( board()->GetVisibleLayers(),
649  (PCB_LAYER_ID) view()->GetTopLayer(), view() );
650 
651  bool padsDisabled = !board()->IsElementVisible( LAYER_PADS );
652 
653  // account for the globals
654  guide.SetIgnoreMTextsMarkedNoShow( ! board()->IsElementVisible( LAYER_MOD_TEXT_INVISIBLE ) );
655  guide.SetIgnoreMTextsOnBack( ! board()->IsElementVisible( LAYER_MOD_TEXT_BK ) );
656  guide.SetIgnoreMTextsOnFront( ! board()->IsElementVisible( LAYER_MOD_TEXT_FR ) );
657  guide.SetIgnoreModulesOnBack( ! board()->IsElementVisible( LAYER_MOD_BK ) );
658  guide.SetIgnoreModulesOnFront( ! board()->IsElementVisible( LAYER_MOD_FR ) );
659  guide.SetIgnorePadsOnBack( padsDisabled || ! board()->IsElementVisible( LAYER_PAD_BK ) );
660  guide.SetIgnorePadsOnFront( padsDisabled || ! board()->IsElementVisible( LAYER_PAD_FR ) );
661  guide.SetIgnoreThroughHolePads( padsDisabled || ! board()->IsElementVisible( LAYER_PADS_TH ) );
662  guide.SetIgnoreModulesVals( ! board()->IsElementVisible( LAYER_MOD_VALUES ) );
663  guide.SetIgnoreModulesRefs( ! board()->IsElementVisible( LAYER_MOD_REFERENCES ) );
664  guide.SetIgnoreThroughVias( ! board()->IsElementVisible( LAYER_VIAS ) );
665  guide.SetIgnoreBlindBuriedVias( ! board()->IsElementVisible( LAYER_VIAS ) );
666  guide.SetIgnoreMicroVias( ! board()->IsElementVisible( LAYER_VIAS ) );
667  guide.SetIgnoreTracks( ! board()->IsElementVisible( LAYER_TRACKS ) );
668 
669  return guide;
670 }
671 
672 
673 bool PCB_SELECTION_TOOL::selectPoint( const VECTOR2I& aWhere, bool aOnDrag,
674  bool* aSelectionCancelledFlag,
675  CLIENT_SELECTION_FILTER aClientFilter )
676 {
678  GENERAL_COLLECTOR collector;
679  const PCB_DISPLAY_OPTIONS& displayOpts = m_frame->GetDisplayOptions();
680 
682 
683  if( m_enteredGroup && !m_enteredGroup->GetBoundingBox().Contains( (wxPoint) aWhere ) )
684  ExitGroup();
685 
688  (wxPoint) aWhere, guide );
689 
690  // Remove unselectable items
691  for( int i = collector.GetCount() - 1; i >= 0; --i )
692  {
693  if( !Selectable( collector[ i ] ) || ( aOnDrag && collector[i]->IsLocked() ) )
694  collector.Remove( i );
695  }
696 
698 
699  // Allow the client to do tool- or action-specific filtering to see if we can get down
700  // to a single item
701  if( aClientFilter )
702  aClientFilter( aWhere, collector, this );
703 
704  // Apply the stateful filter
705  FilterCollectedItems( collector );
706 
707  FilterCollectorForGroups( collector );
708 
709  // Apply some ugly heuristics to avoid disambiguation menus whenever possible
710  if( collector.GetCount() > 1 && !m_skip_heuristics )
711  GuessSelectionCandidates( collector, aWhere );
712 
713  // If still more than one item we're going to have to ask the user.
714  if( collector.GetCount() > 1 )
715  {
716  if( aOnDrag )
718 
719  if( !doSelectionMenu( &collector ) )
720  {
721  if( aSelectionCancelledFlag )
722  *aSelectionCancelledFlag = true;
723 
724  return false;
725  }
726  }
727 
728  bool anyAdded = false;
729  bool anySubtracted = false;
730 
732  {
733  if( m_selection.GetSize() > 0 )
734  {
735  ClearSelection( true /*quiet mode*/ );
736  anySubtracted = true;
737  }
738  }
739 
740  if( collector.GetCount() > 0 )
741  {
742  for( int i = 0; i < collector.GetCount(); ++i )
743  {
744  if( m_subtractive || ( m_exclusive_or && collector[i]->IsSelected() ) )
745  {
746  unselect( collector[i] );
747  anySubtracted = true;
748  }
749  else
750  {
751  select( collector[i] );
752  anyAdded = true;
753  }
754  }
755  }
756 
757  if( anyAdded )
758  {
760  return true;
761  }
762  else if( anySubtracted )
763  {
765  return true;
766  }
767 
768  return false;
769 }
770 
771 
772 bool PCB_SELECTION_TOOL::selectCursor( bool aForceSelect, CLIENT_SELECTION_FILTER aClientFilter )
773 {
774  if( aForceSelect || m_selection.Empty() )
775  {
776  ClearSelection( true /*quiet mode*/ );
777  selectPoint( getViewControls()->GetCursorPosition( false ), false, NULL, aClientFilter );
778  }
779 
780  return !m_selection.Empty();
781 }
782 
783 
785 {
786  bool cancelled = false; // Was the tool cancelled while it was running?
787  m_multiple = true; // Multiple selection mode is active
788  KIGFX::VIEW* view = getView();
789 
791  view->Add( &area );
792 
793  bool anyAdded = false;
794  bool anySubtracted = false;
795 
796  while( TOOL_EVENT* evt = Wait() )
797  {
798  int width = area.GetEnd().x - area.GetOrigin().x;
799 
800  /* Selection mode depends on direction of drag-selection:
801  * Left > Right : Select objects that are fully enclosed by selection
802  * Right > Left : Select objects that are crossed by selection
803  */
804  bool windowSelection = width >= 0 ? true : false;
805 
806  if( view->IsMirroredX() )
807  windowSelection = !windowSelection;
808 
810  windowSelection ? KICURSOR::SELECT_WINDOW : KICURSOR::SELECT_LASSO );
811 
812  if( evt->IsCancelInteractive() || evt->IsActivate() )
813  {
814  cancelled = true;
815  break;
816  }
817 
818  if( evt->IsDrag( BUT_LEFT ) )
819  {
821  {
822  if( m_selection.GetSize() > 0 )
823  {
824  anySubtracted = true;
825  ClearSelection( true /*quiet mode*/ );
826  }
827  }
828 
829  // Start drawing a selection box
830  area.SetOrigin( evt->DragOrigin() );
831  area.SetEnd( evt->Position() );
832  area.SetAdditive( m_additive );
835 
836  view->SetVisible( &area, true );
837  view->Update( &area );
838  getViewControls()->SetAutoPan( true );
839  }
840 
841  if( evt->IsMouseUp( BUT_LEFT ) )
842  {
843  getViewControls()->SetAutoPan( false );
844 
845  // End drawing the selection box
846  view->SetVisible( &area, false );
847 
848  std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> candidates;
849  BOX2I selectionBox = area.ViewBBox();
850  view->Query( selectionBox, candidates ); // Get the list of nearby items
851 
852  int height = area.GetEnd().y - area.GetOrigin().y;
853 
854  // Construct an EDA_RECT to determine BOARD_ITEM selection
855  EDA_RECT selectionRect( (wxPoint) area.GetOrigin(), wxSize( width, height ) );
856 
857  selectionRect.Normalize();
858 
859  GENERAL_COLLECTOR collector;
860 
861  for( auto it = candidates.begin(), it_end = candidates.end(); it != it_end; ++it )
862  {
863  BOARD_ITEM* item = static_cast<BOARD_ITEM*>( it->first );
864 
865  if( item && Selectable( item ) && item->HitTest( selectionRect, windowSelection ) )
866  collector.Append( item );
867  }
868 
869  // Apply the stateful filter
870  FilterCollectedItems( collector );
871 
872  FilterCollectorForGroups( collector );
873 
874  for( EDA_ITEM* i : collector )
875  {
876  BOARD_ITEM* item = static_cast<BOARD_ITEM*>( i );
877 
878  if( m_subtractive || ( m_exclusive_or && item->IsSelected() ) )
879  {
880  unselect( item );
881  anySubtracted = true;
882  }
883  else
884  {
885  select( item );
886  anyAdded = true;
887  }
888  }
889 
890  m_selection.SetIsHover( false );
891 
892  // Inform other potentially interested tools
893  if( anyAdded )
895  else if( anySubtracted )
897 
898  break; // Stop waiting for events
899  }
900  }
901 
902  getViewControls()->SetAutoPan( false );
903 
904  // Stop drawing the selection box
905  view->Remove( &area );
906  m_multiple = false; // Multiple selection mode is inactive
907 
908  if( !cancelled )
910 
912 
913  return cancelled;
914 }
915 
916 
918 {
920 
921  selectCursor( false, aClientFilter );
922 
923  return 0;
924 }
925 
926 
928 {
929  ClearSelection();
930 
931  return 0;
932 }
933 
934 
936 {
937  std::vector<BOARD_ITEM*>* items = aEvent.Parameter<std::vector<BOARD_ITEM*>*>();
938 
939  if( items )
940  {
941  // Perform individual selection of each item before processing the event.
942  for( BOARD_ITEM* item : *items )
943  select( item );
944 
946  }
947 
948  return 0;
949 }
950 
951 
953 {
954  AddItemToSel( aEvent.Parameter<BOARD_ITEM*>() );
955  return 0;
956 }
957 
958 
960 {
961  KIGFX::VIEW* view = getView();
962 
963  // hold all visible items
964  std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> selectedItems;
965 
966  // Filter the view items based on the selection box
967  BOX2I selectionBox;
968 
969  selectionBox.SetMaximum();
970  view->Query( selectionBox, selectedItems ); // Get the list of selected items
971 
972  for( const KIGFX::VIEW::LAYER_ITEM_PAIR& item_pair : selectedItems )
973  {
974  BOARD_ITEM* item = static_cast<BOARD_ITEM*>( item_pair.first );
975 
976  if( !item || !Selectable( item ) || !itemPassesFilter( item ) )
977  continue;
978 
979  select( item );
980  }
981 
983 
984  return 0;
985 }
986 
987 
988 void PCB_SELECTION_TOOL::AddItemToSel( BOARD_ITEM* aItem, bool aQuietMode )
989 {
990  if( aItem )
991  {
992  select( aItem );
993 
994  // Inform other potentially interested tools
995  if( !aQuietMode )
997  }
998 }
999 
1000 
1002 {
1003  std::vector<BOARD_ITEM*>* items = aEvent.Parameter<std::vector<BOARD_ITEM*>*>();
1004 
1005  if( items )
1006  {
1007  // Perform individual unselection of each item before processing the event
1008  for( auto item : *items )
1009  unselect( item );
1010 
1012  }
1013 
1014  return 0;
1015 }
1016 
1017 
1019 {
1020  RemoveItemFromSel( aEvent.Parameter<BOARD_ITEM*>() );
1021  return 0;
1022 }
1023 
1024 
1025 void PCB_SELECTION_TOOL::RemoveItemFromSel( BOARD_ITEM* aItem, bool aQuietMode )
1026 {
1027  if( aItem )
1028  {
1029  unselect( aItem );
1030 
1031  // Inform other potentially interested tools
1033  }
1034 }
1035 
1036 
1038 {
1039  highlight( aItem, BRIGHTENED );
1040 }
1041 
1042 
1044 {
1045  unhighlight( aItem, BRIGHTENED );
1046 }
1047 
1048 
1050  PCB_SELECTION_TOOL* sTool )
1051 {
1052  // Narrow the collection down to a single BOARD_CONNECTED_ITEM for each represented net.
1053  // All other items types are removed.
1054  std::set<int> representedNets;
1055 
1056  for( int i = aCollector.GetCount() - 1; i >= 0; i-- )
1057  {
1058  BOARD_CONNECTED_ITEM* item = dynamic_cast<BOARD_CONNECTED_ITEM*>( aCollector[i] );
1059  if( !item )
1060  aCollector.Remove( i );
1061  else if ( representedNets.count( item->GetNetCode() ) )
1062  aCollector.Remove( i );
1063  else
1064  representedNets.insert( item->GetNetCode() );
1065  }
1066 }
1067 
1068 
1070 {
1071  unsigned initialCount = 0;
1072 
1073  for( auto item : m_selection.GetItems() )
1074  {
1075  if( dynamic_cast<BOARD_CONNECTED_ITEM*>( item ) )
1076  initialCount++;
1077  }
1078 
1079  if( initialCount == 0 )
1081 
1082  for( STOP_CONDITION stopCondition : { STOP_AT_JUNCTION, STOP_AT_PAD, STOP_NEVER } )
1083  {
1084  // copy the selection, since we're going to iterate and modify
1085  std::deque<EDA_ITEM*> selectedItems = m_selection.GetItems();
1086 
1087  for( EDA_ITEM* item : selectedItems )
1088  item->ClearTempFlags();
1089 
1090  for( EDA_ITEM* item : selectedItems )
1091  {
1092  TRACK* trackItem = dynamic_cast<TRACK*>( item );
1093 
1094  // Track items marked SKIP_STRUCT have already been visited
1095  if( trackItem && !( trackItem->GetFlags() & SKIP_STRUCT ) )
1096  selectConnectedTracks( *trackItem, stopCondition );
1097  }
1098 
1099  if( m_selection.GetItems().size() > initialCount )
1100  break;
1101  }
1102 
1103  // Inform other potentially interested tools
1104  if( m_selection.Size() > 0 )
1106 
1107  return 0;
1108 }
1109 
1110 
1112  STOP_CONDITION aStopCondition )
1113 {
1114  constexpr KICAD_T types[] = { PCB_TRACE_T, PCB_ARC_T, PCB_VIA_T, PCB_PAD_T, EOT };
1115 
1116  auto connectivity = board()->GetConnectivity();
1117  auto connectedItems = connectivity->GetConnectedItems( &aStartItem, types, true );
1118 
1119  std::map<wxPoint, std::vector<TRACK*>> trackMap;
1120  std::map<wxPoint, VIA*> viaMap;
1121  std::map<wxPoint, PAD*> padMap;
1122 
1123  // Build maps of connected items
1124  for( BOARD_CONNECTED_ITEM* item : connectedItems )
1125  {
1126  switch( item->Type() )
1127  {
1128  case PCB_ARC_T:
1129  case PCB_TRACE_T:
1130  {
1131  TRACK* track = static_cast<TRACK*>( item );
1132  trackMap[ track->GetStart() ].push_back( track );
1133  trackMap[ track->GetEnd() ].push_back( track );
1134  }
1135  break;
1136 
1137  case PCB_VIA_T:
1138  {
1139  VIA* via = static_cast<VIA*>( item );
1140  viaMap[ via->GetStart() ] = via;
1141  }
1142  break;
1143 
1144  case PCB_PAD_T:
1145  {
1146  PAD* pad = static_cast<PAD*>( item );
1147  padMap[ pad->GetPosition() ] = pad;
1148  }
1149  break;
1150 
1151  default:
1152  break;
1153  }
1154 
1155  item->SetState( SKIP_STRUCT, false );
1156  }
1157 
1158  std::vector<wxPoint> activePts;
1159 
1160  // Set up the initial active points
1161  switch( aStartItem.Type() )
1162  {
1163  case PCB_ARC_T:
1164  case PCB_TRACE_T:
1165  activePts.push_back( static_cast<TRACK*>( &aStartItem )->GetStart() );
1166  activePts.push_back( static_cast<TRACK*>( &aStartItem )->GetEnd() );
1167  break;
1168 
1169  case PCB_VIA_T:
1170  activePts.push_back( static_cast<TRACK*>( &aStartItem )->GetStart() );
1171  break;
1172 
1173  case PCB_PAD_T:
1174  activePts.push_back( aStartItem.GetPosition() );
1175  break;
1176 
1177  default:
1178  break;
1179  }
1180 
1181  bool expand = true;
1182 
1183  // Iterative push from all active points
1184  while( expand )
1185  {
1186  expand = false;
1187 
1188  for( int i = activePts.size() - 1; i >= 0; --i )
1189  {
1190  wxPoint pt = activePts[i];
1191  size_t pt_count = trackMap[ pt ].size() + viaMap.count( pt );
1192 
1193  if( pt_count > 2 && aStopCondition == STOP_AT_JUNCTION )
1194  {
1195  activePts.erase( activePts.begin() + i );
1196  continue;
1197  }
1198 
1199  if( padMap.count( pt ) && aStopCondition != STOP_NEVER )
1200  {
1201  activePts.erase( activePts.begin() + i );
1202  continue;
1203  }
1204 
1205  for( TRACK* track : trackMap[ pt ] )
1206  {
1207  if( track->GetState( SKIP_STRUCT ) )
1208  continue;
1209 
1210  track->SetState( SKIP_STRUCT, true );
1211  select( track );
1212 
1213  if( track->GetStart() == pt )
1214  activePts.push_back( track->GetEnd() );
1215  else
1216  activePts.push_back( track->GetStart() );
1217 
1218  expand = true;
1219  }
1220 
1221  if( viaMap.count( pt ) && !viaMap[ pt ]->IsSelected() && aStopCondition != STOP_AT_JUNCTION )
1222  select( viaMap[ pt ] );
1223 
1224  activePts.erase( activePts.begin() + i );
1225  }
1226  }
1227 }
1228 
1229 
1230 void PCB_SELECTION_TOOL::selectAllItemsOnNet( int aNetCode, bool aSelect )
1231 {
1232  constexpr KICAD_T types[] = { PCB_TRACE_T, PCB_ARC_T, PCB_VIA_T, EOT };
1233  auto connectivity = board()->GetConnectivity();
1234 
1235  for( BOARD_CONNECTED_ITEM* item : connectivity->GetNetItems( aNetCode, types ) )
1236  if( itemPassesFilter( item ) )
1237  aSelect ? select( item ) : unselect( item );
1238 }
1239 
1240 
1242 {
1243  bool select = aEvent.IsAction( &PCB_ACTIONS::selectNet );
1244 
1245  // If we've been passed an argument, just select that netcode1
1246  int netcode = aEvent.Parameter<intptr_t>();
1247 
1248  if( netcode > 0 )
1249  {
1250  selectAllItemsOnNet( netcode, select );
1251  return 0;
1252  }
1253 
1254  if( !selectCursor() )
1255  return 0;
1256 
1257  // copy the selection, since we're going to iterate and modify
1258  auto selection = m_selection.GetItems();
1259 
1260  for( EDA_ITEM* i : selection )
1261  {
1262  BOARD_CONNECTED_ITEM* connItem = dynamic_cast<BOARD_CONNECTED_ITEM*>( i );
1263 
1264  if( connItem )
1265  selectAllItemsOnNet( connItem->GetNetCode(), select );
1266  }
1267 
1268  // Inform other potentially interested tools
1269  if( m_selection.Size() > 0 )
1271 
1272  return 0;
1273 }
1274 
1275 
1276 void PCB_SELECTION_TOOL::selectAllItemsOnSheet( wxString& aSheetPath )
1277 {
1278  std::list<FOOTPRINT*> footprintList;
1279 
1280  // store all footprints that are on that sheet path
1281  for( FOOTPRINT* footprint : board()->Footprints() )
1282  {
1283  if( footprint == nullptr )
1284  continue;
1285 
1286  wxString footprint_path = footprint->GetPath().AsString().BeforeLast('/');
1287 
1288  if( aSheetPath.IsEmpty() )
1289  aSheetPath += '/';
1290 
1291  if( footprint_path == aSheetPath )
1292  footprintList.push_back( footprint );
1293  }
1294 
1295  //Generate a list of all pads, and of all nets they belong to.
1296  std::list<int> netcodeList;
1297  std::list<PAD*> padList;
1298 
1299  for( FOOTPRINT* footprint : footprintList )
1300  {
1301  for( PAD* pad : footprint->Pads() )
1302  {
1303  if( pad->IsConnected() )
1304  {
1305  netcodeList.push_back( pad->GetNetCode() );
1306  padList.push_back( pad );
1307  }
1308  }
1309  }
1310  // remove all duplicates
1311  netcodeList.sort();
1312  netcodeList.unique();
1313 
1314  for( PAD* pad : padList )
1316 
1317  // now we need to find all footprints that are connected to each of these nets then we need
1318  // to determine if these footprints are in the list of footprints belonging to this sheet
1319  std::list<int> removeCodeList;
1320  constexpr KICAD_T padType[] = { PCB_PAD_T, EOT };
1321 
1322  for( int netCode : netcodeList )
1323  {
1324  for( BOARD_CONNECTED_ITEM* mitem : board()->GetConnectivity()->GetNetItems( netCode, padType ) )
1325  {
1326  if( mitem->Type() == PCB_PAD_T && !alg::contains( footprintList, mitem->GetParent() ) )
1327  {
1328  // if we cannot find the footprint of the pad in the footprintList then we can
1329  // assume that that footprint is not located in the same schematic, therefore
1330  // invalidate this netcode.
1331  removeCodeList.push_back( netCode );
1332  break;
1333  }
1334  }
1335  }
1336 
1337  // remove all duplicates
1338  removeCodeList.sort();
1339  removeCodeList.unique();
1340 
1341  for( int removeCode : removeCodeList )
1342  {
1343  netcodeList.remove( removeCode );
1344  }
1345 
1346  std::list<BOARD_CONNECTED_ITEM*> localConnectionList;
1347  constexpr KICAD_T trackViaType[] = { PCB_TRACE_T, PCB_ARC_T, PCB_VIA_T, EOT };
1348 
1349  for( int netCode : netcodeList )
1350  {
1351  for( BOARD_CONNECTED_ITEM* item : board()->GetConnectivity()->GetNetItems( netCode, trackViaType ) )
1352  localConnectionList.push_back( item );
1353  }
1354 
1355  for( BOARD_ITEM* i : footprintList )
1356  {
1357  if( i != NULL )
1358  select( i );
1359  }
1360 
1361  for( BOARD_CONNECTED_ITEM* i : localConnectionList )
1362  {
1363  if( i != NULL )
1364  select( i );
1365  }
1366 }
1367 
1368 
1370 {
1371  //Should recalculate the view to zoom in on the selection
1372  auto selectionBox = m_selection.GetBoundingBox();
1373  auto view = getView();
1374 
1375  VECTOR2D screenSize = view->ToWorld( m_frame->GetCanvas()->GetClientSize(), false );
1376  screenSize.x = std::max( 10.0, screenSize.x );
1377  screenSize.y = std::max( 10.0, screenSize.y );
1378 
1379  if( selectionBox.GetWidth() != 0 || selectionBox.GetHeight() != 0 )
1380  {
1381  VECTOR2D vsize = selectionBox.GetSize();
1382  double scale = view->GetScale() / std::max( fabs( vsize.x / screenSize.x ),
1383  fabs( vsize.y / screenSize.y ) );
1384  view->SetScale( scale );
1385  view->SetCenter( selectionBox.Centre() );
1386  view->Add( &m_selection );
1387  }
1388 
1390 }
1391 
1392 
1394 {
1395  ClearSelection( true /*quiet mode*/ );
1396  wxString sheetPath = *aEvent.Parameter<wxString*>();
1397 
1398  selectAllItemsOnSheet( sheetPath );
1399 
1400  zoomFitSelection();
1401 
1402  if( m_selection.Size() > 0 )
1404 
1405  return 0;
1406 }
1407 
1408 
1410 {
1411  if( !selectCursor( true ) )
1412  return 0;
1413 
1414  // this function currently only supports footprints since they are only
1415  // on one sheet.
1416  auto item = m_selection.Front();
1417 
1418  if( !item )
1419  return 0;
1420 
1421  if( item->Type() != PCB_FOOTPRINT_T )
1422  return 0;
1423 
1424  FOOTPRINT* footprint = dynamic_cast<FOOTPRINT*>( item );
1425 
1426  if( footprint->GetPath().empty() )
1427  return 0;
1428 
1429  ClearSelection( true /*quiet mode*/ );
1430 
1431  // get the sheet path only.
1432  wxString sheetPath = footprint->GetPath().AsString().BeforeLast( '/' );
1433 
1434  if( sheetPath.IsEmpty() )
1435  sheetPath += '/';
1436 
1437  selectAllItemsOnSheet( sheetPath );
1438 
1439  // Inform other potentially interested tools
1440  if( m_selection.Size() > 0 )
1442 
1443  return 0;
1444 }
1445 
1446 
1448 {
1449  bool cleared = false;
1450 
1451  if( m_selection.GetSize() > 0 )
1452  {
1453  // Don't fire an event now; most of the time it will be redundant as we're about to
1454  // fire a SelectedEvent.
1455  cleared = true;
1456  ClearSelection( true /*quiet mode*/ );
1457  }
1458 
1459  if( aItem )
1460  {
1461  select( aItem );
1462  m_frame->FocusOnLocation( aItem->GetPosition() );
1463 
1464  // Inform other potentially interested tools
1466  }
1467  else if( cleared )
1468  {
1470  }
1471 
1473 }
1474 
1475 
1477 {
1478  DIALOG_FIND dlg( m_frame );
1479  dlg.SetCallback( std::bind( &PCB_SELECTION_TOOL::findCallback, this, _1 ) );
1480  dlg.ShowModal();
1481 
1482  return 0;
1483 }
1484 
1485 
1493 static bool itemIsIncludedByFilter( const BOARD_ITEM& aItem, const BOARD& aBoard,
1494  const DIALOG_FILTER_SELECTION::OPTIONS& aFilterOptions )
1495 {
1496  bool include = true;
1497  const PCB_LAYER_ID layer = aItem.GetLayer();
1498 
1499  // if the item needs to be checked against the options
1500  if( include )
1501  {
1502  switch( aItem.Type() )
1503  {
1504  case PCB_FOOTPRINT_T:
1505  {
1506  const FOOTPRINT& footprint = static_cast<const FOOTPRINT&>( aItem );
1507 
1508  include = aFilterOptions.includeModules;
1509 
1510  if( include && !aFilterOptions.includeLockedModules )
1511  include = !footprint.IsLocked();
1512 
1513  break;
1514  }
1515  case PCB_TRACE_T:
1516  case PCB_ARC_T:
1517  include = aFilterOptions.includeTracks;
1518  break;
1519 
1520  case PCB_VIA_T:
1521  include = aFilterOptions.includeVias;
1522  break;
1523 
1524  case PCB_ZONE_T:
1525  include = aFilterOptions.includeZones;
1526  break;
1527 
1528  case PCB_SHAPE_T:
1529  case PCB_TARGET_T:
1530  case PCB_DIM_ALIGNED_T:
1531  case PCB_DIM_CENTER_T:
1532  case PCB_DIM_ORTHOGONAL_T:
1533  case PCB_DIM_LEADER_T:
1534  if( layer == Edge_Cuts )
1535  include = aFilterOptions.includeBoardOutlineLayer;
1536  else
1537  include = aFilterOptions.includeItemsOnTechLayers;
1538  break;
1539 
1540  case PCB_TEXT_T:
1541  include = aFilterOptions.includePcbTexts;
1542  break;
1543 
1544  default:
1545  // no filtering, just select it
1546  break;
1547  }
1548  }
1549 
1550  return include;
1551 }
1552 
1553 
1555 {
1556  const BOARD& board = *getModel<BOARD>();
1557  DIALOG_FILTER_SELECTION::OPTIONS& opts = m_priv->m_filterOpts;
1558  DIALOG_FILTER_SELECTION dlg( m_frame, opts );
1559 
1560  const int cmd = dlg.ShowModal();
1561 
1562  if( cmd != wxID_OK )
1563  return 0;
1564 
1565  // copy current selection
1566  std::deque<EDA_ITEM*> selection = m_selection.GetItems();
1567 
1568  ClearSelection( true /*quiet mode*/ );
1569 
1570  // re-select items from the saved selection according to the dialog options
1571  for( EDA_ITEM* i : selection )
1572  {
1573  BOARD_ITEM* item = static_cast<BOARD_ITEM*>( i );
1574  bool include = itemIsIncludedByFilter( *item, board, opts );
1575 
1576  if( include )
1577  select( item );
1578  }
1579 
1581 
1582  return 0;
1583 }
1584 
1585 
1587 {
1588  if( aCollector.GetCount() == 0 )
1589  return;
1590 
1591  std::set<BOARD_ITEM*> rejected;
1592 
1593  for( EDA_ITEM* i : aCollector )
1594  {
1595  BOARD_ITEM* item = static_cast<BOARD_ITEM*>( i );
1596 
1597  if( !itemPassesFilter( item ) )
1598  rejected.insert( item );
1599  }
1600 
1601  for( BOARD_ITEM* item : rejected )
1602  aCollector.Remove( item );
1603 }
1604 
1605 
1607 {
1608  if( aItem->IsLocked() && !m_filter.lockedItems && aItem->Type() != PCB_PAD_T )
1609  return false;
1610 
1611  switch( aItem->Type() )
1612  {
1613  case PCB_FOOTPRINT_T:
1614  if( !m_filter.footprints )
1615  return false;
1616 
1617  break;
1618 
1619  case PCB_PAD_T:
1620  if( !m_filter.pads )
1621  return false;
1622 
1623  break;
1624 
1625  case PCB_TRACE_T:
1626  case PCB_ARC_T:
1627  if( !m_filter.tracks )
1628  return false;
1629 
1630  break;
1631 
1632  case PCB_VIA_T:
1633  if( !m_filter.vias )
1634  return false;
1635 
1636  break;
1637 
1638  case PCB_FP_ZONE_T:
1639  case PCB_ZONE_T:
1640  {
1641  ZONE* zone = static_cast<ZONE*>( aItem );
1642 
1643  if( ( !m_filter.zones && !zone->GetIsRuleArea() )
1644  || ( !m_filter.keepouts && zone->GetIsRuleArea() ) )
1645  {
1646  return false;
1647  }
1648  }
1649  break;
1650 
1651  case PCB_FP_SHAPE_T:
1652  case PCB_SHAPE_T:
1653  case PCB_TARGET_T:
1654  if( !m_filter.graphics )
1655  return false;
1656 
1657  break;
1658 
1659  case PCB_FP_TEXT_T:
1660  case PCB_TEXT_T:
1661  if( !m_filter.text )
1662  return false;
1663 
1664  break;
1665 
1666  case PCB_DIM_ALIGNED_T:
1667  case PCB_DIM_CENTER_T:
1668  case PCB_DIM_ORTHOGONAL_T:
1669  case PCB_DIM_LEADER_T:
1670  if( !m_filter.dimensions )
1671  return false;
1672 
1673  break;
1674 
1675  default:
1676  if( !m_filter.otherItems )
1677  return false;
1678  }
1679 
1680  return true;
1681 }
1682 
1683 
1684 void PCB_SELECTION_TOOL::ClearSelection( bool aQuietMode )
1685 {
1686  if( m_selection.Empty() )
1687  return;
1688 
1689  while( m_selection.GetSize() )
1690  unhighlight( static_cast<BOARD_ITEM*>( m_selection.Front() ), SELECTED, &m_selection );
1691 
1692  view()->Update( &m_selection );
1693 
1694  m_selection.SetIsHover( false );
1696 
1697  // Inform other potentially interested tools
1698  if( !aQuietMode )
1699  {
1702  }
1703 }
1704 
1705 
1707 {
1708  m_selection.Clear();
1709 
1710  bool enteredGroupFound = false;
1711 
1712  INSPECTOR_FUNC inspector =
1713  [&]( EDA_ITEM* item, void* testData )
1714  {
1715  if( item->IsSelected() )
1716  {
1717  EDA_ITEM* parent = item->GetParent();
1718 
1719  // Let selected parents handle their children.
1720  if( parent && parent->IsSelected() )
1721  return SEARCH_RESULT::CONTINUE;
1722 
1723  highlight( (BOARD_ITEM*) item, SELECTED, &m_selection );
1724  }
1725 
1726  if( item == m_enteredGroup )
1727  {
1728  item->SetFlags( ENTERED );
1729  enteredGroupFound = true;
1730  }
1731  else
1732  {
1733  item->ClearFlags( ENTERED );
1734  }
1735 
1736  return SEARCH_RESULT::CONTINUE;
1737  };
1738 
1741 
1742  if( !enteredGroupFound )
1743  {
1745  m_enteredGroup = nullptr;
1746  }
1747 }
1748 
1749 
1751 {
1752  GENERAL_COLLECTOR* collector = aEvent.Parameter<GENERAL_COLLECTOR*>();
1753 
1754  doSelectionMenu( collector );
1755 
1756  return 0;
1757 }
1758 
1759 
1761 {
1762  BOARD_ITEM* current = nullptr;
1763  PCB_SELECTION highlightGroup;
1764  bool selectAll = false;
1765  bool expandSelection = false;
1766 
1767  highlightGroup.SetLayer( LAYER_SELECT_OVERLAY );
1768  getView()->Add( &highlightGroup );
1769 
1770  do
1771  {
1773  if( expandSelection )
1774  aCollector->Combine();
1775 
1776  expandSelection = false;
1777 
1778  int limit = std::min( 9, aCollector->GetCount() );
1779  ACTION_MENU menu( true );
1780 
1781  for( int i = 0; i < limit; ++i )
1782  {
1783  wxString text;
1784  BOARD_ITEM* item = ( *aCollector )[i];
1785  text = item->GetSelectMenuText( m_frame->GetUserUnits() );
1786 
1787  wxString menuText = wxString::Format( "&%d. %s\t%d", i + 1, text, i + 1 );
1788  menu.Add( menuText, i + 1, item->GetMenuImage() );
1789  }
1790 
1791  menu.AppendSeparator();
1792  menu.Add( _( "Select &All\tA" ), limit + 1, nullptr );
1793 
1794  if( !expandSelection && aCollector->HasAdditionalItems() )
1795  menu.Add( _( "&Expand Selection\tE" ), limit + 2, nullptr );
1796 
1797  if( aCollector->m_MenuTitle.Length() )
1798  {
1799  menu.SetTitle( aCollector->m_MenuTitle );
1800  menu.SetIcon( info_xpm );
1801  menu.DisplayTitle( true );
1802  }
1803  else
1804  {
1805  menu.DisplayTitle( false );
1806  }
1807 
1808  SetContextMenu( &menu, CMENU_NOW );
1809 
1810  while( TOOL_EVENT* evt = Wait() )
1811  {
1812  if( evt->Action() == TA_CHOICE_MENU_UPDATE )
1813  {
1814  if( selectAll )
1815  {
1816  for( int i = 0; i < aCollector->GetCount(); ++i )
1817  unhighlight( ( *aCollector )[i], BRIGHTENED, &highlightGroup );
1818  }
1819  else if( current )
1820  unhighlight( current, BRIGHTENED, &highlightGroup );
1821 
1822  int id = *evt->GetCommandId();
1823 
1824  // User has pointed an item, so show it in a different way
1825  if( id > 0 && id <= limit )
1826  {
1827  current = ( *aCollector )[id - 1];
1828  highlight( current, BRIGHTENED, &highlightGroup );
1829  }
1830  else
1831  current = nullptr;
1832 
1833  // User has pointed on the "Select All" option
1834  if( id == limit + 1 )
1835  {
1836  for( int i = 0; i < aCollector->GetCount(); ++i )
1837  highlight( ( *aCollector )[i], BRIGHTENED, &highlightGroup );
1838  selectAll = true;
1839  }
1840  else
1841  selectAll = false;
1842  }
1843  else if( evt->Action() == TA_CHOICE_MENU_CHOICE )
1844  {
1845  if( selectAll )
1846  {
1847  for( int i = 0; i < aCollector->GetCount(); ++i )
1848  unhighlight( ( *aCollector )[i], BRIGHTENED, &highlightGroup );
1849  }
1850  else if( current )
1851  unhighlight( current, BRIGHTENED, &highlightGroup );
1852 
1853  OPT<int> id = evt->GetCommandId();
1854 
1855  // User has selected the "Select All" option
1856  if( id == limit + 1 )
1857  {
1858  selectAll = true;
1859  current = nullptr;
1860  }
1861  else if( id == limit + 2 )
1862  {
1863  expandSelection = true;
1864  selectAll = false;
1865  current = nullptr;
1866  }
1867  // User has selected an item, so this one will be returned
1868  else if( id && ( *id > 0 ) && ( *id <= limit ) )
1869  {
1870  selectAll = false;
1871  current = ( *aCollector )[*id - 1];
1872  }
1873  else
1874  {
1875  selectAll = false;
1876  current = nullptr;
1877  }
1878  }
1879  else if( evt->Action() == TA_CHOICE_MENU_CLOSED )
1880  {
1881  break;
1882  }
1883  }
1884  } while( expandSelection );
1885 
1886  getView()->Remove( &highlightGroup );
1887 
1888  if( selectAll )
1889  return true;
1890  else if( current )
1891  {
1892  aCollector->Empty();
1893  aCollector->Append( current );
1894  return true;
1895  }
1896 
1897  return false;
1898 }
1899 
1900 
1901 bool PCB_SELECTION_TOOL::Selectable( const BOARD_ITEM* aItem, bool checkVisibilityOnly ) const
1902 {
1903  const RENDER_SETTINGS* settings = getView()->GetPainter()->GetSettings();
1904 
1905  if( settings->GetHighContrast() )
1906  {
1907  std::set<unsigned int> activeLayers = settings->GetHighContrastLayers();
1908  bool onActiveLayer = false;
1909 
1910  for( unsigned int layer : activeLayers )
1911  {
1912  // NOTE: Only checking the regular layers (not GAL meta-layers)
1913  if( layer < PCB_LAYER_ID_COUNT && aItem->IsOnLayer( ToLAYER_ID( layer ) ) )
1914  {
1915  onActiveLayer = true;
1916  break;
1917  }
1918  }
1919 
1920  if( !onActiveLayer ) // We do not want to select items that are in the background
1921  return false;
1922  }
1923 
1924  if( aItem->Type() == PCB_FOOTPRINT_T )
1925  {
1926  // In footprint editor, we do not want to select the footprint itself.
1927  if( m_isFootprintEditor )
1928  return false;
1929 
1930  // Allow selection of footprints if some part of the footprint is visible.
1931 
1932  const FOOTPRINT* footprint = static_cast<const FOOTPRINT*>( aItem );
1933 
1934  for( const BOARD_ITEM* item : footprint->GraphicalItems() )
1935  {
1936  if( Selectable( item, true ) )
1937  return true;
1938  }
1939 
1940  for( const PAD* pad : footprint->Pads() )
1941  {
1942  if( Selectable( pad, true ) )
1943  return true;
1944  }
1945 
1946  for( const ZONE* zone : footprint->Zones() )
1947  {
1948  if( Selectable( zone, true ) )
1949  return true;
1950  }
1951 
1952  return false;
1953  }
1954  else if( aItem->Type() == PCB_GROUP_T )
1955  {
1956  PCB_GROUP* group = const_cast<PCB_GROUP*>( static_cast<const PCB_GROUP*>( aItem ) );
1957 
1958  // Similar to logic for footprint, a group is selectable if any of its members are.
1959  // (This recurses.)
1960  for( BOARD_ITEM* item : group->GetItems() )
1961  {
1962  if( Selectable( item, true ) )
1963  return true;
1964  }
1965 
1966  return false;
1967  }
1968 
1969  const ZONE* zone = nullptr;
1970  const VIA* via = nullptr;
1971  const PAD* pad = nullptr;
1972 
1973  switch( aItem->Type() )
1974  {
1975  case PCB_ZONE_T:
1976  case PCB_FP_ZONE_T:
1977  if( !board()->IsElementVisible( LAYER_ZONES ) )
1978  return false;
1979 
1980  zone = static_cast<const ZONE*>( aItem );
1981 
1982  // A footprint zone is only selectable within the footprint editor
1983  if( zone->GetParent()
1984  && zone->GetParent()->Type() == PCB_FOOTPRINT_T
1986  && !checkVisibilityOnly )
1987  {
1988  return false;
1989  }
1990 
1991  // zones can exist on multiple layers!
1992  if( !( zone->GetLayerSet() & board()->GetVisibleLayers() ).any() )
1993  return false;
1994 
1995  break;
1996 
1997  case PCB_TRACE_T:
1998  case PCB_ARC_T:
1999  if( !board()->IsElementVisible( LAYER_TRACKS ) )
2000  return false;
2001 
2002  if( m_isFootprintEditor )
2003  {
2004  if( !view()->IsLayerVisible( aItem->GetLayer() ) )
2005  return false;
2006  }
2007  else
2008  {
2009  if( !board()->IsLayerVisible( aItem->GetLayer() ) )
2010  return false;
2011  }
2012 
2013  break;
2014 
2015  case PCB_VIA_T:
2016  if( !board()->IsElementVisible( LAYER_VIAS ) )
2017  return false;
2018 
2019  via = static_cast<const VIA*>( aItem );
2020 
2021  // For vias it is enough if only one of its layers is visible
2022  if( !( board()->GetVisibleLayers() & via->GetLayerSet() ).any() )
2023  return false;
2024 
2025  break;
2026 
2027  case PCB_FP_TEXT_T:
2028  if( m_isFootprintEditor )
2029  {
2030  if( !view()->IsLayerVisible( aItem->GetLayer() ) )
2031  return false;
2032  }
2033  else
2034  {
2035  if( !view()->IsVisible( aItem ) )
2036  return false;
2037 
2038  if( !board()->IsLayerVisible( aItem->GetLayer() ) )
2039  return false;
2040  }
2041 
2042  break;
2043 
2044  case PCB_FP_SHAPE_T:
2045  if( m_isFootprintEditor )
2046  {
2047  if( !view()->IsLayerVisible( aItem->GetLayer() ) )
2048  return false;
2049  }
2050  else
2051  {
2052  // Footprint shape selections are only allowed in footprint editor mode.
2053  if( !checkVisibilityOnly )
2054  return false;
2055 
2056  if( !board()->IsLayerVisible( aItem->GetLayer() ) )
2057  return false;
2058  }
2059 
2060  break;
2061 
2062  case PCB_PAD_T:
2063  // Multiple selection is only allowed in footprint editor mode. In pcbnew, you have to
2064  // select footprint subparts one by one, rather than with a drag selection. This is so
2065  // you can pick up items under an (unlocked) footprint without also moving the
2066  // footprint's sub-parts.
2067  if( !m_isFootprintEditor && !checkVisibilityOnly )
2068  {
2069  if( m_multiple )
2070  return false;
2071  }
2072 
2073  pad = static_cast<const PAD*>( aItem );
2074 
2075  if( pad->GetAttribute() == PAD_ATTRIB_PTH || pad->GetAttribute() == PAD_ATTRIB_NPTH )
2076  {
2077  // Check render mode (from the Items tab) first
2078  if( !board()->IsElementVisible( LAYER_PADS_TH ) )
2079  return false;
2080 
2081  // A pad's hole is visible on every layer the pad is visible on plus many layers the
2082  // pad is not visible on -- so we only need to check for any visible hole layers.
2083  if( !( board()->GetVisibleLayers() & LSET::PhysicalLayersMask() ).any() )
2084  return false;
2085  }
2086  else
2087  {
2088  // Check render mode (from the Items tab) first
2089  if( pad->IsOnLayer( F_Cu ) && !board()->IsElementVisible( LAYER_PAD_FR ) )
2090  return false;
2091  else if( pad->IsOnLayer( B_Cu ) && !board()->IsElementVisible( LAYER_PAD_BK ) )
2092  return false;
2093 
2094  if( !( pad->GetLayerSet() & board()->GetVisibleLayers() ).any() )
2095  return false;
2096  }
2097 
2098  break;
2099 
2100  // These are not selectable
2101  case PCB_NETINFO_T:
2102  case NOT_USED:
2103  case TYPE_NOT_INIT:
2104  return false;
2105 
2106  default: // Suppress warnings
2107  break;
2108  }
2109 
2110  return aItem->ViewGetLOD( aItem->GetLayer(), view() ) < view()->GetScale();
2111 }
2112 
2113 
2115 {
2116  if( aItem->IsSelected() )
2117  return;
2118 
2119  if( aItem->Type() == PCB_PAD_T )
2120  {
2121  FOOTPRINT* footprint = static_cast<FOOTPRINT*>( aItem->GetParent() );
2122 
2123  if( m_selection.Contains( footprint ) )
2124  return;
2125  }
2126 
2127  highlight( aItem, SELECTED, &m_selection );
2128 }
2129 
2130 
2132 {
2133  unhighlight( aItem, SELECTED, &m_selection );
2134 }
2135 
2136 
2137 void PCB_SELECTION_TOOL::highlight( BOARD_ITEM* aItem, int aMode, PCB_SELECTION* aGroup )
2138 {
2139  if( aGroup )
2140  aGroup->Add( aItem );
2141 
2142  highlightInternal( aItem, aMode, aGroup != nullptr );
2143  view()->Update( aItem, KIGFX::REPAINT );
2144 
2145  // Many selections are very temporal and updating the display each time just
2146  // creates noise.
2147  if( aMode == BRIGHTENED )
2149 }
2150 
2151 
2152 void PCB_SELECTION_TOOL::highlightInternal( BOARD_ITEM* aItem, int aMode, bool aUsingOverlay )
2153 {
2154  if( aMode == SELECTED )
2155  aItem->SetSelected();
2156  else if( aMode == BRIGHTENED )
2157  aItem->SetBrightened();
2158 
2159  if( aUsingOverlay )
2160  view()->Hide( aItem, true ); // Hide the original item, so it is shown only on overlay
2161 
2162  if( aItem->Type() == PCB_FOOTPRINT_T )
2163  {
2164  static_cast<FOOTPRINT*>( aItem )->RunOnChildren(
2165  [&]( BOARD_ITEM* aChild )
2166  {
2167  highlightInternal( aChild, aMode, aUsingOverlay );
2168  } );
2169  }
2170  else if( aItem->Type() == PCB_GROUP_T )
2171  {
2172  static_cast<PCB_GROUP*>( aItem )->RunOnChildren(
2173  [&]( BOARD_ITEM* aChild )
2174  {
2175  highlightInternal( aChild, aMode, aUsingOverlay );
2176  } );
2177  }
2178 }
2179 
2180 
2182 {
2183  if( aGroup )
2184  aGroup->Remove( aItem );
2185 
2186  unhighlightInternal( aItem, aMode, aGroup != nullptr );
2187  view()->Update( aItem, KIGFX::REPAINT );
2188 
2189  // Many selections are very temporal and updating the display each time just
2190  // creates noise.
2191  if( aMode == BRIGHTENED )
2193 }
2194 
2195 
2196 void PCB_SELECTION_TOOL::unhighlightInternal( BOARD_ITEM* aItem, int aMode, bool aUsingOverlay )
2197 {
2198  if( aMode == SELECTED )
2199  aItem->ClearSelected();
2200  else if( aMode == BRIGHTENED )
2201  aItem->ClearBrightened();
2202 
2203  if( aUsingOverlay )
2204  view()->Hide( aItem, false ); // // Restore original item visibility
2205 
2206  if( aItem->Type() == PCB_FOOTPRINT_T )
2207  {
2208  static_cast<FOOTPRINT*>( aItem )->RunOnChildren(
2209  [&]( BOARD_ITEM* aChild )
2210  {
2211  unhighlightInternal( aChild, aMode, aUsingOverlay );
2212  } );
2213  }
2214  else if( aItem->Type() == PCB_GROUP_T )
2215  {
2216  static_cast<PCB_GROUP*>( aItem )->RunOnChildren(
2217  [&]( BOARD_ITEM* aChild )
2218  {
2219  unhighlightInternal( aChild, aMode, aUsingOverlay );
2220  } );
2221  }
2222 }
2223 
2224 
2226 {
2228  GENERAL_COLLECTOR collector;
2229 
2230  // Since we're just double-checking, we want a considerably sloppier check than the initial
2231  // selection (for which most tools use 5 pixels). So we increase this to an effective 20
2232  // pixels by artificially inflating the value of a pixel by 4X.
2233  guide.SetOnePixelInIU( guide.OnePixelInIU() * 4 );
2234 
2237  (wxPoint) aPoint, guide );
2238 
2239  for( int i = collector.GetCount() - 1; i >= 0; --i )
2240  {
2241  BOARD_ITEM* item = collector[i];
2242 
2243  if( item->IsSelected() && item->HitTest( (wxPoint) aPoint, 5 * guide.OnePixelInIU() ) )
2244  return true;
2245  }
2246 
2247  return false;
2248 }
2249 
2250 
2251 int PCB_SELECTION_TOOL::hitTestDistance( const wxPoint& aWhere, BOARD_ITEM* aItem,
2252  int aMaxDistance ) const
2253 {
2254  BOX2D viewportD = getView()->GetViewport();
2255  BOX2I viewport( VECTOR2I( viewportD.GetPosition() ), VECTOR2I( viewportD.GetSize() ) );
2256  int distance = INT_MAX;
2257  SEG loc( aWhere, aWhere );
2258 
2259  switch( aItem->Type() )
2260  {
2261  case PCB_TEXT_T:
2262  {
2263  PCB_TEXT* text = static_cast<PCB_TEXT*>( aItem );
2264  text->GetEffectiveTextShape()->Collide( loc, aMaxDistance, &distance );
2265  }
2266  break;
2267 
2268  case PCB_FP_TEXT_T:
2269  {
2270  FP_TEXT* text = static_cast<FP_TEXT*>( aItem );
2271  text->GetEffectiveTextShape()->Collide( loc, aMaxDistance, &distance );
2272  }
2273  break;
2274 
2275  case PCB_ZONE_T:
2276  {
2277  ZONE* zone = static_cast<ZONE*>( aItem );
2278 
2279  // Zone borders are very specific
2280  if( zone->HitTestForEdge( aWhere, aMaxDistance / 2 ) )
2281  distance = 0;
2282  else if( zone->HitTestForEdge( aWhere, aMaxDistance ) )
2283  distance = aMaxDistance / 2;
2284  else
2285  aItem->GetEffectiveShape()->Collide( loc, aMaxDistance, &distance );
2286  }
2287  break;
2288 
2289  case PCB_FOOTPRINT_T:
2290  {
2291  FOOTPRINT* footprint = static_cast<FOOTPRINT*>( aItem );
2292  EDA_RECT bbox = footprint->GetBoundingBox( false, false );
2293 
2294  footprint->GetBoundingHull().Collide( loc, aMaxDistance, &distance );
2295 
2296  // Consider footprints larger than the viewport only as a last resort
2297  if( bbox.GetHeight() > viewport.GetHeight() || bbox.GetWidth() > viewport.GetWidth() )
2298  distance = INT_MAX / 2;
2299  }
2300  break;
2301 
2302  case PCB_MARKER_T:
2303  {
2304  PCB_MARKER* marker = static_cast<PCB_MARKER*>( aItem );
2305  SHAPE_LINE_CHAIN polygon;
2306 
2307  marker->ShapeToPolygon( polygon );
2308  polygon.Move( marker->GetPos() );
2309  polygon.Collide( loc, aMaxDistance, &distance );
2310  }
2311  break;
2312 
2313  case PCB_GROUP_T:
2314  {
2315  PCB_GROUP* group = static_cast<PCB_GROUP*>( aItem );
2316 
2317  for( BOARD_ITEM* member : group->GetItems() )
2318  distance = std::min( distance, hitTestDistance( aWhere, member, aMaxDistance ) );
2319  }
2320  break;
2321 
2322  default:
2323  aItem->GetEffectiveShape()->Collide( loc, aMaxDistance, &distance );
2324  break;
2325  }
2326 
2327  return distance;
2328 }
2329 
2330 
2331 // The general idea here is that if the user clicks directly on a small item inside a larger
2332 // one, then they want the small item. The quintessential case of this is clicking on a pad
2333 // within a footprint, but we also apply it for text within a footprint, footprints within
2334 // larger footprints, and vias within either larger pads or longer tracks.
2335 //
2336 // These "guesses" presume there is area within the larger item to click in to select it. If
2337 // an item is mostly covered by smaller items within it, then the guesses are inappropriate as
2338 // there might not be any area left to click to select the larger item. In this case we must
2339 // leave the items in the collector and bring up a Selection Clarification menu.
2340 //
2341 // We currently check for pads and text mostly covering a footprint, but we don't check for
2342 // smaller footprints mostly covering a larger footprint.
2343 //
2345  const VECTOR2I& aWhere ) const
2346 {
2347  std::set<BOARD_ITEM*> preferred;
2348  std::set<BOARD_ITEM*> rejected;
2349  wxPoint where( aWhere.x, aWhere.y );
2350 
2351  PCB_LAYER_ID activeLayer = (PCB_LAYER_ID) view()->GetTopLayer();
2352  LSET silkLayers( 2, B_SilkS, F_SilkS );
2353 
2354  if( silkLayers[activeLayer] )
2355  {
2356  for( int i = 0; i < aCollector.GetCount(); ++i )
2357  {
2358  BOARD_ITEM* item = aCollector[i];
2359  KICAD_T type = item->Type();
2360 
2361  if( ( type == PCB_FP_TEXT_T || type == PCB_TEXT_T || type == PCB_SHAPE_T )
2362  && silkLayers[item->GetLayer()] )
2363  {
2364  preferred.insert( item );
2365  }
2366  }
2367 
2368  if( preferred.size() > 0 )
2369  {
2370  aCollector.Empty();
2371 
2372  for( BOARD_ITEM* item : preferred )
2373  aCollector.Append( item );
2374 
2375  return;
2376  }
2377  }
2378 
2379  // Prefer exact hits to sloppy ones
2380 
2381  constexpr int MAX_SLOP = 5;
2382 
2383  int pixel = (int) aCollector.GetGuide()->OnePixelInIU();
2384  int minSlop = INT_MAX;
2385 
2386  std::map<BOARD_ITEM*, int> itemsBySloppiness;
2387 
2388  for( int i = 0; i < aCollector.GetCount(); ++i )
2389  {
2390  BOARD_ITEM* item = aCollector[i];
2391  int itemSlop = hitTestDistance( where, item, MAX_SLOP * pixel );
2392 
2393  itemsBySloppiness[ item ] = itemSlop;
2394 
2395  if( itemSlop < minSlop )
2396  minSlop = itemSlop;
2397  }
2398 
2399  // Prune sloppier items
2400 
2401  if( minSlop < INT_MAX )
2402  {
2403  for( std::pair<BOARD_ITEM*, int> pair : itemsBySloppiness )
2404  {
2405  if( pair.second > minSlop + pixel )
2406  aCollector.Transfer( pair.first );
2407  }
2408  }
2409 
2410  // If the user clicked on a small item within a much larger one then it's pretty clear
2411  // they're trying to select the smaller one.
2412 
2413  constexpr double sizeRatio = 1.3;
2414 
2415  std::vector<std::pair<BOARD_ITEM*, double>> itemsByArea;
2416 
2417  for( int i = 0; i < aCollector.GetCount(); ++i )
2418  {
2419  BOARD_ITEM* item = aCollector[i];
2420  double area;
2421 
2422  if( item->Type() == PCB_ZONE_T
2423  && static_cast<ZONE*>( item )->HitTestForEdge( where, MAX_SLOP * pixel / 2 ) )
2424  {
2425  // Zone borders are very specific, so make them "small"
2426  area = MAX_SLOP * SEG::Square( pixel );
2427  }
2428  else if( item->Type() == PCB_VIA_T )
2429  {
2430  // Vias rarely hide other things, and we don't want them deferring to short track
2431  // segments -- so make them artificially small by dropping the π from πr².
2432  area = SEG::Square( static_cast<VIA*>( item )->GetDrill() / 2 );
2433  }
2434  else
2435  {
2436  try
2437  {
2438  area = FOOTPRINT::GetCoverageArea( item, aCollector );
2439  }
2440  catch( const ClipperLib::clipperException& e )
2441  {
2442  wxLogError( "A clipper exception %s was detected.", e.what() );
2443  }
2444  }
2445 
2446  itemsByArea.emplace_back( item, area );
2447  }
2448 
2449  std::sort( itemsByArea.begin(), itemsByArea.end(),
2450  []( const std::pair<BOARD_ITEM*, double>& lhs,
2451  const std::pair<BOARD_ITEM*, double>& rhs ) -> bool
2452  {
2453  return lhs.second < rhs.second;
2454  } );
2455 
2456  bool rejecting = false;
2457 
2458  for( int i = 1; i < (int) itemsByArea.size(); ++i )
2459  {
2460  if( itemsByArea[i].second > itemsByArea[i-1].second * sizeRatio )
2461  rejecting = true;
2462 
2463  if( rejecting )
2464  rejected.insert( itemsByArea[i].first );
2465  }
2466 
2467  // Special case: if a footprint is completely covered with other features then there's no
2468  // way to select it -- so we need to leave it in the list for user disambiguation.
2469 
2470  constexpr double maxCoverRatio = 0.70;
2471 
2472  for( int i = 0; i < aCollector.GetCount(); ++i )
2473  {
2474  if( FOOTPRINT* footprint = dynamic_cast<FOOTPRINT*>( aCollector[i] ) )
2475  {
2476  if( footprint->CoverageRatio( aCollector ) > maxCoverRatio )
2477  rejected.erase( footprint );
2478  }
2479  }
2480 
2481  // Hopefully we've now got what the user wanted.
2482 
2483  if( (unsigned) aCollector.GetCount() > rejected.size() ) // do not remove everything
2484  {
2485  for( BOARD_ITEM* item : rejected )
2486  aCollector.Transfer( item );
2487  }
2488 }
2489 
2490 
2492 {
2493  std::unordered_set<BOARD_ITEM*> toAdd;
2494 
2495  // If any element is a member of a group, replace those elements with the top containing group.
2496  for( int j = 0; j < aCollector.GetCount(); )
2497  {
2498  BOARD_ITEM* item = aCollector[j];
2499  BOARD_ITEM* parent = item->GetParent();
2500 
2501  // Ignore footprint groups in board editor
2502  if( !m_isFootprintEditor && parent && parent->Type() == PCB_FOOTPRINT_T )
2503  {
2504  ++j;
2505  continue;
2506  }
2507 
2509 
2510  if( aTop )
2511  {
2512  if( aTop != item )
2513  {
2514  toAdd.insert( aTop );
2515  aCollector.Remove( item );
2516  continue;
2517  }
2518  }
2519  else if( m_enteredGroup && !PCB_GROUP::WithinScope( item, m_enteredGroup ) )
2520  {
2521  // If a group is entered, disallow selections of objects outside the group.
2522  aCollector.Remove( item );
2523  continue;
2524  }
2525 
2526  ++j;
2527  }
2528 
2529  for( BOARD_ITEM* item : toAdd )
2530  {
2531  if( !aCollector.HasItem( item ) )
2532  aCollector.Append( item );
2533  }
2534 }
2535 
2536 
2538 {
2539  getView()->Update( &m_selection );
2541 
2542  return 0;
2543 }
2544 
2545 
2547 {
2548  ACTION_MENU* actionMenu = aEvent.Parameter<ACTION_MENU*>();
2549  CONDITIONAL_MENU* conditionalMenu = dynamic_cast<CONDITIONAL_MENU*>( actionMenu );
2550 
2551  if( conditionalMenu )
2552  conditionalMenu->Evaluate( m_selection );
2553 
2554  if( actionMenu )
2555  actionMenu->UpdateAll();
2556 
2557  return 0;
2558 }
2559 
2560 
2562 {
2564 
2568 
2574 
2575  Go( &PCB_SELECTION_TOOL::find, ACTIONS::find.MakeEvent() );
2576 
2585 
2587 }
static TOOL_ACTION selectItems
Select a list of items (specified as the event parameter)
Definition: pcb_actions.h:70
void Empty()
Clear the list.
Definition: collector.h:95
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: pcb_actions.h:63
const GENERAL_COLLECTORS_GUIDE getCollectorsGuide() const
static TOOL_ACTION selectionActivate
Activation of the selection tool.
Definition: pcb_actions.h:57
void Hide(VIEW_ITEM *aItem, bool aHide=true)
Temporarily hide the item in the view (e.g.
Definition: view.cpp:1475
void ClearReferencePoint()
Definition: selection.h:269
int selectSameSheet(const TOOL_EVENT &aEvent)
Find dialog callback.
static double GetCoverageArea(const BOARD_ITEM *aItem, const GENERAL_COLLECTOR &aCollector)
Return the initial comments block or NULL if none, without transfer of ownership.
Definition: footprint.cpp:1733
const std::set< unsigned int > GetHighContrastLayers() const
Returns the set of currently high-contrast layers.
const wxPoint & GetPos() const
Definition: marker_base.h:84
bool IsLocked() const override
Definition: footprint.h:279
Filled polygons are shown.
void AddStandardSubMenus(TOOL_MENU &aMenu)
Construct a "basic" menu for a tool, containing only items that apply to all tools (e....
void SetIgnoreTracks(bool ignore)
Definition: collectors.h:603
bool AddItem(BOARD_ITEM *aItem)
Add 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:343
int CursorSelection(const TOOL_EVENT &aEvent)
Clear current selection event handler.
static const TOOL_EVENT SelectedEvent
Definition: actions.h:209
BOX2D GetViewport() const
Return the current viewport visible area rectangle.
Definition: view.cpp:513
void SetEnd(VECTOR2I aEnd)
Set the current end of the rectangle (the corner that moves with the cursor.
TOOL_MENU m_menu
The functions below are not yet implemented - their interface may change.
static TOOL_ACTION move
move or drag an item
Definition: pcb_actions.h:96
SHAPE_POLY_SET GetBoundingHull() const
Return a bounding polygon for the shapes and pads in the footprint.
Definition: footprint.cpp:738
void SetOnePixelInIU(double aValue)
Definition: collectors.h:609
class ALIGNED_DIMENSION, a linear dimension (graphic item)
Definition: typeinfo.h:100
virtual void Clear() override
Remove all the stored items from the group.
Definition: selection.h:96
void ForceRefresh()
Force a redraw.
class LEADER, a leader dimension (graphic item)
Definition: typeinfo.h:101
void select(BOARD_ITEM *aItem)
Take necessary action mark an item as selected.
bool otherItems
Anything not fitting one of the above categories.
static TOOL_ACTION groupLeave
Definition: pcb_actions.h:427
class FP_TEXT, text in a footprint
Definition: typeinfo.h:92
static const KICAD_T AllBoardItems[]
A scan list for all editable board items.
Definition: collectors.h:268
void SetIgnoreBlindBuriedVias(bool ignore)
Definition: collectors.h:597
TOOL_EVENT * Wait(const TOOL_EVENT_LIST &aEventList=TOOL_EVENT(TC_ANY, TA_ANY))
Suspend execution of the tool until an event specified in aEventList arrives.
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: track.cpp:376
BOARD * board() const
Container for all the knowledge about how graphical objects are drawn on any output surface/device.
bool IsSelected() const
Definition: eda_item.h:172
const KIID_PATH & GetPath() const
Definition: footprint.h:199
static bool WithinScope(BOARD_ITEM *item, PCB_GROUP *scope)
Definition: pcb_group.cpp:93
Model changes (required full reload)
Definition: tool_base.h:81
multilayer pads, usually with holes
static const TOOL_EVENT UnselectedEvent
Definition: actions.h:210
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
Definition: zone.h:755
Defines the structure of a menu based on ACTIONs.
Definition: action_menu.h:45
int find(const TOOL_EVENT &aEvent)
Invoke filter dialog and modify current selection.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:82
VECTOR2D ToWorld(const VECTOR2D &aCoord, bool aAbsolute=true) const
Converts a screen space point/vector to a point/vector in world space coordinates.
Definition: view.cpp:450
class PCB_GROUP, a set of BOARD_ITEMs
Definition: typeinfo.h:108
void SetOrigin(VECTOR2I aOrigin)
void ClearSelected()
Definition: eda_item.h:181
const wxPoint & GetStart() const
Definition: track.h:116
int SelectionMenu(const TOOL_EVENT &aEvent)
Show a popup menu to trim the COLLECTOR passed as aEvent's parameter down to a single item.
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:567
virtual double OnePixelInIU() const =0
void SetIgnoreModulesVals(bool ignore)
Definition: collectors.h:585
void SetIgnoreMicroVias(bool ignore)
Definition: collectors.h:600
Control for copper zone opacity/visibility (color ignored)
Stop at any place where more than two traces meet.
class CENTER_DIMENSION, a center point marking (graphic item)
Definition: typeinfo.h:102
void SetIgnoreModulesOnBack(bool ignore)
Definition: collectors.h:555
static TOOL_ACTION unselectItem
Definition: pcb_actions.h:67
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
CONDITIONAL_MENU & GetMenu()
Definition: tool_menu.cpp:46
the 3d code uses this value
Definition: typeinfo.h:79
static TOOL_ACTION selectNet
Select all connections belonging to a single net.
Definition: pcb_actions.h:81
static TOOL_ACTION dragFreeAngle
Definition: pcb_actions.h:142
void highlightInternal(BOARD_ITEM *aItem, int aHighlightMode, bool aUsingOverlay)
void Move(const VECTOR2I &aVector) override
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:215
static TOOL_ACTION unselectItems
Definition: pcb_actions.h:71
static TOOL_ACTION cancelInteractive
Definition: actions.h:65
DIALOG_FILTER_SELECTION::OPTIONS m_filterOpts
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition: view.cpp:351
static TOOL_ACTION properties
Activation of the edit tool.
Definition: pcb_actions.h:121
Stop when reaching a pad.
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: zone.cpp:288
int GetWidth() const
Definition: eda_rect.h:114
show footprints on back
void SetBrightened()
Definition: eda_item.h:179
static TOOL_ACTION zoomFitScreen
Definition: actions.h:99
class PCB_TEXT, text on a layer
Definition: typeinfo.h:91
void SetIgnoreModulesRefs(bool ignore)
Definition: collectors.h:591
LSET GetVisibleLayers() const
A proxy function that calls the correspondent function in m_BoardSettings Returns a bit-mask of all t...
Definition: board.cpp:461
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Run the specified action.
Definition: tool_manager.h:141
double CoverageRatio(const GENERAL_COLLECTOR &aCollector) const
Calculate the ratio of total area of the footprint pads and graphical items to the area of the footpr...
Definition: footprint.cpp:1781
static TOOL_ACTION selectionMenu
Run a selection menu to select from a list of items.
Definition: pcb_actions.h:74
static TOOL_ACTION selectConnection
Select tracks between junctions or expands an existing selection to pads or the entire connection.
Definition: pcb_actions.h:78
class ARC, an arc track segment on a copper layer
Definition: typeinfo.h:97
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
Test to see if this object is on the given layer.
Definition: pad.h:559
void SetExclusiveOr(bool aExclusiveOr)
show footprints values (when texts are visibles)
bool selectPoint(const VECTOR2I &aWhere, bool aOnDrag=false, bool *aSelectionCancelledFlag=NULL, CLIENT_SELECTION_FILTER aClientFilter=NULL)
Select an item pointed by the parameter aWhere.
Definition: bitmap.cpp:58
static TOOL_ACTION drag45Degree
Definition: pcb_actions.h:141
void highlight(BOARD_ITEM *aItem, int aHighlightMode, PCB_SELECTION *aGroup=nullptr)
Highlight the item visually.
class FP_SHAPE, a footprint edge
Definition: typeinfo.h:93
class PAD, a pad in a footprint
Definition: typeinfo.h:89
double OnePixelInIU() const override
Definition: collectors.h:608
virtual void Clear()
Remove all the stored items from the group.
Definition: view_group.cpp:75
Private implementation of firewalled private data.
void UpdateAll()
Run update handlers for the menu and its submenus.
void setTransitions() override
Zoom the screen to center and fit the current selection.
int UnselectItem(const TOOL_EVENT &aEvent)
void(* CLIENT_SELECTION_FILTER)(const VECTOR2I &, GENERAL_COLLECTOR &, PCB_SELECTION_TOOL *)
static TOOL_ACTION zoomFitObjects
Definition: actions.h:100
void Reset(RESET_REASON aReason) override
Bring the tool to a known, initial state.
Struct that will be set with the result of the user choices in the dialog.
const EDA_RECT GetBoundingBox() const override
May be re-implemented for each derived class in order to handle all the types given by its member dat...
Definition: pcb_group.cpp:193
virtual wxPoint GetPosition() const
Definition: eda_item.h:301
void selectConnectedTracks(BOARD_CONNECTED_ITEM &aSourceItem, STOP_CONDITION aStopCondition)
Select connected tracks and vias.
bool doSelectionMenu(GENERAL_COLLECTOR *aItems)
Allow the selection of a single item from a list via pop-up menu.
like PAD_PTH, but not plated mechanical use only, no connection allowed
Definition: pad_shapes.h:85
void SetContextMenu(ACTION_MENU *aMenu, CONTEXT_MENU_TRIGGER aTrigger=CMENU_BUTTON)
Assign a context menu and tells when it should be activated.
static TOOL_ACTION find
Definition: actions.h:79
VECTOR2< int > VECTOR2I
Definition: vector2d.h:623
static SEG::ecoord Square(int a)
Definition: seg.h:123
const PCB_DISPLAY_OPTIONS & GetDisplayOptions() const
Display options control the way tracks, vias, outlines and other things are shown (for instance solid...
std::unordered_set< BOARD_ITEM * > & GetItems()
Definition: pcb_group.h:68
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
int UnselectItems(const TOOL_EVENT &aEvent)
static bool NotEmpty(const SELECTION &aSelection)
Test 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))
Define which state (aStateFunc) to go when a certain event arrives (aConditions).
bool Contains(const wxPoint &aPoint) const
Definition: eda_rect.cpp:57
void Remove(int aIndex)
Remove the item at aIndex (first position is 0).
Definition: collector.h:115
void SetCurrentCursor(KICURSOR cursor)
Set the current cursor shape for this panel.
virtual void Remove(VIEW_ITEM *aItem) override
Remove a VIEW_ITEM from the view.
Definition: pcb_view.cpp:75
search types array terminator (End Of Types)
Definition: typeinfo.h:81
TRACK_DRAG_ACTION
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition: typeinfo.h:77
static const TOOL_EVENT SelectedItemsModified
Selected items were moved, this can be very high frequency on the canvas, use with care.
Definition: actions.h:214
bool HitTestForCorner(const wxPoint &refPos, int aAccuracy, SHAPE_POLY_SET::VERTEX_INDEX &aCornerHit) const
Function HitTestForCorner tests if the given wxPoint is near a corner.
Definition: zone.cpp:422
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition: view.h:207
static bool itemIsIncludedByFilter(const BOARD_ITEM &aItem, const BOARD &aBoard, const DIALOG_FILTER_SELECTION::OPTIONS &aFilterOptions)
Function itemIsIncludedByFilter()
class TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:95
PADS & Pads()
Definition: footprint.h:164
void SetIsHover(bool aIsHover)
Definition: selection.h:67
virtual bool Collide(const VECTOR2I &aP, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const override
Check if point aP lies closer to us than aClearance.
virtual void Add(EDA_ITEM *aItem)
Definition: selection.h:77
bool IsAction(const TOOL_ACTION *aAction) const
Test if the event contains an action issued upon activation of the given TOOL_ACTION.
Definition: tool_event.cpp:70
PCB_BASE_FRAME * m_frame
PAD_ATTR_T GetAttribute() const
Definition: pad.h:363
void ClearBrightened()
Definition: eda_item.h:182
void Append(EDA_ITEM *item)
Add an item to the end of the list.
Definition: collector.h:105
void RebuildSelection()
Rebuild the selection from the EDA_ITEMs' selection flags.
void SetAdditive(bool aAdditive)
show footprints on front
PCB_BASE_EDIT_FRAME * frame() const
virtual bool HitTest(const wxPoint &aPosition, int aAccuracy=0) const
Test if aPosition is contained within or on the bounding box of an item.
Definition: eda_item.h:274
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:1124
int GetCount() const
Return the number of objects in the list.
Definition: collector.h:87
bool Init() override
Init() is called once upon a registration of the tool.
PCB_SELECTION & GetSelection()
Return the set of currently selected items.
FP_ZONES & Zones()
Definition: footprint.h:170
void UnbrightenItem(BOARD_ITEM *aItem)
void SetState(int type, bool state)
Definition: eda_item.h:191
int updateSelection(const TOOL_EVENT &aEvent)
Event handler to update the selection VIEW_ITEM.
void Transfer(int aIndex)
Move the item at aIndex (first position is 0) to the backup list.
Definition: collector.h:159
MOUSE_DRAG_ACTION
Container for 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:130
virtual void Update(const VIEW_ITEM *aItem, int aUpdateFlags) const override
For dynamic VIEWs, inform the associated VIEW that the graphical representation of this item has chan...
Definition: pcb_view.cpp:92
const COLLECTORS_GUIDE * GetGuide() const
Definition: collectors.h:343
Item needs to be redrawn.
Definition: view_item.h:57
LSET is a set of PCB_LAYER_IDs.
MOUSE_DRAG_ACTION GetDragAction() const
Indicates whether a drag should draw a selection rectangle or drag selected (or unselected) objects.
Definition: tools_holder.h:134
void SetCenter(const VECTOR2D &aCenter)
Set the center point of the VIEW (i.e.
Definition: view.cpp:579
bool selectMultiple()
Handle drawing a selection box that allows one to select many items at the same time.
bool text
Text (free or attached to a footprint)
const PCB_SELECTION & selection() const
void SetFlags(STATUS_FLAGS aMask)
Definition: eda_item.h:202
#define NULL
void SetSelected()
Definition: eda_item.h:178
int selectNet(const TOOL_EVENT &aEvent)
Select all copper connections belonging to the same net(s) as the items in the selection.
void SetIgnoreMTextsOnBack(bool ignore)
Definition: collectors.h:543
std::function< SEARCH_RESULT(EDA_ITEM *aItem, void *aTestData) > INSPECTOR_FUNC
Used to inspect and possibly collect the (search) results of iterating over a list or tree of KICAD_T...
Definition: eda_item.h:69
TRACK_DRAG_ACTION m_TrackDragAction
KIGFX::VIEW_GROUP m_enteredGroupOverlay
bool dimensions
Dimension items.
void SetIgnorePadsOnFront(bool ignore)
Definition: collectors.h:573
SELECTION_FILTER_OPTIONS m_filter
int expandConnection(const TOOL_EVENT &aEvent)
Expand the current track selection to the next boundary (junctions, pads, or all)
void MarkTargetDirty(int aTarget)
Set or clear target 'dirty' flag.
Definition: view.h:574
virtual EDA_RECT GetBoundingBox() const
Definition: selection.h:180
bool ProcessEvent(const TOOL_EVENT &aEvent)
Propagate an event to tools that requested events of matching type(s).
static PCB_GROUP * TopLevelGroup(BOARD_ITEM *aItem, PCB_GROUP *aScope, bool aFootprintEditor)
Definition: pcb_group.cpp:72
bool IsVisible(const VIEW_ITEM *aItem) const
Return information if the item is visible (or not).
Definition: view.cpp:1494
bool graphics
Graphic lines, shapes, polygons.
void SetIgnoreMTextsOnFront(bool ignore)
Definition: collectors.h:549
void AddItemToSel(BOARD_ITEM *aItem, bool aQuietMode=false)
Select all items on the board.
T Parameter() const
Return a non-standard parameter assigned to the event.
Definition: tool_event.h:443
#define ENTERED
indicates a group has been entered
Definition: eda_item.h:137
virtual int GetTopLayer() const
Definition: view.cpp:823
coord_type GetWidth() const
Definition: box2.h:197
Meta control for all pads opacity/visibility (color ignored)
#define SELECTED
Definition: eda_item.h:113
Generic, UI-independent tool event.
Definition: tool_event.h:173
void connectedItemFilter(const VECTOR2I &, GENERAL_COLLECTOR &aCollector, PCB_SELECTION_TOOL *sTool)
void SetMaximum()
Definition: box2.h:73
bool Contains(EDA_ITEM *aItem) const
Definition: selection.h:114
void findCallback(BOARD_ITEM *aItem)
Find an item.
FOOTPRINT * footprint() const
const BOX2I ViewBBox() const override
Set the origin of the rectangle (the fixed corner)
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Return a list of missing connections between components/tracks.
Definition: board.h:414
const std::deque< EDA_ITEM * > GetItems() const
Definition: selection.h:133
KIGFX::PCB_VIEW * view() const
bool ToolStackIsEmpty()
Definition: tools_holder.h:117
bool HasItem(const EDA_ITEM *aItem) const
Tests if aItem has already been collected.
Definition: collector.h:203
static const TOOL_EVENT UninhibitSelectionEditing
Definition: actions.h:221
bool Selectable(const BOARD_ITEM *aItem, bool checkVisibilityOnly=false) const
Check conditions for an item to be selected.
EDA_ITEM * GetParent() const
Definition: eda_item.h:164
Items that may change while the view stays the same (noncached)
Definition: definitions.h:50
static const TOOL_EVENT ClearedEvent
Selected item had a property changed (except movement)
Definition: actions.h:211
DRAWINGS & GraphicalItems()
Definition: footprint.h:167
void BrightenItem(BOARD_ITEM *aItem)
ZONE handles a list of polygons defining a copper zone.
Definition: zone.h:57
LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: pad.h:360
class ZONE, a copper pour area
Definition: typeinfo.h:105
static const TOOL_EVENT SelectedItemsMoved
Used to inform tools that the selection should temporarily be non-editable.
Definition: actions.h:217
void RunOnDescendants(const std::function< void(BOARD_ITEM *)> &aFunction) const
Invoke a function on all descendants of the group.
Definition: pcb_group.cpp:324
PCB_SELECTION m_selection
static float distance(const SFVEC2UI &a, const SFVEC2UI &b)
static TOOL_ACTION updateMenu
Definition: actions.h:170
virtual void Add(VIEW_ITEM *aItem)
Add an item to the group.
Definition: view_group.cpp:56
void SetIgnoreMTextsMarkedNoShow(bool ignore)
Definition: collectors.h:537
virtual KIGFX::VIEW_ITEM * GetItem(unsigned int aIdx) const override
Definition: selection.h:106
void ExitGroup(bool aSelectGroup=false)
Leave the currently entered group.
#define IS_MOVED
Item being moved.
Definition: eda_item.h:105
void unselect(BOARD_ITEM *aItem)
Take necessary action mark an item as unselected.
const BITMAP_OPAQUE info_xpm[1]
Definition: info.cpp:36
bool m_isFootprintEditor
virtual void SetLayer(int aLayer)
Set layer used to draw the group.
Definition: view_group.h:108
static TOOL_ACTION hideDynamicRatsnest
Definition: pcb_actions.h:456
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:115
KIGFX::VIEW * getView() const
Returns the instance of #VIEW object used in the application.
Definition: tool_base.cpp:36
virtual void SetAutoPan(bool aEnabled)
Turn on/off auto panning (this feature is used when there is a tool active (eg.
bool Empty() const
Checks if there is anything selected.
Definition: selection.h:122
class PCB_TARGET, a target (graphic item)
Definition: typeinfo.h:104
wxString m_MenuTitle
Definition: collector.h:250
class FOOTPRINT, a footprint
Definition: typeinfo.h:88
bool IsMirroredX() const
Return true if view is flipped across the X axis.
Definition: view.h:237
static TOOL_ACTION clearHighlight
Definition: pcb_actions.h:445
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:507
virtual unsigned int GetSize() const override
Return the number of stored items.
Definition: selection.h:101
virtual void SetScale(double aScale, VECTOR2D aAnchor={ 0, 0 })
Set the scaling factor, zooming around a given anchor point.
Definition: view.cpp:553
int selectSheetContents(const TOOL_EVENT &aEvent)
Select all footprints belonging to same hierarchical sheet as the selected footprint (same sheet path...
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
void ShapeToPolygon(SHAPE_LINE_CHAIN &aPolygon, int aScale=-1) const
Return the shape polygon in internal units in a SHAPE_LINE_CHAIN the coordinates are relatives to the...
Definition: seg.h:41
static TOOL_ACTION filterSelection
Filter the items in the current selection (invokes dialog)
Definition: pcb_actions.h:93
void Normalize()
Ensures that the height ant width are positive.
Definition: eda_rect.cpp:35
bool Collide(const SHAPE *aShape, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const override
Check if the boundary of shape (this) lies closer to the shape aShape than aClearance,...
std::unique_ptr< PRIV > m_priv
void SetCallback(boost::function< void(BOARD_ITEM *)> aCallback)
Function to be called on each found event.
Definition: dialog_find.h:62
bool GetHighContrast() const
static LSET PhysicalLayersMask()
Return a mask holding all layers which are physically realized.
Definition: lset.cpp:849
int Main(const TOOL_EVENT &aEvent)
The main loop.
virtual RENDER_SETTINGS * GetSettings()=0
Return a pointer to current settings that are going to be used when drawing items.
int SelectItems(const TOOL_EVENT &aEvent)
Item unselection event handler.
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:453
virtual bool IsLocked() const
Definition: board_item.h:249
int SelectItem(const TOOL_EVENT &aEvent)
bool lockedItems
Allow selecting locked items.
bool selectCursor(bool aForceSelect=false, CLIENT_SELECTION_FILTER aClientFilter=NULL)
Select an item under the cursor unless there is something already selected or aSelectAlways is true.
class MARKER_PCB, a marker used to show something
Definition: typeinfo.h:98
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
PCB_SELECTION & RequestSelection(CLIENT_SELECTION_FILTER aClientFilter, bool aConfirmLockedItems=false)
Return the current selection set, filtered according to aFlags and aClientFilter.
bool HasAdditionalItems()
Test if the collector has heuristic backup items.
Definition: collector.h:140
Meta control for all vias opacity/visibility.
static TOOL_ACTION highlightNet
Definition: pcb_actions.h:446
bool IsType(FRAME_T aType) const
void SetHighlight(bool aEnabled, int aNetcode=-1, bool aMulti=false)
Turns on/off highlighting.
std::shared_ptr< SHAPE_COMPOUND > GetEffectiveTextShape() const
Definition: eda_text.cpp:624
wxPoint GetPosition() const override
Definition: pad.h:177
static TOOL_ACTION selectOnSheetFromEeschema
Select all components on sheet from Eeschema crossprobing.
Definition: pcb_actions.h:87
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:190
#define _(s)
Definition: 3d_actions.cpp:33
SHAPE_LINE_CHAIN.
int hitTestDistance(const wxPoint &aWhere, BOARD_ITEM *aItem, int aMaxDistance) const
void SetIgnoreModulesOnFront(bool ignore)
Definition: collectors.h:561
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:594
virtual wxString GetSelectMenuText(EDA_UNITS aUnits) const
Return the text to display to be used in the selection clarification context menu when multiple items...
Definition: eda_item.cpp:123
const EDA_RECT GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: footprint.cpp:630
std::pair< VIEW_ITEM *, int > LAYER_ITEM_PAIR
Definition: view.h:72
void AddSubMenu(std::shared_ptr< ACTION_MENU > aSubMenu)
Store a submenu of this menu model.
Definition: tool_menu.cpp:52
bool IsToolActive() const
Definition: tool_base.cpp:31
wxString AsString() const
Definition: kiid.cpp:245
class NETINFO_ITEM, a description of a net
Definition: typeinfo.h:107
static TOOL_ACTION selectItem
Select an item (specified as the event parameter).
Definition: pcb_actions.h:66
class ZONE, managed by a footprint
Definition: typeinfo.h:94
Plated through hole pad.
Definition: pad_shapes.h:80
Handle the component boundary box.
Definition: eda_rect.h:42
ZONE_DISPLAY_MODE m_ZoneDisplayMode
PCBNEW_SETTINGS & Settings()
int Size() const
Returns the number of selected parts.
Definition: selection.h:128
The selection tool: currently supports:
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
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:149
static const TOOL_EVENT InhibitSelectionEditing
Definition: actions.h:220
coord_type GetHeight() const
Definition: box2.h:198
void RunOnChildren(const std::function< void(BOARD_ITEM *)> &aFunction) const
Invoke a function on all members of the group.
Definition: pcb_group.cpp:310
int UpdateMenu(const TOOL_EVENT &aEvent)
Pass the selection to a conditional menu for updating.
RESET_REASON
Determine the reason of reset for a tool.
Definition: tool_base.h:78
const wxPoint & GetEnd() const
Definition: track.h:113
static TOOL_ACTION deselectNet
Remove all connections belonging to a single net from the active selection.
Definition: pcb_actions.h:84
boost::optional< T > OPT
Definition: optional.h:7
void ClearFlags(STATUS_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: eda_item.h:203
virtual std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER) const
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
Definition: board_item.cpp:153
void SetVisible(VIEW_ITEM *aItem, bool aIsVisible=true)
Set the item visibility.
Definition: view.cpp:1454
int SelectAll(const TOOL_EVENT &aEvent)
Multiple item selection event handler.
void Combine()
Re-combine the backup list into the main list of the collector.
Definition: collector.h:148
ACTION_MENU * create() const override
< Return an instance of this class. It has to be overridden in inheriting classes.
Represent a selection area (currently a rectangle) in a VIEW, drawn corner-to-corner between two poin...
bool itemPassesFilter(BOARD_ITEM *aItem)
class ORTHOGONAL_DIMENSION, a linear dimension constrained to x/y
Definition: typeinfo.h:103
class VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:96
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1) override
Add a VIEW_ITEM to the view.
Definition: pcb_view.cpp:58
void selectAllItemsOnNet(int aNetCode, bool aSelect=true)
Select all items with the given net code.
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition: view.cpp:321
const Vec & GetSize() const
Definition: box2.h:189
virtual int Query(const BOX2I &aRect, std::vector< LAYER_ITEM_PAIR > &aResult) const
Find all visible items that touch or are within the rectangle aRect.
Definition: view.cpp:427
void RemoveItemFromSel(BOARD_ITEM *aItem, bool aQuietMode=false)
Multiple item unselection event handler.
KIGFX::VIEW_CONTROLS * getViewControls() const
Return the instance of VIEW_CONTROLS object used in the application.
Definition: tool_base.cpp:42
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition: view.h:67
void FilterCollectorForGroups(GENERAL_COLLECTOR &aCollector) const
#define SKIP_STRUCT
flag indicating that the structure should be ignored
Definition: eda_item.h:117
A general implementation of a COLLECTORS_GUIDE.
Definition: collectors.h:381
bool selectionContains(const VECTOR2I &aPoint) const
Definition: pad.h:60
double GetScale() const
Definition: view.h:263
int ClearSelection(const TOOL_EVENT &aEvent)
STATUS_FLAGS GetFlags() const
Definition: eda_item.h:204
void FilterCollectedItems(GENERAL_COLLECTOR &aCollector)
BOARD_ITEM_CONTAINER * GetParent() const
Definition: board_item.h:168
void FocusOnLocation(const wxPoint &aPos)
Useful to focus on a particular location, in find functions.
void unhighlightInternal(BOARD_ITEM *aItem, int aHighlightMode, bool aUsingOverlay)
void GuessSelectionCandidates(GENERAL_COLLECTOR &aCollector, const VECTOR2I &aWhere) const
Try to guess best selection candidates in case multiple items are clicked, by doing some brain-dead h...
virtual BITMAP_DEF GetMenuImage() const
Return a pointer to an image to be used in menus.
Definition: eda_item.cpp:222
class PCB_SHAPE, a segment not on copper layers
Definition: typeinfo.h:90
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:173
static TOOL_ACTION selectAll
Definition: actions.h:73
void selectAllItemsOnSheet(wxString &aSheetPath)
Select all items with the given sheet timestamp/UUID name (the sheet path).
void ShowContextMenu(SELECTION &aSelection)
Helper function to set and immediately show a CONDITIONAL_MENU in concert with the given SELECTION.
Definition: tool_menu.cpp:59
void FocusOnItem(BOARD_ITEM *aItem)
#define IS_NEW
New item, just created.
Definition: eda_item.h:106
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition: lset.cpp:905
void unhighlight(BOARD_ITEM *aItem, int aHighlightMode, PCB_SELECTION *aGroup=nullptr)
Unhighlight the item visually.
Base PCB main window class for Pcbnew, Gerbview, and CvPcb footprint viewer.
static TOOL_ACTION selectionCursor
Select a single item under the cursor position.
Definition: pcb_actions.h:60
void SetIgnoreThroughHolePads(bool ignore)
Definition: collectors.h:579
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:606
Definition: track.h:83
virtual double ViewGetLOD(int aLayer, VIEW *aView) const
Return the level of detail (LOD) of the item.
Definition: view_item.h:137
int filterSelection(const TOOL_EVENT &aEvent)
Return true if the given item passes the current SELECTION_FILTER_OPTIONS.
EDA_ITEM * Front() const
Definition: selection.h:203
virtual void Update(const VIEW_ITEM *aItem, int aUpdateFlags) const
For dynamic VIEWs, inform the associated VIEW that the graphical representation of this item has chan...
Definition: view.cpp:1508
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:162
static TOOL_ACTION selectSameSheet
Select all components on the same sheet as the selected footprint.
Definition: pcb_actions.h:90
bool IsLayerVisible(int aLayer) const
Return information about visibility of a particular layer.
Definition: view.h:404
void SetIgnorePadsOnBack(bool ignore)
Definition: collectors.h:567
virtual void Remove(EDA_ITEM *aItem)
Definition: selection.h:88