KiCad PCB EDA Suite
selection_tool.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2013-2017 CERN
5  * @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
6  * @author Maciej Suminski <maciej.suminski@cern.ch>
7  * Copyright (C) 2018 KiCad Developers, see AUTHORS.txt for contributors.
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, you may find one here:
21  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
22  * or you may search the http://www.gnu.org website for the version 2 license,
23  * or you may write to the Free Software Foundation, Inc.,
24  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25  */
26 
27 #include <limits>
28 #include <functional>
29 using namespace std::placeholders;
30 #include <class_board.h>
31 #include <class_board_item.h>
32 #include <class_track.h>
33 #include <class_module.h>
34 #include <class_drawsegment.h>
35 #include <class_zone.h>
36 #include <collectors.h>
37 #include <confirm.h>
38 #include <dialog_find.h>
39 #include <dialog_block_options.h>
40 #include <class_draw_panel_gal.h>
41 #include <view/view_controls.h>
43 #include <painter.h>
44 #include <bitmaps.h>
45 #include <tool/tool_event.h>
46 #include <tool/tool_manager.h>
47 #include <router/router_tool.h>
49 #include <footprint_viewer_frame.h>
50 #include <id.h>
51 #include "tool_event_utils.h"
52 #include "selection_tool.h"
53 #include "pcb_bright_box.h"
54 #include "pcb_actions.h"
55 
56 #include "kicad_plugin.h"
57 
58 
59 class SELECT_MENU : public ACTION_MENU
60 {
61 public:
63  ACTION_MENU( true )
64  {
65  SetTitle( _( "Select" ) );
66  SetIcon( options_generic_xpm );
67 
69 
70  AppendSeparator();
71 
76  }
77 
78 private:
79 
80  void update() override
81  {
82  using S_C = SELECTION_CONDITIONS;
83 
84  const auto& selection = getToolManager()->GetTool<SELECTION_TOOL>()->GetSelection();
85 
86  bool connItem = S_C::OnlyTypes( GENERAL_COLLECTOR::Tracks )( selection );
87  bool sheetSelEnabled = ( S_C::OnlyType( PCB_MODULE_T ) )( selection );
88 
89  Enable( getMenuId( PCB_ACTIONS::selectNet ), connItem );
90  Enable( getMenuId( PCB_ACTIONS::selectCopper ), connItem );
91  Enable( getMenuId( PCB_ACTIONS::selectConnection ), connItem );
92  Enable( getMenuId( PCB_ACTIONS::selectSameSheet ), sheetSelEnabled );
93  }
94 
95  ACTION_MENU* create() const override
96  {
97  return new SELECT_MENU();
98  }
99 };
100 
101 
106 {
107 public:
109 };
110 
111 
113  PCB_TOOL_BASE( "pcbnew.InteractiveSelection" ),
114  m_frame( NULL ),
115  m_additive( false ),
116  m_subtractive( false ),
117  m_exclusive_or( false ),
118  m_multiple( false ),
119  m_skip_heuristics( false ),
120  m_locked( true ),
121  m_priv( std::make_unique<PRIV>() )
122 {
123 }
124 
125 
127 {
128  getView()->Remove( &m_selection );
129 }
130 
131 
133 {
134  auto frame = getEditFrame<PCB_BASE_FRAME>();
135 
138  {
140  return true;
141  }
142 
143  auto selectMenu = std::make_shared<SELECT_MENU>();
144  selectMenu->SetTool( this );
145  m_menu.AddSubMenu( selectMenu );
146 
147  auto& menu = m_menu.GetMenu();
148 
149  menu.AddMenu( selectMenu.get(), SELECTION_CONDITIONS::NotEmpty );
150  menu.AddSeparator( 1000 );
151 
152  if( frame )
154 
155  return true;
156 }
157 
158 
160 {
161  m_frame = getEditFrame<PCB_BASE_FRAME>();
162  m_locked = true;
163 
164  if( aReason == TOOL_BASE::MODEL_RELOAD )
165  {
166  // Remove pointers to the selected items from containers
167  // without changing their properties (as they are already deleted
168  // while a new board is loaded)
169  m_selection.Clear();
170  getView()->GetPainter()->GetSettings()->SetHighlight( false );
171  }
172  else
173  {
174  // Restore previous properties of selected items and remove them from containers
175  ClearSelection( true );
176  }
177 
178  // Reinsert the VIEW_GROUP, in case it was removed from the VIEW
179  view()->Remove( &m_selection );
180  view()->Add( &m_selection );
181 }
182 
183 
184 int SELECTION_TOOL::Main( const TOOL_EVENT& aEvent )
185 {
186  // Main loop: keep receiving events
187  while( TOOL_EVENT* evt = Wait() )
188  {
189  if( m_frame->ToolStackIsEmpty() )
190  m_frame->GetCanvas()->SetCurrentCursor( wxCURSOR_ARROW );
191 
192  bool dragAlwaysSelects = getEditFrame<PCB_BASE_FRAME>()->GetDragSelects();
194 
195  if( evt->Modifier( MD_SHIFT ) && evt->Modifier( MD_CTRL ) )
196  m_subtractive = true;
197  else if( evt->Modifier( MD_SHIFT ) )
198  m_additive = true;
199  else if( evt->Modifier( MD_CTRL ) )
200  m_exclusive_or = true;
201 
202  // Is the user requesting that the selection list include all possible
203  // items without removing less likely selection candidates
204  m_skip_heuristics = !!evt->Modifier( MD_ALT );
205 
206  // Single click? Select single object
207  if( evt->IsClick( BUT_LEFT ) )
208  {
209  selectPoint( evt->Position() );
210  }
211 
212  // right click? if there is any object - show the context menu
213  else if( evt->IsClick( BUT_RIGHT ) )
214  {
215  bool selectionCancelled = false;
216 
217  if( m_selection.Empty() )
218  {
219  selectPoint( evt->Position(), false, &selectionCancelled );
220  m_selection.SetIsHover( true );
221  }
222 
223  if( !selectionCancelled )
225  }
226 
227  // double click? Display the properties window
228  else if( evt->IsDblClick( BUT_LEFT ) )
229  {
230  if( m_selection.Empty() )
231  selectPoint( evt->Position() );
232 
234  }
235 
236  // drag with LMB? Select multiple objects (or at least draw a selection box) or drag them
237  else if( evt->IsDrag( BUT_LEFT ) )
238  {
239  if( m_additive || m_subtractive || m_exclusive_or || dragAlwaysSelects )
240  {
241  selectMultiple();
242  }
243  else
244  {
245  // selection is empty? try to start dragging the item under the point where drag
246  // started
247  if( m_selection.Empty() && selectCursor() )
248  m_selection.SetIsHover( true );
249 
250  // Check if dragging has started within any of selected items bounding box
251  if( selectionContains( evt->Position() ) )
252  {
253  // Yes -> run the move tool and wait till it finishes
255  }
256  else
257  {
258  // No -> drag a selection box
259  selectMultiple();
260  }
261  }
262  }
263 
264  else if( evt->IsCancel() )
265  {
266  ClearSelection();
267 
268  if( evt->FirstResponder() == this )
270  }
271 
272  else if( evt->Action() == TA_UNDO_REDO_PRE )
273  {
274  ClearSelection();
275  }
276 
277  else
278  evt->SetPassEvent();
279  }
280 
281  // This tool is supposed to be active forever
282  assert( false );
283 
284  return 0;
285 }
286 
287 
289 {
290  return m_selection;
291 }
292 
293 
295  std::vector<BOARD_ITEM*>* aFiltered,
296  bool aConfirmLockedItems )
297 {
298  bool selectionEmpty = m_selection.Empty();
299  m_selection.SetIsHover( selectionEmpty );
300 
301  if( selectionEmpty )
302  {
303  m_toolMgr->RunAction( PCB_ACTIONS::selectionCursor, true, aClientFilter );
305  }
306 
307  if ( aConfirmLockedItems && CheckLock() == SELECTION_LOCKED )
308  {
309  ClearSelection();
310  return m_selection;
311  }
312 
313  if( aClientFilter )
314  {
315  GENERAL_COLLECTOR collector;
316 
317  for( auto item : m_selection )
318  collector.Append( item );
319 
320  aClientFilter( VECTOR2I(), collector );
321 
322  /*
323  * The first step is to find the items that may have been added by the client filter
324  * This can happen if the locked pads select the module instead
325  */
326  std::vector<EDA_ITEM*> new_items;
327  std::set_difference( collector.begin(), collector.end(),
329  std::back_inserter( new_items ) );
330 
334  std::vector<EDA_ITEM*> diff;
335  std::set_difference( m_selection.begin(), m_selection.end(),
336  collector.begin(), collector.end(),
337  std::back_inserter( diff ) );
338 
339  if( aFiltered )
340  {
341  for( auto item : diff )
342  aFiltered->push_back( static_cast<BOARD_ITEM*>( item ) );
343  }
344 
349  for( auto item : diff )
350  unhighlight( static_cast<BOARD_ITEM*>( item ), SELECTED, &m_selection );
351 
352  for( auto item : new_items )
353  highlight( static_cast<BOARD_ITEM*>( item ), SELECTED, &m_selection );
354 
356  }
357 
358  return m_selection;
359 }
360 
361 
363 {
364  GENERAL_COLLECTORS_GUIDE guide( board()->GetVisibleLayers(),
365  (PCB_LAYER_ID) view()->GetTopLayer(), view() );
366 
367  // account for the globals
368  guide.SetIgnoreMTextsMarkedNoShow( ! board()->IsElementVisible( LAYER_MOD_TEXT_INVISIBLE ) );
369  guide.SetIgnoreMTextsOnBack( ! board()->IsElementVisible( LAYER_MOD_TEXT_BK ) );
370  guide.SetIgnoreMTextsOnFront( ! board()->IsElementVisible( LAYER_MOD_TEXT_FR ) );
371  guide.SetIgnoreModulesOnBack( ! board()->IsElementVisible( LAYER_MOD_BK ) );
372  guide.SetIgnoreModulesOnFront( ! board()->IsElementVisible( LAYER_MOD_FR ) );
373  guide.SetIgnorePadsOnBack( ! board()->IsElementVisible( LAYER_PAD_BK ) );
374  guide.SetIgnorePadsOnFront( ! board()->IsElementVisible( LAYER_PAD_FR ) );
375  guide.SetIgnoreThroughHolePads( ! board()->IsElementVisible( LAYER_PADS_TH ) );
376  guide.SetIgnoreModulesVals( ! board()->IsElementVisible( LAYER_MOD_VALUES ) );
377  guide.SetIgnoreModulesRefs( ! board()->IsElementVisible( LAYER_MOD_REFERENCES ) );
378  guide.SetIgnoreThroughVias( ! board()->IsElementVisible( LAYER_VIA_THROUGH ) );
379  guide.SetIgnoreBlindBuriedVias( ! board()->IsElementVisible( LAYER_VIA_BBLIND ) );
380  guide.SetIgnoreMicroVias( ! board()->IsElementVisible( LAYER_VIA_MICROVIA ) );
381  guide.SetIgnoreTracks( ! board()->IsElementVisible( LAYER_TRACKS ) );
382 
383  return guide;
384 }
385 
386 
387 bool SELECTION_TOOL::selectPoint( const VECTOR2I& aWhere, bool aOnDrag,
388  bool* aSelectionCancelledFlag,
389  CLIENT_SELECTION_FILTER aClientFilter )
390 {
392  GENERAL_COLLECTOR collector;
394  bool cleared = false;
395 
396  guide.SetIgnoreZoneFills( displayOpts->m_DisplayZonesMode != 0 );
397 
398  collector.Collect( board(),
400  wxPoint( aWhere.x, aWhere.y ), guide );
401 
402  // Remove unselectable items
403  for( int i = collector.GetCount() - 1; i >= 0; --i )
404  {
405  if( !Selectable( collector[ i ] ) || ( aOnDrag && collector[i]->IsLocked() ) )
406  collector.Remove( i );
407  }
408 
410 
411  // Allow the client to do tool- or action-specific filtering to see if we
412  // can get down to a single item
413  if( aClientFilter )
414  aClientFilter( aWhere, collector );
415 
416  // Apply some ugly heuristics to avoid disambiguation menus whenever possible
417  if( collector.GetCount() > 1 && !m_skip_heuristics )
418  {
419  GuessSelectionCandidates( collector, aWhere );
420  }
421 
422  // If still more than one item we're going to have to ask the user.
423  if( collector.GetCount() > 1 )
424  {
425  if( aOnDrag )
427 
428  if( !doSelectionMenu( &collector, _( "Clarify Selection" ) ) )
429  {
430  if( aSelectionCancelledFlag )
431  *aSelectionCancelledFlag = true;
432 
433  return false;
434  }
435  }
436 
438  {
439  if( m_selection.GetSize() > 0 )
440  {
441  // Don't fire an event now as it will end up redundant if we fire a SelectedEvent
442  // or an UnselectedEvent.
443  cleared = true;
444  ClearSelection( true );
445  }
446  }
447 
448  if( collector.GetCount() == 1 )
449  {
450  BOARD_ITEM* item = collector[ 0 ];
451 
452  if( m_subtractive || ( m_exclusive_or && item->IsSelected() ) )
453  {
454  unselect( item );
456  return false;
457  }
458  else
459  {
460  select( item );
462  return true;
463  }
464  }
465 
466  if( cleared )
468 
469  return false;
470 }
471 
472 
473 bool SELECTION_TOOL::selectCursor( bool aForceSelect, CLIENT_SELECTION_FILTER aClientFilter )
474 {
475  if( aForceSelect || m_selection.Empty() )
476  {
477  ClearSelection( true /*quiet mode*/ );
478  selectPoint( getViewControls()->GetCursorPosition( false ), false, NULL, aClientFilter );
479  }
480 
481  return !m_selection.Empty();
482 }
483 
484 
486 {
487  bool cancelled = false; // Was the tool cancelled while it was running?
488  m_multiple = true; // Multiple selection mode is active
489  KIGFX::VIEW* view = getView();
490 
492  view->Add( &area );
493 
494  bool anyAdded = false;
495  bool anySubtracted = false;
496 
497  while( TOOL_EVENT* evt = Wait() )
498  {
499  if( evt->IsCancelInteractive() || evt->IsActivate() )
500  {
501  cancelled = true;
502  break;
503  }
504 
505  if( evt->IsDrag( BUT_LEFT ) )
506  {
508  {
509  if( m_selection.GetSize() > 0 )
510  {
511  anySubtracted = true;
512  ClearSelection( true /*quiet mode*/ );
513  }
514  }
515 
516  // Start drawing a selection box
517  area.SetOrigin( evt->DragOrigin() );
518  area.SetEnd( evt->Position() );
519  area.SetAdditive( m_additive );
522 
523  view->SetVisible( &area, true );
524  view->Update( &area );
525  getViewControls()->SetAutoPan( true );
526  }
527 
528  if( evt->IsMouseUp( BUT_LEFT ) )
529  {
530  getViewControls()->SetAutoPan( false );
531 
532  // End drawing the selection box
533  view->SetVisible( &area, false );
534 
535  // Mark items within the selection box as selected
536  std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> selectedItems;
537 
538  // Filter the view items based on the selection box
539  BOX2I selectionBox = area.ViewBBox();
540  view->Query( selectionBox, selectedItems ); // Get the list of selected items
541 
542  std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR>::iterator it, it_end;
543 
544  int width = area.GetEnd().x - area.GetOrigin().x;
545  int height = area.GetEnd().y - area.GetOrigin().y;
546 
547  /* Selection mode depends on direction of drag-selection:
548  * Left > Right : Select objects that are fully enclosed by selection
549  * Right > Left : Select objects that are crossed by selection
550  */
551  bool windowSelection = width >= 0 ? true : false;
552 
553  if( view->IsMirroredX() )
554  windowSelection = !windowSelection;
555 
556  // Construct an EDA_RECT to determine BOARD_ITEM selection
557  EDA_RECT selectionRect( (wxPoint) area.GetOrigin(), wxSize( width, height ) );
558 
559  selectionRect.Normalize();
560 
561  for( it = selectedItems.begin(), it_end = selectedItems.end(); it != it_end; ++it )
562  {
563  BOARD_ITEM* item = static_cast<BOARD_ITEM*>( it->first );
564 
565  if( !item || !Selectable( item ) )
566  continue;
567 
568  if( item->HitTest( selectionRect, windowSelection ) )
569  {
570  if( m_subtractive || ( m_exclusive_or && item->IsSelected() ) )
571  {
572  unselect( item );
573  anySubtracted = true;
574  }
575  else
576  {
577  select( item );
578  anyAdded = true;
579  }
580  }
581  }
582 
583  m_selection.SetIsHover( false );
584 
585  // Inform other potentially interested tools
586  if( anyAdded )
588  else if( anySubtracted )
590 
591  break; // Stop waiting for events
592  }
593  }
594 
595  getViewControls()->SetAutoPan( false );
596 
597  // Stop drawing the selection box
598  view->Remove( &area );
599  m_multiple = false; // Multiple selection mode is inactive
600 
601  if( !cancelled )
603 
604  return cancelled;
605 }
606 
607 
609 {
610  if( !m_locked || m_editModules )
611  return SELECTION_UNLOCKED;
612 
613  bool containsLocked = false;
614 
615  // Check if the selection contains locked items
616  for( const auto& item : m_selection )
617  {
618  switch( item->Type() )
619  {
620  case PCB_MODULE_T:
621  if( static_cast<MODULE*>( item )->IsLocked() )
622  containsLocked = true;
623  break;
624 
625  case PCB_MODULE_EDGE_T:
626  case PCB_MODULE_TEXT_T:
627  if( static_cast<MODULE*>( item->GetParent() )->IsLocked() )
628  containsLocked = true;
629  break;
630 
631  default: // suppress warnings
632  break;
633  }
634  }
635 
636  if( containsLocked )
637  {
638  if( IsOK( m_frame, _( "Selection contains locked items. Do you want to continue?" ) ) )
639  {
640  m_locked = false;
642  }
643  else
644  return SELECTION_LOCKED;
645  }
646 
647  return SELECTION_UNLOCKED;
648 }
649 
650 
652 {
654 
655  selectCursor( false, aClientFilter );
656 
657  return 0;
658 }
659 
660 
662 {
663  ClearSelection();
664 
665  return 0;
666 }
667 
668 
670 {
671  std::vector<BOARD_ITEM*>* items = aEvent.Parameter<std::vector<BOARD_ITEM*>*>();
672 
673  if( items )
674  {
675  // Perform individual selection of each item before processing the event.
676  for( auto item : *items )
677  select( item );
678 
680  }
681 
682  return 0;
683 }
684 
685 
687 {
688  AddItemToSel( aEvent.Parameter<BOARD_ITEM*>() );
689  return 0;
690 }
691 
692 
693 void SELECTION_TOOL::AddItemToSel( BOARD_ITEM* aItem, bool aQuietMode )
694 {
695  if( aItem )
696  {
697  select( aItem );
698 
699  // Inform other potentially interested tools
700  if( !aQuietMode )
702  }
703 }
704 
705 
707 {
708  std::vector<BOARD_ITEM*>* items = aEvent.Parameter<std::vector<BOARD_ITEM*>*>();
709 
710  if( items )
711  {
712  // Perform individual unselection of each item before processing the event
713  for( auto item : *items )
714  unselect( item );
715 
717  }
718 
719  return 0;
720 }
721 
722 
724 {
725  // Check if there is an item to be selected
726  BOARD_ITEM* item = aEvent.Parameter<BOARD_ITEM*>();
727 
728  if( item )
729  {
730  unselect( item );
731 
732  // Inform other potentially interested tools
734  }
735 
736  return 0;
737 }
738 
739 
741 {
742  highlight( aItem, BRIGHTENED );
743 }
744 
745 
747 {
748  unhighlight( aItem, BRIGHTENED );
749 }
750 
751 
752 void connectedTrackFilter( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector )
753 {
754  // Narrow the collection down to a single TRACK item for a trivial connection, or
755  // multiple TRACK items for non-trivial connections.
756  for( int i = aCollector.GetCount() - 1; i >= 0; i-- )
757  {
758  if( !dynamic_cast<TRACK*>( aCollector[i] ) )
759  aCollector.Remove( i );
760  }
761 
762  ROUTER_TOOL::NeighboringSegmentFilter( aPt, aCollector );
763 }
764 
765 
767 {
770 
772  return 0;
773 
774  return expandConnection( aEvent );
775 }
776 
777 
779 {
780  // copy the selection, since we're going to iterate and modify
781  auto selection = m_selection.GetItems();
782 
783  // We use the BUSY flag to mark connections
784  for( auto item : selection )
785  item->SetState( BUSY, false );
786 
787  for( auto item : selection )
788  {
789  TRACK* trackItem = dynamic_cast<TRACK*>( item );
790 
791  // Track items marked BUSY have already been visited
792  // therefore their connections have already been marked
793  if( trackItem && !trackItem->GetState( BUSY ) )
794  {
795  if( aEvent.GetCommandId()
797  selectAllItemsConnectedToItem( *trackItem );
798  else
799  selectAllItemsConnectedToTrack( *trackItem );
800  }
801  }
802 
803  // Inform other potentially interested tools
804  if( m_selection.Size() > 0 )
806 
807  return 0;
808 }
809 
810 
811 void connectedItemFilter( const VECTOR2I&, GENERAL_COLLECTOR& aCollector )
812 {
813  // Narrow the collection down to a single BOARD_CONNECTED_ITEM for each represented net.
814  // All other items types are removed.
815  std::set<int> representedNets;
816 
817  for( int i = aCollector.GetCount() - 1; i >= 0; i-- )
818  {
819  BOARD_CONNECTED_ITEM* item = dynamic_cast<BOARD_CONNECTED_ITEM*>( aCollector[i] );
820  if( !item )
821  aCollector.Remove( i );
822  else if ( representedNets.count( item->GetNetCode() ) )
823  aCollector.Remove( i );
824  else
825  representedNets.insert( item->GetNetCode() );
826  }
827 }
828 
829 
831 {
832  bool haveCopper = false;
833 
834  for( auto item : m_selection.GetItems() )
835  {
836  if( dynamic_cast<BOARD_CONNECTED_ITEM*>( item ) )
837  haveCopper = true;;
838  }
839 
840  if( !haveCopper )
842 
843  // copy the selection, since we're going to iterate and modify
844  auto selection = m_selection.GetItems();
845 
846  for( auto item : selection )
847  {
848  BOARD_CONNECTED_ITEM* connItem = dynamic_cast<BOARD_CONNECTED_ITEM*>( item );
849 
850  if( connItem )
851  selectAllItemsConnectedToItem( *connItem );
852  }
853 
854  // Inform other potentially interested tools
855  if( m_selection.Size() > 0 )
857 
858  return 0;
859 }
860 
861 
863 {
864  constexpr KICAD_T types[] = { PCB_TRACE_T, PCB_VIA_T, EOT };
865  auto connectivity = board()->GetConnectivity();
866 
867  for( auto item : connectivity->GetConnectedItems(
868  static_cast<BOARD_CONNECTED_ITEM*>( &aSourceTrack ), types ) )
869  select( item );
870 }
871 
872 
874 {
875  constexpr KICAD_T types[] = { PCB_TRACE_T, PCB_VIA_T, PCB_PAD_T, EOT };
876  auto connectivity = board()->GetConnectivity();
877 
878  for( auto item : connectivity->GetConnectedItems( &aSourceItem, types ) )
879  {
880  // We want to select items connected through pads but not pads
881  // otherwise, the common use case of "Select Copper"->Delete will
882  // remove footprints in addition to traces and vias
883  if( item->Type() != PCB_PAD_T )
884  select( item );
885  }
886 }
887 
888 
890 {
891  constexpr KICAD_T types[] = { PCB_TRACE_T, PCB_VIA_T, EOT };
892  auto connectivity = board()->GetConnectivity();
893 
894  for( auto item : connectivity->GetNetItems( aNetCode, types ) )
895  select( item );
896 }
897 
898 
900 {
901  if( !selectCursor() )
902  return 0;
903 
904  // copy the selection, since we're going to iterate and modify
905  auto selection = m_selection.GetItems();
906 
907  for( auto i : selection )
908  {
909  auto item = static_cast<BOARD_ITEM*>( i );
910 
911  // only connected items get a net code
912  if( item->IsConnected() )
913  {
914  auto& connItem = static_cast<BOARD_CONNECTED_ITEM&>( *item );
915 
916  selectAllItemsOnNet( connItem.GetNetCode() );
917  }
918  }
919 
920  // Inform other potentially interested tools
921  if( m_selection.Size() > 0 )
923 
924  return 0;
925 }
926 
927 
928 void SELECTION_TOOL::selectAllItemsOnSheet( wxString& aSheetpath )
929 {
930  std::list<MODULE*> modList;
931 
932  // store all modules that are on that sheet
933  for( auto mitem : board()->Modules() )
934  {
935  if( mitem != NULL && mitem->GetPath().Contains( aSheetpath ) )
936  {
937  modList.push_back( mitem );
938  }
939  }
940 
941  //Generate a list of all pads, and of all nets they belong to.
942  std::list<int> netcodeList;
943  std::list<BOARD_CONNECTED_ITEM*> padList;
944  for( MODULE* mmod : modList )
945  {
946  for( auto pad : mmod->Pads() )
947  {
948  if( pad->IsConnected() )
949  {
950  netcodeList.push_back( pad->GetNetCode() );
951  padList.push_back( pad );
952  }
953  }
954  }
955  // remove all duplicates
956  netcodeList.sort();
957  netcodeList.unique();
958 
959  // auto select trivial connections segments which are launched from the pads
960  std::list<TRACK*> launchTracks;
961 
962  for( auto pad : padList )
963  {
965  }
966 
967  // now we need to find all modules that are connected to each of these nets
968  // then we need to determine if these modules are in the list of modules
969  // belonging to this sheet ( modList )
970  std::list<int> removeCodeList;
971  constexpr KICAD_T padType[] = { PCB_PAD_T, EOT };
972 
973  for( int netCode : netcodeList )
974  {
975  for( BOARD_CONNECTED_ITEM* mitem : board()->GetConnectivity()->GetNetItems( netCode, padType ) )
976  {
977  if( mitem->Type() == PCB_PAD_T)
978  {
979  bool found = ( std::find( modList.begin(), modList.end(),
980  mitem->GetParent() ) != modList.end() );
981 
982  if( !found )
983  {
984  // if we cannot find the module of the pad in the modList
985  // then we can assume that that module is not located in the same
986  // schematic, therefore invalidate this netcode.
987  removeCodeList.push_back( netCode );
988  break;
989  }
990  }
991  }
992  }
993 
994  // remove all duplicates
995  removeCodeList.sort();
996  removeCodeList.unique();
997 
998  for( int removeCode : removeCodeList )
999  {
1000  netcodeList.remove( removeCode );
1001  }
1002 
1003  std::list<BOARD_CONNECTED_ITEM*> localConnectionList;
1004  constexpr KICAD_T trackViaType[] = { PCB_TRACE_T, PCB_VIA_T, EOT };
1005 
1006  for( int netCode : netcodeList )
1007  {
1008  for( BOARD_CONNECTED_ITEM* item : board()->GetConnectivity()->GetNetItems( netCode, trackViaType ) )
1009  {
1010  localConnectionList.push_back( item );
1011  }
1012  }
1013 
1014  for( BOARD_ITEM* i : modList )
1015  {
1016  if( i != NULL )
1017  select( i );
1018  }
1019 
1020  for( BOARD_CONNECTED_ITEM* i : localConnectionList )
1021  {
1022  if( i != NULL )
1023  select( i );
1024  }
1025 }
1026 
1027 
1029 {
1030  //Should recalculate the view to zoom in on the selection
1031  auto selectionBox = m_selection.ViewBBox();
1032  auto view = getView();
1033 
1034  VECTOR2D screenSize = view->ToWorld( m_frame->GetCanvas()->GetClientSize(), false );
1035 
1036  if( selectionBox.GetWidth() != 0 || selectionBox.GetHeight() != 0 )
1037  {
1038  VECTOR2D vsize = selectionBox.GetSize();
1039  double scale = view->GetScale() / std::max( fabs( vsize.x / screenSize.x ),
1040  fabs( vsize.y / screenSize.y ) );
1041  view->SetScale( scale );
1042  view->SetCenter( selectionBox.Centre() );
1043  view->Add( &m_selection );
1044  }
1045 
1047 }
1048 
1049 
1051 {
1052  ClearSelection( true /*quiet mode*/ );
1053  wxString* sheetpath = aEvent.Parameter<wxString*>();
1054 
1055  selectAllItemsOnSheet( *sheetpath );
1056 
1057  zoomFitSelection();
1058 
1059  if( m_selection.Size() > 0 )
1061 
1062  return 0;
1063 }
1064 
1065 
1067 {
1068  if( !selectCursor( true ) )
1069  return 0;
1070 
1071  // this function currently only supports modules since they are only
1072  // on one sheet.
1073  auto item = m_selection.Front();
1074 
1075  if( !item )
1076  return 0;
1077 
1078  if( item->Type() != PCB_MODULE_T )
1079  return 0;
1080 
1081  auto mod = dynamic_cast<MODULE*>( item );
1082 
1083  ClearSelection( true /*quiet mode*/ );
1084 
1085  // get the lowest subsheet name for this.
1086  wxString sheetPath = mod->GetPath();
1087  sheetPath = sheetPath.BeforeLast( '/' );
1088  sheetPath = sheetPath.AfterLast( '/' );
1089 
1090  selectAllItemsOnSheet( sheetPath );
1091 
1092  // Inform other potentially interested tools
1093  if( m_selection.Size() > 0 )
1095 
1096  return 0;
1097 }
1098 
1099 
1101 {
1102  bool cleared = false;
1103 
1104  if( m_selection.GetSize() > 0 )
1105  {
1106  // Don't fire an event now; most of the time it will be redundant as we're about to
1107  // fire a SelectedEvent.
1108  cleared = true;
1109  ClearSelection( true /*quiet mode*/ );
1110  }
1111 
1112  if( aItem )
1113  {
1114  select( aItem );
1115  m_frame->FocusOnLocation( aItem->GetPosition() );
1116 
1117  // Inform other potentially interested tools
1119  }
1120  else if( cleared )
1121  {
1123  }
1124 
1126 }
1127 
1128 
1129 int SELECTION_TOOL::find( const TOOL_EVENT& aEvent )
1130 {
1131  DIALOG_FIND dlg( m_frame );
1132  dlg.SetCallback( std::bind( &SELECTION_TOOL::findCallback, this, _1 ) );
1133  dlg.ShowModal();
1134 
1135  return 0;
1136 }
1137 
1138 
1147 static bool itemIsIncludedByFilter( const BOARD_ITEM& aItem,
1148  const BOARD& aBoard,
1149  const DIALOG_BLOCK_OPTIONS::OPTIONS& aBlockOpts )
1150 {
1151  bool include = true;
1152  const PCB_LAYER_ID layer = aItem.GetLayer();
1153 
1154  // can skip without even checking item type
1155  // fixme: selecting items on invisible layers does not work in GAL
1156  if( !aBlockOpts.includeItemsOnInvisibleLayers
1157  && !aBoard.IsLayerVisible( layer ) )
1158  {
1159  include = false;
1160  }
1161 
1162  // if the item needs to be checked against the options
1163  if( include )
1164  {
1165  switch( aItem.Type() )
1166  {
1167  case PCB_MODULE_T:
1168  {
1169  const auto& module = static_cast<const MODULE&>( aItem );
1170 
1171  include = aBlockOpts.includeModules;
1172 
1173  if( include && !aBlockOpts.includeLockedModules )
1174  {
1175  include = !module.IsLocked();
1176  }
1177 
1178  break;
1179  }
1180  case PCB_TRACE_T:
1181  {
1182  include = aBlockOpts.includeTracks;
1183  break;
1184  }
1185  case PCB_VIA_T:
1186  {
1187  include = aBlockOpts.includeVias;
1188  break;
1189  }
1190  case PCB_ZONE_AREA_T:
1191  {
1192  include = aBlockOpts.includeZones;
1193  break;
1194  }
1195  case PCB_LINE_T:
1196  case PCB_TARGET_T:
1197  case PCB_DIMENSION_T:
1198  {
1199  if( layer == Edge_Cuts )
1200  include = aBlockOpts.includeBoardOutlineLayer;
1201  else
1202  include = aBlockOpts.includeItemsOnTechLayers;
1203  break;
1204  }
1205  case PCB_TEXT_T:
1206  {
1207  include = aBlockOpts.includePcbTexts;
1208  break;
1209  }
1210  default:
1211  {
1212  // no filtering, just select it
1213  break;
1214  }
1215  }
1216  }
1217 
1218  return include;
1219 }
1220 
1221 
1223 {
1224  const BOARD& board = *getModel<BOARD>();
1225  DIALOG_BLOCK_OPTIONS::OPTIONS& opts = m_priv->m_filterOpts;
1226  DIALOG_BLOCK_OPTIONS dlg( m_frame, opts, false, _( "Filter selection" ) );
1227 
1228  const int cmd = dlg.ShowModal();
1229 
1230  if( cmd != wxID_OK )
1231  return 0;
1232 
1233  // copy current selection
1234  std::deque<EDA_ITEM*> selection = m_selection.GetItems();
1235 
1236  ClearSelection( true /*quiet mode*/ );
1237 
1238  // re-select items from the saved selection according to the dialog options
1239  for( EDA_ITEM* i : selection )
1240  {
1241  BOARD_ITEM* item = static_cast<BOARD_ITEM*>( i );
1242  bool include = itemIsIncludedByFilter( *item, board, opts );
1243 
1244  if( include )
1245  select( item );
1246  }
1247 
1249 
1250  return 0;
1251 }
1252 
1253 
1254 void SELECTION_TOOL::ClearSelection( bool aQuietMode )
1255 {
1256  if( m_selection.Empty() )
1257  return;
1258 
1259  while( m_selection.GetSize() )
1260  unhighlight( static_cast<BOARD_ITEM*>( m_selection.Front() ), SELECTED, &m_selection );
1261 
1262  view()->Update( &m_selection );
1263 
1264  m_selection.SetIsHover( false );
1266 
1267  m_locked = true;
1268 
1269  // Inform other potentially interested tools
1270  if( !aQuietMode )
1271  {
1274  }
1275 }
1276 
1277 
1279 {
1280  m_selection.Clear();
1281 
1282  INSPECTOR_FUNC inspector = [&] ( EDA_ITEM* item, void* testData )
1283  {
1284  if( item->IsSelected() )
1285  {
1286  EDA_ITEM* parent = item->GetParent();
1287 
1288  // Flags on module children might be set only because the parent is selected.
1289  if( parent && parent->Type() == PCB_MODULE_T && parent->IsSelected() )
1290  return SEARCH_CONTINUE;
1291 
1292  highlight( (BOARD_ITEM*) item, SELECTED, &m_selection );
1293  }
1294 
1295  return SEARCH_CONTINUE;
1296  };
1297 
1298  board()->Visit( inspector, nullptr, m_editModules ? GENERAL_COLLECTOR::ModuleItems
1300 }
1301 
1302 
1304 {
1305  GENERAL_COLLECTOR* collector = aEvent.Parameter<GENERAL_COLLECTOR*>();
1306 
1307  doSelectionMenu( collector, wxEmptyString );
1308 
1309  return 0;
1310 }
1311 
1312 
1313 bool SELECTION_TOOL::doSelectionMenu( GENERAL_COLLECTOR* aCollector, const wxString& aTitle )
1314 {
1315  BOARD_ITEM* current = nullptr;
1316  PCBNEW_SELECTION highlightGroup;
1317  ACTION_MENU menu( true );
1318 
1319  highlightGroup.SetLayer( LAYER_SELECT_OVERLAY );
1320  getView()->Add( &highlightGroup );
1321 
1322  int limit = std::min( 9, aCollector->GetCount() );
1323 
1324  for( int i = 0; i < limit; ++i )
1325  {
1326  wxString text;
1327  BOARD_ITEM* item = ( *aCollector )[i];
1328  text = item->GetSelectMenuText( m_frame->GetUserUnits() );
1329 
1330  wxString menuText = wxString::Format("&%d. %s", i + 1, text );
1331  menu.Add( menuText, i + 1, item->GetMenuImage() );
1332  }
1333 
1334  if( aTitle.Length() )
1335  menu.SetTitle( aTitle );
1336 
1337  menu.SetIcon( info_xpm );
1338  menu.DisplayTitle( true );
1339  SetContextMenu( &menu, CMENU_NOW );
1340 
1341  while( TOOL_EVENT* evt = Wait() )
1342  {
1343  if( evt->Action() == TA_CHOICE_MENU_UPDATE )
1344  {
1345  if( current )
1346  unhighlight( current, BRIGHTENED, &highlightGroup );
1347 
1348  int id = *evt->GetCommandId();
1349 
1350  // User has pointed an item, so show it in a different way
1351  if( id > 0 && id <= limit )
1352  {
1353  current = ( *aCollector )[id - 1];
1354  highlight( current, BRIGHTENED, &highlightGroup );
1355  }
1356  else
1357  {
1358  current = NULL;
1359  }
1360  }
1361  else if( evt->Action() == TA_CHOICE_MENU_CHOICE )
1362  {
1363  if( current )
1364  unhighlight( current, BRIGHTENED, &highlightGroup );
1365 
1366  OPT<int> id = evt->GetCommandId();
1367 
1368  // User has selected an item, so this one will be returned
1369  if( id && ( *id > 0 ) )
1370  current = ( *aCollector )[*id - 1];
1371  else
1372  current = NULL;
1373 
1374  break;
1375  }
1376  }
1377  getView()->Remove( &highlightGroup );
1378 
1379  if( current )
1380  {
1381  aCollector->Empty();
1382  aCollector->Append( current );
1383  return true;
1384  }
1385 
1386  return false;
1387 }
1388 
1389 
1391 {
1392  int count = aCollector->GetPrimaryCount(); // try to use preferred layer
1393 
1394  if( 0 == count )
1395  count = aCollector->GetCount();
1396 
1397  for( int i = 0; i < count; ++i )
1398  {
1399  if( ( *aCollector )[i]->Type() != PCB_MODULE_T )
1400  return NULL;
1401  }
1402 
1403  // All are modules, now find smallest MODULE
1404  int minDim = 0x7FFFFFFF;
1405  int minNdx = 0;
1406 
1407  for( int i = 0; i < count; ++i )
1408  {
1409  MODULE* module = (MODULE*) ( *aCollector )[i];
1410 
1411  int lx = module->GetFootprintRect().GetWidth();
1412  int ly = module->GetFootprintRect().GetHeight();
1413 
1414  int lmin = std::min( lx, ly );
1415 
1416  if( lmin < minDim )
1417  {
1418  minDim = lmin;
1419  minNdx = i;
1420  }
1421  }
1422 
1423  return (*aCollector)[minNdx];
1424 }
1425 
1426 
1427 bool SELECTION_TOOL::Selectable( const BOARD_ITEM* aItem, bool checkVisibilityOnly ) const
1428 {
1429  // Is high contrast mode enabled?
1430  bool highContrast = getView()->GetPainter()->GetSettings()->GetHighContrast();
1431 
1432  int layers[KIGFX::VIEW::VIEW_MAX_LAYERS], layers_count;
1433 
1434  // Filter out items that do not belong to active layers
1435  std::set<unsigned int> activeLayers = getView()->GetPainter()->GetSettings()->GetActiveLayers();
1436 
1437  // The markers layer is considered to be always active
1438  activeLayers.insert( (unsigned int) LAYER_DRC );
1439 
1440  aItem->ViewGetLayers( layers, layers_count );
1441 
1442  if( highContrast )
1443  {
1444  bool onActive = false; // Is the item on any of active layers?
1445 
1446  for( int i = 0; i < layers_count; ++i )
1447  {
1448  if( activeLayers.count( layers[i] ) > 0 ) // Item is on at least one of the active layers
1449  {
1450  onActive = true;
1451  break;
1452  }
1453  }
1454 
1455  if( !onActive ) // We do not want to select items that are in the background
1456  {
1457  return false;
1458  }
1459  }
1460 
1461  switch( aItem->Type() )
1462  {
1463  case PCB_ZONE_AREA_T:
1464  // Keepout zones can exist on multiple layers!
1465  {
1466  auto* zone = static_cast<const ZONE_CONTAINER*>( aItem );
1467 
1468  if( zone->GetIsKeepout() )
1469  {
1470  auto zoneLayers = zone->GetLayerSet().Seq();
1471 
1472  for( unsigned int i = 0; i < zoneLayers.size(); i++ )
1473  {
1474  if( board()->IsLayerVisible( zoneLayers[i] ) )
1475  {
1476  return true;
1477  }
1478  }
1479 
1480  // No active layers selected!
1481  return false;
1482  }
1483  }
1484  break;
1485 
1486  case PCB_TRACE_T:
1487  {
1488  if( !board()->IsElementVisible( LAYER_TRACKS ) )
1489  return false;
1490  }
1491  break;
1492 
1493  case PCB_VIA_T:
1494  {
1495  const VIA* via = static_cast<const VIA*>( aItem );
1496 
1497  // Check if appropriate element layer is visible
1498  switch( via->GetViaType() )
1499  {
1500  case VIA_THROUGH:
1502  return false;
1503  break;
1504 
1505  case VIA_BLIND_BURIED:
1507  return false;
1508  break;
1509 
1510  case VIA_MICROVIA:
1512  return false;
1513  break;
1514 
1515  default:
1516  wxFAIL;
1517  return false;
1518  }
1519 
1520  // For vias it is enough if only one of its layers is visible
1521  return ( board()->GetVisibleLayers() & via->GetLayerSet() ).any();
1522  }
1523 
1524  case PCB_MODULE_T:
1525  {
1526  // In modedit, we do not want to select the module itself.
1527  if( m_editModules )
1528  return false;
1529 
1530  // Allow selection of footprints if some part of the footprint is visible.
1531 
1532  MODULE* module = const_cast<MODULE*>( static_cast<const MODULE*>( aItem ) );
1533 
1534  for( auto item : module->GraphicalItems() )
1535  {
1536  if( Selectable( item, true ) )
1537  return true;
1538  }
1539 
1540  for( auto pad : module->Pads() )
1541  {
1542  if( Selectable( pad, true ) )
1543  return true;
1544  }
1545 
1546  return false;
1547  }
1548 
1549  case PCB_MODULE_TEXT_T:
1550  // Multiple selection is only allowed in modedit mode. In pcbnew, you have to select
1551  // module subparts one by one, rather than with a drag selection. This is so you can
1552  // pick up items under an (unlocked) module without also moving the module's sub-parts.
1553  if( !m_editModules && !checkVisibilityOnly )
1554  {
1555  if( m_multiple )
1556  return false;
1557  }
1558 
1559  if( !m_editModules && !view()->IsVisible( aItem ) )
1560  return false;
1561 
1562  break;
1563 
1564  case PCB_MODULE_EDGE_T:
1565  case PCB_PAD_T:
1566  {
1567  // Multiple selection is only allowed in modedit mode. In pcbnew, you have to select
1568  // module subparts one by one, rather than with a drag selection. This is so you can
1569  // pick up items under an (unlocked) module without also moving the module's sub-parts.
1570  if( !m_editModules && !checkVisibilityOnly )
1571  {
1572  if( m_multiple )
1573  return false;
1574  }
1575 
1576  if( aItem->Type() == PCB_PAD_T )
1577  {
1578  auto pad = static_cast<const D_PAD*>( aItem );
1579 
1580  // In pcbnew, locked modules prevent individual pad selection.
1581  // In modedit, we don't enforce this as the module is assumed to be edited by design.
1582  if( !m_editModules && !checkVisibilityOnly )
1583  {
1584  if( pad->GetParent() && pad->GetParent()->IsLocked() )
1585  return false;
1586  }
1587 
1588  // Check render mode (from the Items tab) first
1589  switch( pad->GetAttribute() )
1590  {
1591  case PAD_ATTRIB_STANDARD:
1593  if( !board()->IsElementVisible( LAYER_PADS_TH ) )
1594  return false;
1595  break;
1596 
1597  case PAD_ATTRIB_CONN:
1598  case PAD_ATTRIB_SMD:
1599  if( pad->IsOnLayer( F_Cu ) && !board()->IsElementVisible( LAYER_PAD_FR ) )
1600  return false;
1601  else if( pad->IsOnLayer( B_Cu ) && !board()->IsElementVisible( LAYER_PAD_BK ) )
1602  return false;
1603  break;
1604  }
1605 
1606  // Otherwise, pads are selectable if any draw layer is visible
1607 
1608  // Shortcut: check copper layer visibility
1609  if( board()->IsLayerVisible( F_Cu ) && pad->IsOnLayer( F_Cu ) )
1610  return true;
1611 
1612  if( board()->IsLayerVisible( B_Cu ) && pad->IsOnLayer( B_Cu ) )
1613  return true;
1614 
1615  // Now check the non-copper layers
1616 
1617  bool draw_layer_visible = false;
1618 
1619  int pad_layers[KIGFX::VIEW::VIEW_MAX_LAYERS], pad_layers_count;
1620  pad->ViewGetLayers( pad_layers, pad_layers_count );
1621 
1622  for( int i = 0; i < pad_layers_count; ++i )
1623  {
1624  // NOTE: Only checking the regular layers (not GAL meta-layers)
1625  if( ( ( pad_layers[i] < PCB_LAYER_ID_COUNT ) &&
1626  board()->IsLayerVisible( static_cast<PCB_LAYER_ID>( pad_layers[i] ) ) ) )
1627  {
1628  draw_layer_visible = true;
1629  }
1630  }
1631 
1632  return draw_layer_visible;
1633  }
1634 
1635  break;
1636  }
1637 
1638 
1639  case PCB_MARKER_T: // Always selectable
1640  return true;
1641 
1642  // These are not selectable
1643  case NOT_USED:
1644  case TYPE_NOT_INIT:
1645  return false;
1646 
1647  default: // Suppress warnings
1648  break;
1649  }
1650 
1651  // All other items are selected only if the layer on which they exist is visible
1652  return board()->IsLayerVisible( aItem->GetLayer() );
1653 }
1654 
1655 
1657 {
1658  if( aItem->IsSelected() )
1659  {
1660  return;
1661  }
1662 
1663  if( aItem->Type() == PCB_PAD_T )
1664  {
1665  MODULE* module = static_cast<MODULE*>( aItem->GetParent() );
1666 
1667  if( m_selection.Contains( module ) )
1668  return;
1669  }
1670 
1671  highlight( aItem, SELECTED, &m_selection );
1672 }
1673 
1674 
1676 {
1677  unhighlight( aItem, SELECTED, &m_selection );
1678 
1679  if( m_selection.Empty() )
1680  m_locked = true;
1681 }
1682 
1683 
1684 void SELECTION_TOOL::highlight( BOARD_ITEM* aItem, int aMode, PCBNEW_SELECTION* aGroup )
1685 {
1686  if( aMode == SELECTED )
1687  aItem->SetSelected();
1688  else if( aMode == BRIGHTENED )
1689  aItem->SetBrightened();
1690 
1691  if( aGroup )
1692  {
1693  // Hide the original item, so it is shown only on overlay
1694  view()->Hide( aItem, true );
1695 
1696  aGroup->Add( aItem );
1697  }
1698 
1699  // Modules are treated in a special way - when they are highlighted, we have to
1700  // highlight all the parts that make the module, not the module itself
1701  if( aItem->Type() == PCB_MODULE_T )
1702  {
1703  static_cast<MODULE*>( aItem )->RunOnChildren( [&] ( BOARD_ITEM* item )
1704  {
1705  if( aMode == SELECTED )
1706  item->SetSelected();
1707  else if( aMode == BRIGHTENED )
1708  {
1709  item->SetBrightened();
1710 
1711  if( aGroup )
1712  aGroup->Add( item );
1713  }
1714 
1715  if( aGroup )
1716  view()->Hide( item, true );
1717  });
1718  }
1719 
1720  view()->Update( aItem );
1721 
1722  // Many selections are very temporal and updating the display each time just
1723  // creates noise.
1724  if( aMode == BRIGHTENED )
1726 }
1727 
1728 
1729 void SELECTION_TOOL::unhighlight( BOARD_ITEM* aItem, int aMode, PCBNEW_SELECTION* aGroup )
1730 {
1731  if( aMode == SELECTED )
1732  aItem->ClearSelected();
1733  else if( aMode == BRIGHTENED )
1734  aItem->ClearBrightened();
1735 
1736  if( aGroup )
1737  {
1738  aGroup->Remove( aItem );
1739 
1740  // Restore original item visibility
1741  view()->Hide( aItem, false );
1742  }
1743 
1744  // Modules are treated in a special way - when they are highlighted, we have to
1745  // highlight all the parts that make the module, not the module itself
1746  if( aItem->Type() == PCB_MODULE_T )
1747  {
1748  static_cast<MODULE*>( aItem )->RunOnChildren( [&] ( BOARD_ITEM* item )
1749  {
1750  if( aMode == SELECTED )
1751  item->ClearSelected();
1752  else if( aMode == BRIGHTENED )
1753  item->ClearBrightened();
1754 
1755  // N.B. if we clear the selection flag for sub-elements, we need to also
1756  // remove the element from the selection group (if it exists)
1757  if( aGroup )
1758  {
1759  aGroup->Remove( item );
1760 
1761  view()->Hide( item, false );
1762  view()->Update( item );
1763  }
1764  });
1765  }
1766 
1767  view()->Update( aItem );
1768 
1769  // Many selections are very temporal and updating the display each time just
1770  // creates noise.
1771  if( aMode == BRIGHTENED )
1773 }
1774 
1775 
1776 bool SELECTION_TOOL::selectionContains( const VECTOR2I& aPoint ) const
1777 {
1778  const unsigned GRIP_MARGIN = 20;
1779  VECTOR2I margin = getView()->ToWorld( VECTOR2I( GRIP_MARGIN, GRIP_MARGIN ), false );
1780 
1781  // Check if the point is located within any of the currently selected items bounding boxes
1782  for( auto item : m_selection )
1783  {
1784  BOX2I itemBox = item->ViewBBox();
1785  itemBox.Inflate( margin.x, margin.y ); // Give some margin for gripping an item
1786 
1787  if( itemBox.Contains( aPoint ) )
1788  return true;
1789  }
1790 
1791  return false;
1792 }
1793 
1794 
1795 static EDA_RECT getRect( const BOARD_ITEM* aItem )
1796 {
1797  if( aItem->Type() == PCB_MODULE_T )
1798  return static_cast<const MODULE*>( aItem )->GetFootprintRect();
1799 
1800  return aItem->GetBoundingBox();
1801 }
1802 
1803 
1804 static double calcArea( const BOARD_ITEM* aItem )
1805 {
1806  if( aItem->Type() == PCB_TRACE_T )
1807  {
1808  const TRACK* t = static_cast<const TRACK*>( aItem );
1809  return ( t->GetWidth() + t->GetLength() ) * t->GetWidth();
1810  }
1811 
1812  return getRect( aItem ).GetArea();
1813 }
1814 
1815 
1816 /*static double calcMinArea( GENERAL_COLLECTOR& aCollector, KICAD_T aType )
1817 {
1818  double best = std::numeric_limits<double>::max();
1819 
1820  if( !aCollector.GetCount() )
1821  return 0.0;
1822 
1823  for( int i = 0; i < aCollector.GetCount(); i++ )
1824  {
1825  BOARD_ITEM* item = aCollector[i];
1826  if( item->Type() == aType )
1827  best = std::min( best, calcArea( item ) );
1828  }
1829 
1830  return best;
1831 }*/
1832 
1833 
1834 static double calcMaxArea( GENERAL_COLLECTOR& aCollector, KICAD_T aType )
1835 {
1836  double best = 0.0;
1837 
1838  for( int i = 0; i < aCollector.GetCount(); i++ )
1839  {
1840  BOARD_ITEM* item = aCollector[i];
1841  if( item->Type() == aType )
1842  best = std::max( best, calcArea( item ) );
1843  }
1844 
1845  return best;
1846 }
1847 
1848 
1849 static inline double calcCommonArea( const BOARD_ITEM* aItem, const BOARD_ITEM* aOther )
1850 {
1851  if( !aItem || !aOther )
1852  return 0;
1853 
1854  return getRect( aItem ).Common( getRect( aOther ) ).GetArea();
1855 }
1856 
1857 
1858 double calcRatio( double a, double b )
1859 {
1860  if( a == 0.0 && b == 0.0 )
1861  return 1.0;
1862 
1863  if( b == 0.0 )
1865 
1866  return a / b;
1867 }
1868 
1869 
1870 // The general idea here is that if the user clicks directly on a small item inside a larger
1871 // one, then they want the small item. The quintessential case of this is clicking on a pad
1872 // within a footprint, but we also apply it for text within a footprint, footprints within
1873 // larger footprints, and vias within either larger pads or longer tracks.
1874 //
1875 // These "guesses" presume there is area within the larger item to click in to select it. If
1876 // an item is mostly covered by smaller items within it, then the guesses are inappropriate as
1877 // there might not be any area left to click to select the larger item. In this case we must
1878 // leave the items in the collector and bring up a Selection Clarification menu.
1879 //
1880 // We currently check for pads and text mostly covering a footprint, but we don’t check for
1881 // smaller footprints mostly covering a larger footprint.
1882 //
1884  const VECTOR2I& aWhere ) const
1885 {
1886  std::set<BOARD_ITEM*> preferred;
1887  std::set<BOARD_ITEM*> rejected;
1888  std::set<BOARD_ITEM*> forced;
1889  wxPoint where( aWhere.x, aWhere.y );
1890 
1891  // footprints which are below this percentage of the largest footprint will be considered
1892  // for selection; all others will not
1893  constexpr double footprintToFootprintMinRatio = 0.20;
1894  // pads which are below this percentage of their parent's area will exclude their parent
1895  constexpr double padToFootprintMinRatio = 0.45;
1896  // footprints containing items with items-to-footprint area ratio higher than this will be
1897  // forced to stay on the list
1898  constexpr double footprintMaxCoverRatio = 0.80;
1899  constexpr double viaToPadMinRatio = 0.50;
1900  constexpr double trackViaLengthRatio = 2.0;
1901  constexpr double trackTrackLengthRatio = 0.3;
1902  constexpr double textToFeatureMinRatio = 0.2;
1903  constexpr double textToFootprintMinRatio = 0.4;
1904  // If the common area of two compared items is above the following threshold, they cannot
1905  // be rejected (it means they overlap and it might be hard to pick one by selecting
1906  // its unique area).
1907  constexpr double commonAreaRatio = 0.6;
1908 
1909  PCB_LAYER_ID activeLayer = (PCB_LAYER_ID) view()->GetTopLayer();
1910  LSET silkLayers( 2, B_SilkS, F_SilkS );
1911 
1912  if( silkLayers[activeLayer] )
1913  {
1914  for( int i = 0; i < aCollector.GetCount(); ++i )
1915  {
1916  BOARD_ITEM* item = aCollector[i];
1917  KICAD_T type = item->Type();
1918 
1919  if( ( type == PCB_MODULE_TEXT_T || type == PCB_TEXT_T || type == PCB_LINE_T )
1920  && silkLayers[item->GetLayer()] )
1921  {
1922  preferred.insert( item );
1923  }
1924  }
1925 
1926  if( preferred.size() > 0 )
1927  {
1928  aCollector.Empty();
1929 
1930  for( BOARD_ITEM* item : preferred )
1931  aCollector.Append( item );
1932  return;
1933  }
1934  }
1935 
1936  int numZones = aCollector.CountType( PCB_ZONE_AREA_T );
1937 
1938  // Zone edges are very specific; zone fills much less so.
1939  if( numZones > 0 )
1940  {
1941  for( int i = aCollector.GetCount() - 1; i >= 0; i-- )
1942  {
1943  if( aCollector[i]->Type() == PCB_ZONE_AREA_T )
1944  {
1945  auto zone = static_cast<ZONE_CONTAINER*>( aCollector[i] );
1946 
1947  if( zone->HitTestForEdge( where, 5 * aCollector.GetGuide()->OnePixelInIU() ) )
1948  preferred.insert( zone );
1949  else
1950  rejected.insert( zone );
1951  }
1952  }
1953 
1954  if( preferred.size() > 0 )
1955  {
1956  aCollector.Empty();
1957 
1958  for( BOARD_ITEM* item : preferred )
1959  aCollector.Append( item );
1960  return;
1961  }
1962  }
1963 
1964  if( aCollector.CountType( PCB_MODULE_TEXT_T ) > 0 )
1965  {
1966  for( int i = 0; i < aCollector.GetCount(); ++i )
1967  {
1968  if( TEXTE_MODULE* txt = dyn_cast<TEXTE_MODULE*>( aCollector[i] ) )
1969  {
1970  double textArea = calcArea( txt );
1971 
1972  for( int j = 0; j < aCollector.GetCount(); ++j )
1973  {
1974  if( i == j )
1975  continue;
1976 
1977  BOARD_ITEM* item = aCollector[j];
1978  double itemArea = calcArea( item );
1979  double areaRatio = calcRatio( textArea, itemArea );
1980  double commonArea = calcCommonArea( txt, item );
1981  double itemCommonRatio = calcRatio( commonArea, itemArea );
1982  double txtCommonRatio = calcRatio( commonArea, textArea );
1983 
1984  if( item->Type() == PCB_MODULE_T )
1985  {
1986  // when text area is small compared to an overlapping footprint,
1987  // then it's a clear sign the text is the selection target
1988  if( areaRatio < textToFootprintMinRatio && itemCommonRatio < commonAreaRatio )
1989  rejected.insert( item );
1990  }
1991 
1992  switch( item->Type() )
1993  {
1994  case PCB_TRACE_T:
1995  case PCB_PAD_T:
1996  case PCB_LINE_T:
1997  case PCB_VIA_T:
1998  case PCB_MODULE_T:
1999  if( areaRatio > textToFeatureMinRatio && txtCommonRatio < commonAreaRatio )
2000  rejected.insert( txt );
2001  break;
2002  default:
2003  break;
2004  }
2005  }
2006  }
2007  }
2008  }
2009 
2010  if( aCollector.CountType( PCB_PAD_T ) > 0 )
2011  {
2012  for( int i = 0; i < aCollector.GetCount(); ++i )
2013  {
2014  if( D_PAD* pad = dyn_cast<D_PAD*>( aCollector[i] ) )
2015  {
2016  MODULE* parent = pad->GetParent();
2017  double ratio = calcRatio( calcArea( pad ), calcArea( parent ) );
2018 
2019  // when pad area is small compared to the parent footprint,
2020  // then it is a clear sign the pad is the selection target
2021  if( ratio < padToFootprintMinRatio )
2022  rejected.insert( pad->GetParent() );
2023  }
2024  }
2025  }
2026 
2027  int moduleCount = aCollector.CountType( PCB_MODULE_T );
2028 
2029  if( moduleCount > 0 )
2030  {
2031  double maxArea = calcMaxArea( aCollector, PCB_MODULE_T );
2032  BOX2D viewportD = getView()->GetViewport();
2033  BOX2I viewport( VECTOR2I( viewportD.GetPosition() ), VECTOR2I( viewportD.GetSize() ) );
2034  double maxCoverRatio = footprintMaxCoverRatio;
2035 
2036  // MODULE::CoverageRatio() doesn't take zone handles & borders into account so just
2037  // use a more aggressive cutoff point if zones are involved.
2038  if( aCollector.CountType( PCB_ZONE_AREA_T ) )
2039  maxCoverRatio /= 2;
2040 
2041  for( int i = 0; i < aCollector.GetCount(); ++i )
2042  {
2043  if( MODULE* mod = dyn_cast<MODULE*>( aCollector[i] ) )
2044  {
2045  // filter out components larger than the viewport
2046  if( mod->ViewBBox().Contains( viewport ) )
2047  rejected.insert( mod );
2048  // footprints completely covered with other features have no other
2049  // means of selection, so must be kept
2050  else if( mod->CoverageRatio( aCollector ) > maxCoverRatio )
2051  rejected.erase( mod );
2052  // if a footprint is much smaller than the largest overlapping
2053  // footprint then it should be considered for selection
2054  else if( calcRatio( calcArea( mod ), maxArea ) <= footprintToFootprintMinRatio )
2055  continue;
2056  // if there are multiple footprints for selection at this point, prefer
2057  // one that is on the active layer
2058  else if( moduleCount > 1 && mod->GetLayer() == activeLayer )
2059  preferred.insert( mod );
2060  // reject ALL OTHER footprints if there's still something else left
2061  // to select
2062  else if( (int)( rejected.size() + 1 ) < aCollector.GetCount() )
2063  rejected.insert( mod );
2064  }
2065  }
2066  }
2067 
2068  if( aCollector.CountType( PCB_VIA_T ) > 0 )
2069  {
2070  for( int i = 0; i < aCollector.GetCount(); ++i )
2071  {
2072  if( VIA* via = dyn_cast<VIA*>( aCollector[i] ) )
2073  {
2074  double viaArea = calcArea( via );
2075 
2076  for( int j = 0; j < aCollector.GetCount(); ++j )
2077  {
2078  if( i == j )
2079  continue;
2080 
2081  BOARD_ITEM* item = aCollector[j];
2082  double areaRatio = calcRatio( viaArea, calcArea( item ) );
2083 
2084  if( item->Type() == PCB_MODULE_T && areaRatio < padToFootprintMinRatio )
2085  rejected.insert( item );
2086 
2087  if( item->Type() == PCB_PAD_T && areaRatio < viaToPadMinRatio )
2088  rejected.insert( item );
2089 
2090  if( TRACK* track = dyn_cast<TRACK*>( item ) )
2091  {
2092  if( track->GetNetCode() != via->GetNetCode() )
2093  continue;
2094 
2095  double lenRatio = (double) ( track->GetLength() + track->GetWidth() ) /
2096  (double) via->GetWidth();
2097 
2098  if( lenRatio > trackViaLengthRatio )
2099  rejected.insert( track );
2100  }
2101  }
2102  }
2103  }
2104  }
2105 
2106  int nTracks = aCollector.CountType( PCB_TRACE_T );
2107 
2108  if( nTracks > 0 )
2109  {
2110  double maxLength = 0.0;
2111  double minLength = std::numeric_limits<double>::max();
2112  double maxArea = 0.0;
2113  const TRACK* maxTrack = nullptr;
2114 
2115  for( int i = 0; i < aCollector.GetCount(); ++i )
2116  {
2117  if( TRACK* track = dyn_cast<TRACK*>( aCollector[i] ) )
2118  {
2119  maxLength = std::max( track->GetLength(), maxLength );
2120  maxLength = std::max( (double) track->GetWidth(), maxLength );
2121 
2122  minLength = std::min( std::max( track->GetLength(), (double) track->GetWidth() ), minLength );
2123 
2124  double area = track->GetLength() * track->GetWidth();
2125 
2126  if( area > maxArea )
2127  {
2128  maxArea = area;
2129  maxTrack = track;
2130  }
2131  }
2132  }
2133 
2134  if( maxLength > 0.0 && minLength / maxLength < trackTrackLengthRatio && nTracks > 1 )
2135  {
2136  for( int i = 0; i < aCollector.GetCount(); ++i )
2137  {
2138  if( TRACK* track = dyn_cast<TRACK*>( aCollector[i] ) )
2139  {
2140  double ratio = std::max( (double) track->GetWidth(), track->GetLength() ) / maxLength;
2141 
2142  if( ratio > trackTrackLengthRatio )
2143  rejected.insert( track );
2144  }
2145  }
2146  }
2147 
2148  for( int j = 0; j < aCollector.GetCount(); ++j )
2149  {
2150  if( MODULE* mod = dyn_cast<MODULE*>( aCollector[j] ) )
2151  {
2152  double ratio = calcRatio( maxArea, mod->GetFootprintRect().GetArea() );
2153 
2154  if( ratio < padToFootprintMinRatio && calcCommonArea( maxTrack, mod ) < commonAreaRatio )
2155  rejected.insert( mod );
2156  }
2157  }
2158  }
2159 
2160  if( (unsigned) aCollector.GetCount() > rejected.size() ) // do not remove everything
2161  {
2162  for( BOARD_ITEM* item : rejected )
2163  {
2164  aCollector.Remove( item );
2165  }
2166  }
2167 }
2168 
2169 
2171 {
2172  getView()->Update( &m_selection );
2173 
2174  return 0;
2175 }
2176 
2177 
2179 {
2180  ACTION_MENU* actionMenu = aEvent.Parameter<ACTION_MENU*>();
2181  CONDITIONAL_MENU* conditionalMenu = dynamic_cast<CONDITIONAL_MENU*>( actionMenu );
2182 
2183  if( conditionalMenu )
2184  conditionalMenu->Evaluate( m_selection );
2185 
2186  if( actionMenu )
2187  actionMenu->UpdateAll();
2188 
2189  return 0;
2190 }
2191 
2192 
2194 {
2196 
2200 
2206 
2207  Go( &SELECTION_TOOL::find, ACTIONS::find.MakeEvent() );
2208 
2217 }
2218 
2219 
static TOOL_ACTION selectItems
Selects a list of items (specified as the event parameter)
Definition: pcb_actions.h:80
void Empty()
Function Empty sets the list to empty.
Definition: collector.h:122
static TOOL_ACTION selectionClear
Clears the current selection.
Definition: pcb_actions.h:73
static TOOL_ACTION selectionActivate
Activation of the selection tool.
Definition: pcb_actions.h:67
void GuessSelectionCandidates(GENERAL_COLLECTOR &aCollector, const VECTOR2I &aWhere) const
Function guessSelectionCandidates() Tries to guess best selection candidates in case multiple items a...
void Hide(VIEW_ITEM *aItem, bool aHide=true)
Temporarily hides the item in the view (e.g.
Definition: view.cpp:1507
void AddMenu(ACTION_MENU *aMenu, const SELECTION_CONDITION &aCondition=SELECTION_CONDITIONS::ShowAlways, int aOrder=ANY_ORDER)
Function AddMenu()
void ClearReferencePoint()
Definition: selection.h:248
int UnselectItem(const TOOL_EVENT &aEvent)
Item unselection event handler.
int Main(const TOOL_EVENT &aEvent)
Function Main()
int UpdateMenu(const TOOL_EVENT &aEvent)
Pass the selection to a conditional menu for updating.
OPT< int > GetCommandId() const
Definition: tool_event.h:450
void AddStandardSubMenus(TOOL_MENU &aMenu)
Function CreateBasicMenu.
void SetIgnoreTracks(bool ignore)
Definition: collectors.h:607
wxMenuItem * Add(const wxString &aLabel, int aId, const BITMAP_OPAQUE *aIcon)
Function Add() Adds a wxWidgets-style entry to the menu.
void connectedTrackFilter(const VECTOR2I &aPt, GENERAL_COLLECTOR &aCollector)
to draw blind/buried vias
void Reset(RESET_REASON aReason) override
Function Reset() Brings the tool to a known, initial state.
static const TOOL_EVENT SelectedEvent
Definition: actions.h:197
BOX2D GetViewport() const
Function GetViewport() Returns the current viewport visible area rectangle.
Definition: view.cpp:538
void SetEnd(VECTOR2I aEnd)
Set the current end of the rectangle (the corner that moves with the cursor.
TOOL_MENU m_menu
functions below are not yet implemented - their interface may change
static EDA_RECT getRect(const BOARD_ITEM *aItem)
virtual void Clear() override
Function Clear() Removes all the stored items from the group.
Definition: selection.h:93
void ForceRefresh()
Function ForceRefresh() Forces a redraw.
int GetNetCode() const
Function GetNetCode.
static double calcCommonArea(const BOARD_ITEM *aItem, const BOARD_ITEM *aOther)
std::function< SEARCH_RESULT(EDA_ITEM *aItem, void *aTestData) > INSPECTOR_FUNC
Typedef INSPECTOR is used to inspect and possibly collect the (search) results of iterating over a li...
Definition: base_struct.h:83
static const KICAD_T AllBoardItems[]
A scan list for all editable board items.
Definition: collectors.h:267
void SetIgnoreBlindBuriedVias(bool ignore)
Definition: collectors.h:601
static const KICAD_T Tracks[]
A scan list for only TRACKS.
Definition: collectors.h:313
TOOL_EVENT * Wait(const TOOL_EVENT_LIST &aEventList=TOOL_EVENT(TC_ANY, TA_ANY))
Function Wait()
virtual LSET GetLayerSet() const override
Function GetLayerSet returns a "layer mask", which is a bitmap of all layers on which the TRACK segme...
BOARD * board() const
std::unique_ptr< PRIV > m_priv
like PAD_STANDARD, but not plated mechanical use only, no connection allowed
Definition: pad_shapes.h:66
bool IsSelected() const
Definition: base_struct.h:233
Model changes (required full reload)
Definition: tool_base.h:82
multilayer pads, usually with holes
static const TOOL_EVENT UnselectedEvent
Definition: actions.h:198
int selectSameSheet(const TOOL_EVENT &aEvent)
Selects all modules belonging to same hierarchical sheet as the selected footprint.
virtual void Update(VIEW_ITEM *aItem, int aUpdateFlags) override
For dynamic VIEWs, informs the associated VIEW that the graphical representation of this item has cha...
Definition: pcb_view.cpp:91
Class ACTION_MENU.
Definition: action_menu.h:43
This file is part of the common library.
Class BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class,...
bool HasType(KICAD_T aType) const
Checks if there is at least one item of requested kind.
Definition: selection.h:212
VECTOR2D ToWorld(const VECTOR2D &aCoord, bool aAbsolute=true) const
Function ToWorld() Converts a screen space point/vector to a point/vector in world space coordinates.
Definition: view.cpp:475
void SetOrigin(VECTOR2I aOrigin)
Set the origin of the rectange (the fixed corner)
void ClearSelected()
Definition: base_struct.h:243
void SetCurrentCursor(wxStockCursor aStockCursorID)
Function SetCurrentCursor Set the current cursor shape for this panel.
VIEW_CONTROLS class definition.
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:474
Classes BOARD_ITEM and BOARD_CONNECTED_ITEM.
virtual double OnePixelInIU() const =0
void SetIgnoreModulesVals(bool ignore)
Definition: collectors.h:589
void SetIgnoreMicroVias(bool ignore)
Definition: collectors.h:604
Class SELECTION_TOOL.
void SetIgnoreModulesOnBack(bool ignore)
Definition: collectors.h:559
SELECTION_LOCK_FLAGS CheckLock()
Checks if the user has agreed to modify locked items for the given selection.
static TOOL_ACTION unselectItem
Definition: pcb_actions.h:77
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
CONDITIONAL_MENU & GetMenu()
Function GetMenu.
Definition: tool_menu.cpp:46
the 3d code uses this value
Definition: typeinfo.h:80
static TOOL_ACTION selectNet
Selects all connections belonging to a single net.
Definition: pcb_actions.h:96
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:219
ITER end()
Definition: selection.h:60
static TOOL_ACTION unselectItems
Definition: pcb_actions.h:81
const GENERAL_COLLECTORS_GUIDE getCollectorsGuide() const
int find(const TOOL_EVENT &aEvent)
Find an item.
Smd pad, appears on the solder paste layer (default)
Definition: pad_shapes.h:62
class ZONE_CONTAINER, a zone area
Definition: typeinfo.h:100
virtual void Remove(VIEW_ITEM *aItem)
Function Remove() Removes a VIEW_ITEM from the view.
Definition: view.cpp:376
static TOOL_ACTION properties
Activation of the edit tool.
Definition: pcb_actions.h:122
virtual void ViewGetLayers(int aLayers[], int &aCount) const override
Function ViewGetLayers() Returns the all the layers within the VIEW the object is painted on.
ITER begin()
Definition: collector.h:91
int GetWidth() const
Definition: eda_rect.h:119
int UnselectItems(const TOOL_EVENT &aEvent)
Multiple item unselection event handler
PADS & Pads()
Definition: class_module.h:165
void SetBrightened()
Definition: base_struct.h:241
PCBNEW_SELECTION m_selection
class TEXTE_PCB, text on a layer
Definition: typeinfo.h:92
void SetIgnoreModulesRefs(bool ignore)
Definition: collectors.h:595
LSET GetVisibleLayers() const
Function GetVisibleLayers is a proxy function that calls the correspondent function in m_BoardSetting...
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Function RunAction() Runs the specified action.
Definition: tool_manager.h:109
static TOOL_ACTION selectionMenu
Runs a selection menu to select from a list of items.
Definition: pcb_actions.h:84
static TOOL_ACTION selectConnection
Selects a connection between junctions.
Definition: pcb_actions.h:87
Class that groups generic conditions for selected items.
void SetExclusiveOr(bool aExclusiveOr)
show modules values (when texts are visibles)
Template specialization to enable wxStrings for certain containers (e.g. unordered_map)
EDA_RECT GetFootprintRect() const
Function GetFootprintRect() Returns the area of the module footprint excluding any text.
ITER end()
Definition: collector.h:92
EDA_RECT Common(const EDA_RECT &aRect) const
Function Common returns the area that is common with another rectangle.
class D_PAD, a pad in a footprint
Definition: typeinfo.h:90
#define BUSY
Pcbnew: flag indicating that the structure has.
Definition: base_struct.h:140
void UpdateAll()
Function UpdateAll() Runs update handlers for the menu and its submenus.
DRAWINGS & GraphicalItems()
Definition: class_module.h:175
const COLLECTORS_GUIDE * GetGuide()
Definition: collectors.h:347
void SetContextMenu(ACTION_MENU *aMenu, CONTEXT_MENU_TRIGGER aTrigger=CMENU_BUTTON)
Function SetContextMenu()
static TOOL_ACTION find
Definition: actions.h:78
void(* CLIENT_SELECTION_FILTER)(const VECTOR2I &, GENERAL_COLLECTOR &)
VECTOR2< int > VECTOR2I
Definition: vector2d.h:587
int CountType(KICAD_T aType)
Function CountType counts the number of items matching aType.
Definition: collector.h:264
bool selectionContains(const VECTOR2I &aPoint) const
Function selectionContains()
static double calcArea(const BOARD_ITEM *aItem)
Class BOARD_CONNECTED_ITEM is a base class derived from BOARD_ITEM for items that can be connected an...
static bool NotEmpty(const SELECTION &aSelection)
Function NotEmpty Tests if there are any items selected.
int selectConnection(const TOOL_EVENT &aEvent)
Selects a trivial connection (between two junctions) of items in selection
void Go(int(T::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
Function Go()
void select(BOARD_ITEM *aItem)
Function select() Takes necessary action mark an item as selected.
class EDGE_MODULE, a footprint edge
Definition: typeinfo.h:94
void Remove(int aIndex)
Function Remove removes the item at aIndex (first position is 0);.
Definition: collector.h:142
virtual void Remove(VIEW_ITEM *aItem) override
Function Remove() Removes a VIEW_ITEM from the view.
Definition: pcb_view.cpp:74
search types array terminator (End Of Types)
Definition: typeinfo.h:82
KICAD_T
Enum KICAD_T is the set of class identification values, stored in EDA_ITEM::m_StructType.
Definition: typeinfo.h:78
static const TOOL_EVENT SelectedItemsModified
Definition: actions.h:201
PAINTER * GetPainter() const
Function GetPainter() Returns the painter object used by the view for drawing VIEW_ITEMS.
Definition: view.h:199
static constexpr int VIEW_MAX_LAYERS
maximum number of layers that may be shown
Definition: view.h:701
Definitions for tracks, vias and zones.
class TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:95
void * GetDisplayOptions() override
Function GetDisplayOptions returns the display options current in use Display options are relative to...
double GetLength() const
Function GetLength returns the length of the track using the hypotenuse calculation.
Definition: class_track.h:149
void SetIsHover(bool aIsHover)
Definition: selection.h:64
BOARD_ITEM * pickSmallestComponent(GENERAL_COLLECTOR *aCollector)
Function pickSmallestComponent() Allows one to find the smallest (in terms of bounding box area) item...
Private implementation of firewalled private data.
virtual void Add(EDA_ITEM *aItem)
Definition: selection.h:74
void highlight(BOARD_ITEM *aItem, int aHighlightMode, PCBNEW_SELECTION *aGroup=nullptr)
Function highlight() Highlights the item visually.
PCBNEW_SELECTION & GetSelection()
Function GetSelection()
void ClearBrightened()
Definition: base_struct.h:245
void Append(EDA_ITEM *item)
Function Append adds an item to the end of the list.
Definition: collector.h:132
void SetAdditive(bool aAdditive)
show modules on front
PCB_BASE_EDIT_FRAME * frame() const
virtual bool HitTest(const wxPoint &aPosition, int aAccuracy=0) const
Function HitTest tests if aPosition is contained within or on the bounding box of an item.
Definition: base_struct.h:340
void findCallback(BOARD_ITEM *aItem)
Find dialog callback.
SEARCH_RESULT Visit(INSPECTOR inspector, void *testData, const KICAD_T scanTypes[]) override
Function Visit may be re-implemented for each derived class in order to handle all the types given by...
int GetCount() const
Function GetCount returns the number of objects in the list.
Definition: collector.h:113
int selectCopper(const TOOL_EVENT &aEvent)
Selects items with a continuous copper connection to items in selection
int filterSelection(const TOOL_EVENT &aEvent)
Invoke filter dialog and modify current selection
#define SELECTED
Definition: base_struct.h:127
int expandConnection(const TOOL_EVENT &aEvent)
Expands the current selection to select a connection between two junctions
Struct that will be set with the result of the user choices in the dialog.
ITER begin()
Definition: selection.h:59
class MODULE, a footprint
Definition: typeinfo.h:89
bool selectPoint(const VECTOR2I &aWhere, bool aOnDrag=false, bool *aSelectionCancelledFlag=NULL, CLIENT_SELECTION_FILTER aClientFilter=NULL)
Function selectPoint() Selects an item pointed by the parameter aWhere.
bool selectCursor(bool aForceSelect=false, CLIENT_SELECTION_FILTER aClientFilter=NULL)
Function selectCursor() Selects an item under the cursor unless there is something already selected o...
Class PCB_DISPLAY_OPTIONS handles display options like enable/disable some optional drawings.
PCB_LAYER_ID
A quick note on layer IDs:
void UnbrightenItem(BOARD_ITEM *aItem)
Class LSET is a set of PCB_LAYER_IDs.
const PCBNEW_SELECTION & selection() const
void SetCenter(const VECTOR2D &aCenter)
Function SetCenter() Sets the center point of the VIEW (i.e.
Definition: view.cpp:604
static double calcMaxArea(GENERAL_COLLECTOR &aCollector, KICAD_T aType)
void selectAllItemsOnSheet(wxString &aSheetpath)
Selects all items with the given sheet timestamp name (the sheet path)
void SetSelected()
Definition: base_struct.h:239
void SetIgnoreMTextsOnBack(bool ignore)
Definition: collectors.h:547
int updateSelection(const TOOL_EVENT &aEvent)
Event handler to update the selection VIEW_ITEM.
void SetHighlight(bool aEnabled, int aNetcode=-1, bool aHighlightItems=false)
Function SetHighlight Turns on/off highlighting - it may be done for the active layer,...
Definition: painter.h:141
void SetIgnorePadsOnFront(bool ignore)
Definition: collectors.h:577
int ClearSelection(const TOOL_EVENT &aEvent)
Clear current selection event handler.
void MarkTargetDirty(int aTarget)
Function MarkTargetDirty() Sets or clears target 'dirty' flag.
Definition: view.h:585
bool selectMultiple()
Function selectMultiple() Handles drawing a selection box that allows one to select many items at the...
void selectAllItemsOnNet(int aNetCode)
Selects all items with the given net code.
bool ProcessEvent(const TOOL_EVENT &aEvent)
Propagates an event to tools that requested events of matching type(s).
bool IsVisible(const VIEW_ITEM *aItem) const
Returns information if the item is visible (or not).
Definition: view.cpp:1526
void SetIgnoreMTextsOnFront(bool ignore)
Definition: collectors.h:553
void connectedItemFilter(const VECTOR2I &, GENERAL_COLLECTOR &aCollector)
SELECTION_LOCK_FLAGS
Definition: selection.h:263
T Parameter() const
Function Parameter() Returns a non-standard parameter assigned to the event.
Definition: tool_event.h:427
virtual int GetTopLayer() const
Definition: view.cpp:851
void SetIcon(const BITMAP_OPAQUE *aIcon)
Function SetIcon() Assigns an icon for the entry.
Definition: action_menu.cpp:68
bool Contains(const Vec &aPoint) const
Function Contains.
Definition: box2.h:149
to draw usual through hole vias
Class TOOL_EVENT.
Definition: tool_event.h:168
void AddItemToSel(BOARD_ITEM *aItem, bool aQuietMode=false)
bool Contains(EDA_ITEM *aItem) const
Definition: selection.h:111
const BOX2I ViewBBox() const override
Function ViewBBox() returns the bounding box of the item covering all its layers.
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Function GetConnectivity() returns list of missing connections between components/tracks.
Definition: class_board.h:310
const std::deque< EDA_ITEM * > GetItems() const
Definition: selection.h:130
KIGFX::PCB_VIEW * view() const
#define BRIGHTENED
item is drawn with a bright contour
Definition: base_struct.h:143
VIATYPE_T GetViaType() const
Definition: class_track.h:346
bool Init() override
Function Init() Init() is called once upon a registration of the tool.
EDA_ITEM * GetParent() const
Definition: base_struct.h:220
PCB_BASE_FRAME * m_frame
Items that may change while the view stays the same (noncached)
Definition: definitions.h:50
static const TOOL_EVENT ClearedEvent
Definition: actions.h:199
int SelectionMenu(const TOOL_EVENT &aEvent)
Function SelectionMenu() Shows a popup menu to trim the COLLECTOR passed as aEvent's parameter down t...
double GetArea() const
Function GetArea returns the area of the rectangle.
static TOOL_ACTION selectCopper
Selects whole copper connection.
Definition: pcb_actions.h:93
static TOOL_ACTION updateMenu
Definition: actions.h:158
int selectSheetContents(const TOOL_EVENT &aEvent)
Selects all modules belonging to same sheet, from Eeschema, using crossprobing
void SetIgnoreMTextsMarkedNoShow(bool ignore)
Definition: collectors.h:541
virtual void Update(VIEW_ITEM *aItem, int aUpdateFlags)
For dynamic VIEWs, informs the associated VIEW that the graphical representation of this item has cha...
Definition: view.cpp:1540
int SelectItem(const TOOL_EVENT &aEvent)
Item selection event handler.
static bool itemIsIncludedByFilter(const BOARD_ITEM &aItem, const BOARD &aBoard, const DIALOG_BLOCK_OPTIONS::OPTIONS &aBlockOpts)
Function itemIsIncludedByFilter()
Like smd, does not appear on the solder paste layer (default) note also has a special attribute in Ge...
Definition: pad_shapes.h:63
class DIMENSION, a dimension (graphic item)
Definition: typeinfo.h:98
#define _(s)
virtual void SetLayer(int aLayer)
Function SetLayer() Sets layer used to draw the group.
Definition: view_group.h:115
static TOOL_ACTION hideDynamicRatsnest
Definition: pcb_actions.h:418
int GetHeight() const
Definition: eda_rect.h:120
KIGFX::VIEW * getView() const
Function getView()
Definition: tool_base.cpp:36
virtual void SetAutoPan(bool aEnabled)
Function SetAutoPan Turns on/off auto panning (this feature is used when there is a tool active (eg.
int selectNet(const TOOL_EVENT &aEvent)
Selects all copper connections belonging to the same net(s) as the items in the selection.
bool Empty() const
Checks if there is anything selected.
Definition: selection.h:119
class PCB_TARGET, a target (graphic item)
Definition: typeinfo.h:99
virtual const wxPoint GetPosition() const =0
static TOOL_ACTION drag
Definition: pcb_actions.h:109
bool IsMirroredX() const
Function IsMirroredX() Returns true if view is flipped across the X axis.
Definition: view.h:230
static TOOL_ACTION expandSelectedConnection
Expands the current selection to select a connection between two junctions.
Definition: pcb_actions.h:90
static TOOL_ACTION clearHighlight
Definition: pcb_actions.h:405
void SetSubtractive(bool aSubtractive)
const Vec & GetPosition() const
Definition: box2.h:192
bool IsElementVisible(GAL_LAYER_ID aLayer) const
Function IsElementVisible tests whether a given element category is visible.
virtual unsigned int GetSize() const override
Function GetSize() Returns the number of stored items.
Definition: selection.h:98
virtual void SetScale(double aScale, VECTOR2D aAnchor={ 0, 0 })
Function SetScale() Sets the scaling factor, zooming around a given anchor point.
Definition: view.cpp:578
class TEXTE_MODULE, text in a footprint
Definition: typeinfo.h:93
static TOOL_ACTION filterSelection
Filters the items in the current selection (invokes dialog)
Definition: pcb_actions.h:105
void Normalize()
Function Normalize ensures that the height ant width are positive.
void SetCallback(boost::function< void(BOARD_ITEM *)> aCallback)
Definition: dialog_find.h:39
bool GetHighContrast() const
Function GetHighContrast Returns information about high contrast display mode.
Definition: painter.h:163
virtual RENDER_SETTINGS * GetSettings()=0
Function GetSettings Returns pointer to current settings that are going to be used when drawing items...
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Function Inflate inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:300
bool IsLayerVisible(PCB_LAYER_ID aLayer) const
Function IsLayerVisible is a proxy function that calls the correspondent function in m_BoardSettings ...
Definition: class_board.h:459
class MARKER_PCB, a marker used to show something
Definition: typeinfo.h:97
int GetId() const
Function GetId() Returns the unique id of the TOOL_ACTION object.
Definition: tool_action.h:100
const int scale
void FocusOnLocation(const wxPoint &aPos, bool aCenterView=false)
Useful to focus on a particular location, in find functions Move the graphic cursor (crosshair cursor...
void SetTitle(const wxString &aTitle) override
Function SetTitle() Sets title for the menu.
Definition: action_menu.cpp:86
smd pads, front layer
PCBNEW_SELECTION & RequestSelection(CLIENT_SELECTION_FILTER aClientFilter, std::vector< BOARD_ITEM * > *aFiltered=nullptr, bool aConfirmLockedItems=false)
Function RequestSelection()
int GetWidth() const
Definition: class_track.h:103
bool ToolStackIsEmpty()
bool IsType(FRAME_T aType) const
Class to handle a graphic segment.
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:205
EDA_UNITS_T GetUserUnits() const
Return the user units currently in use.
void selectAllItemsConnectedToTrack(TRACK &aSourceTrack)
Selects all items connected by copper tracks to the given TRACK This selects tracks and vias but stop...
static TOOL_ACTION selectOnSheetFromEeschema
Selects all components on sheet from Eeschema crossprobing.
Definition: pcb_actions.h:99
#define max(a, b)
Definition: auxiliary.h:86
Class BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:161
MODULE * module() const
static const KICAD_T ModuleItems[]
A scan list for primary module items.
Definition: collectors.h:308
bool Selectable(const BOARD_ITEM *aItem, bool checkVisibilityOnly=false) const
Function selectable() Checks conditions for an item to be selected.
void SetIgnoreModulesOnFront(bool ignore)
Definition: collectors.h:565
Used when the right click button is pressed, or when the select tool is in effect.
Definition: collectors.h:240
void SetIgnoreThroughVias(bool ignore)
Definition: collectors.h:598
void AddSubMenu(std::shared_ptr< ACTION_MENU > aSubMenu)
Function CreateSubMenu.
Definition: tool_menu.cpp:52
size_t i
Definition: json11.cpp:597
void unselect(BOARD_ITEM *aItem)
Function unselect() Takes necessary action mark an item as unselected.
static TOOL_ACTION selectItem
Selects an item (specified as the event parameter).
Definition: pcb_actions.h:76
static void NeighboringSegmentFilter(const VECTOR2I &aPt, GENERAL_COLLECTOR &aCollector)
Class EDA_RECT handles the component boundary box.
Definition: eda_rect.h:44
int Size() const
Returns the number of selected parts.
Definition: selection.h:125
virtual wxString GetSelectMenuText(EDA_UNITS_T aUnits) const
Function GetSelectMenuText returns the text to display to be used in the selection clarification cont...
currently selected items overlay
void RebuildSelection()
Rebuilds the selection from the EDA_ITEMs' selection flags.
Class EDA_ITEM is a base class for most all the KiCad significant classes, used in schematics and boa...
Definition: base_struct.h:163
double calcRatio(double a, double b)
RESET_REASON
Determines the reason of reset for a tool
Definition: tool_base.h:79
boost::optional< T > OPT
Definition: optional.h:7
void SetVisible(VIEW_ITEM *aItem, bool aIsVisible=true)
Sets the item visibility.
Definition: view.cpp:1486
int SelectItems(const TOOL_EVENT &aEvent)
Multiple item selection event handler
ACTION_MENU * create() const override
Returns an instance of this class. It has to be overridden in inheriting classes.
void zoomFitSelection()
Zooms the screen to center and fit the current selection.
Class SELECTION_AREA.
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
Function Add() Adds a VIEW_ITEM to the view.
Definition: pcb_view.cpp:58
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Function Add() Adds a VIEW_ITEM to the view.
Definition: view.cpp:346
const Vec & GetSize() const
Definition: box2.h:187
virtual int Query(const BOX2I &aRect, std::vector< LAYER_ITEM_PAIR > &aResult) const
Function Query() Finds all visible items that touch or are within the rectangle aRect.
Definition: view.cpp:452
Module description (excepted pads)
virtual const EDA_RECT GetBoundingBox() const
Function GetBoundingBox returns the orthogonal, bounding box of this object for display purposes.
KIGFX::VIEW_CONTROLS * getViewControls() const
Function getViewControls()
Definition: tool_base.cpp:42
Class VIEW.
Definition: view.h:61
bool doSelectionMenu(GENERAL_COLLECTOR *aItems, const wxString &aTitle)
Allows the selection of a single item from a list via pop-up menu.
A general implementation of a COLLECTORS_GUIDE.
Definition: collectors.h:385
void BrightenItem(BOARD_ITEM *aItem)
double GetScale() const
Function GetScale()
Definition: view.h:257
class DRAWSEGMENT, a segment not on copper layers
Definition: typeinfo.h:91
BOARD_ITEM_CONTAINER * GetParent() const
virtual BITMAP_DEF GetMenuImage() const
Function GetMenuImage returns a pointer to an image to be used in menus.
virtual PCB_LAYER_ID GetLayer() const
Function GetLayer returns the primary layer this item is on.
int GetState(int type) const
Definition: base_struct.h:249
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition: confirm.cpp:281
void ShowContextMenu(SELECTION &aSelection)
Function ShowContextMenu.
Definition: tool_menu.cpp:59
#define mod(a, n)
Definition: greymap.cpp:24
void selectAllItemsConnectedToItem(BOARD_CONNECTED_ITEM &aSourceItem)
Selects all items connected (by copper) to the given item This selects tracks and vias and continues ...
void setTransitions() override
Sets up handlers for various events.
int CursorSelection(const TOOL_EVENT &aEvent)
Select a single item under cursor event handler.
static TOOL_ACTION selectionCursor
Select a single item under the cursor position.
Definition: pcb_actions.h:70
void SetIgnoreThroughHolePads(bool ignore)
Definition: collectors.h:583
void unhighlight(BOARD_ITEM *aItem, int aHighlightMode, PCBNEW_SELECTION *aGroup=nullptr)
Function unhighlight() Unhighlights the item visually.
show modules references (when texts are visibles)
void SetIgnoreZoneFills(bool ignore)
Definition: collectors.h:610
void update() override
Update menu state stub.
EDA_ITEM * Front() const
Definition: selection.h:182
DIALOG_BLOCK_OPTIONS::OPTIONS m_filterOpts
KICAD_T Type() const
Function Type()
Definition: base_struct.h:210
#define min(a, b)
Definition: auxiliary.h:85
const std::set< unsigned int > GetActiveLayers()
Function GetActiveLayers() Returns the set of currently active layers.
Definition: painter.h:89
static TOOL_ACTION selectSameSheet
Selects all components on the same sheet as the selected footprint.
Definition: pcb_actions.h:102
void SetIgnorePadsOnBack(bool ignore)
Definition: collectors.h:571
void DisplayTitle(bool aDisplay=true)
Function DisplayTitle() Decides whether a title for a pop up menu should be displayed.
Definition: action_menu.cpp:97
virtual const BOX2I ViewBBox() const override
Function ViewBBox() Returns the bounding box for all stored items covering all its layers.
Definition: selection.h:141
virtual void Remove(EDA_ITEM *aItem)
Definition: selection.h:85