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  !m_selection.GetBoundingBox().Contains( wxPoint( evt->Position() ) ) )
219  {
220  ClearSelection();
221  selectPoint( evt->Position(), false, &selectionCancelled );
222  m_selection.SetIsHover( true );
223  }
224 
225  if( !selectionCancelled )
227  }
228 
229  // double click? Display the properties window
230  else if( evt->IsDblClick( BUT_LEFT ) )
231  {
232  if( m_selection.Empty() )
233  selectPoint( evt->Position() );
234 
236  }
237 
238  // drag with LMB? Select multiple objects (or at least draw a selection box) or drag them
239  else if( evt->IsDrag( BUT_LEFT ) )
240  {
241  if( m_additive || m_subtractive || m_exclusive_or || dragAlwaysSelects )
242  {
243  selectMultiple();
244  }
245  else
246  {
247  // selection is empty? try to start dragging the item under the point where drag
248  // started
249  if( m_selection.Empty() && selectCursor() )
250  m_selection.SetIsHover( true );
251 
252  // Check if dragging has started within any of selected items bounding box
253  if( selectionContains( evt->Position() ) )
254  {
255  // Yes -> run the move tool and wait till it finishes
257  }
258  else
259  {
260  // No -> drag a selection box
261  selectMultiple();
262  }
263  }
264  }
265 
266  else if( evt->IsCancel() )
267  {
268  ClearSelection();
269 
270  if( evt->FirstResponder() == this )
272  }
273 
274  else if( evt->Action() == TA_UNDO_REDO_PRE )
275  {
276  ClearSelection();
277  }
278 
279  else
280  evt->SetPassEvent();
281  }
282 
283  // This tool is supposed to be active forever
284  assert( false );
285 
286  return 0;
287 }
288 
289 
291 {
292  return m_selection;
293 }
294 
295 
297  std::vector<BOARD_ITEM*>* aFiltered,
298  bool aConfirmLockedItems )
299 {
300  bool selectionEmpty = m_selection.Empty();
301  m_selection.SetIsHover( selectionEmpty );
302 
303  if( selectionEmpty )
304  {
305  m_toolMgr->RunAction( PCB_ACTIONS::selectionCursor, true, aClientFilter );
307  }
308 
309  if ( aConfirmLockedItems && CheckLock() == SELECTION_LOCKED )
310  {
311  ClearSelection();
312  return m_selection;
313  }
314 
315  if( aClientFilter )
316  {
317  GENERAL_COLLECTOR collector;
318 
319  for( auto item : m_selection )
320  collector.Append( item );
321 
322  aClientFilter( VECTOR2I(), collector );
323 
324  /*
325  * The first step is to find the items that may have been added by the client filter
326  * This can happen if the locked pads select the module instead
327  */
328  std::vector<EDA_ITEM*> new_items;
329  std::set_difference( collector.begin(), collector.end(),
331  std::back_inserter( new_items ) );
332 
336  std::vector<EDA_ITEM*> diff;
337  std::set_difference( m_selection.begin(), m_selection.end(),
338  collector.begin(), collector.end(),
339  std::back_inserter( diff ) );
340 
341  if( aFiltered )
342  {
343  for( auto item : diff )
344  aFiltered->push_back( static_cast<BOARD_ITEM*>( item ) );
345  }
346 
351  for( auto item : diff )
352  unhighlight( static_cast<BOARD_ITEM*>( item ), SELECTED, &m_selection );
353 
354  for( auto item : new_items )
355  highlight( static_cast<BOARD_ITEM*>( item ), SELECTED, &m_selection );
356 
358  }
359 
360  return m_selection;
361 }
362 
363 
365 {
366  GENERAL_COLLECTORS_GUIDE guide( board()->GetVisibleLayers(),
367  (PCB_LAYER_ID) view()->GetTopLayer(), view() );
368 
369  // account for the globals
370  guide.SetIgnoreMTextsMarkedNoShow( ! board()->IsElementVisible( LAYER_MOD_TEXT_INVISIBLE ) );
371  guide.SetIgnoreMTextsOnBack( ! board()->IsElementVisible( LAYER_MOD_TEXT_BK ) );
372  guide.SetIgnoreMTextsOnFront( ! board()->IsElementVisible( LAYER_MOD_TEXT_FR ) );
373  guide.SetIgnoreModulesOnBack( ! board()->IsElementVisible( LAYER_MOD_BK ) );
374  guide.SetIgnoreModulesOnFront( ! board()->IsElementVisible( LAYER_MOD_FR ) );
375  guide.SetIgnorePadsOnBack( ! board()->IsElementVisible( LAYER_PAD_BK ) );
376  guide.SetIgnorePadsOnFront( ! board()->IsElementVisible( LAYER_PAD_FR ) );
377  guide.SetIgnoreThroughHolePads( ! board()->IsElementVisible( LAYER_PADS_TH ) );
378  guide.SetIgnoreModulesVals( ! board()->IsElementVisible( LAYER_MOD_VALUES ) );
379  guide.SetIgnoreModulesRefs( ! board()->IsElementVisible( LAYER_MOD_REFERENCES ) );
380  guide.SetIgnoreThroughVias( ! board()->IsElementVisible( LAYER_VIA_THROUGH ) );
381  guide.SetIgnoreBlindBuriedVias( ! board()->IsElementVisible( LAYER_VIA_BBLIND ) );
382  guide.SetIgnoreMicroVias( ! board()->IsElementVisible( LAYER_VIA_MICROVIA ) );
383  guide.SetIgnoreTracks( ! board()->IsElementVisible( LAYER_TRACKS ) );
384 
385  return guide;
386 }
387 
388 
389 bool SELECTION_TOOL::selectPoint( const VECTOR2I& aWhere, bool aOnDrag,
390  bool* aSelectionCancelledFlag,
391  CLIENT_SELECTION_FILTER aClientFilter )
392 {
394  GENERAL_COLLECTOR collector;
395  auto& displayOpts = m_frame->GetDisplayOptions();
396  bool cleared = false;
397 
398  guide.SetIgnoreZoneFills( displayOpts.m_DisplayZonesMode != 0 );
399 
400  collector.Collect( board(),
402  wxPoint( aWhere.x, aWhere.y ), guide );
403 
404  // Remove unselectable items
405  for( int i = collector.GetCount() - 1; i >= 0; --i )
406  {
407  if( !Selectable( collector[ i ] ) || ( aOnDrag && collector[i]->IsLocked() ) )
408  collector.Remove( i );
409  }
410 
412 
413  // Allow the client to do tool- or action-specific filtering to see if we
414  // can get down to a single item
415  if( aClientFilter )
416  aClientFilter( aWhere, collector );
417 
418  // Apply some ugly heuristics to avoid disambiguation menus whenever possible
419  if( collector.GetCount() > 1 && !m_skip_heuristics )
420  {
421  GuessSelectionCandidates( collector, aWhere );
422  }
423 
424  // If still more than one item we're going to have to ask the user.
425  if( collector.GetCount() > 1 )
426  {
427  if( aOnDrag )
429 
430  if( !doSelectionMenu( &collector, _( "Clarify Selection" ) ) )
431  {
432  if( aSelectionCancelledFlag )
433  *aSelectionCancelledFlag = true;
434 
435  return false;
436  }
437  }
438 
440  {
441  if( m_selection.GetSize() > 0 )
442  {
443  // Don't fire an event now as it will end up redundant if we fire a SelectedEvent
444  // or an UnselectedEvent.
445  cleared = true;
446  ClearSelection( true );
447  }
448  }
449 
450  if( collector.GetCount() == 1 )
451  {
452  BOARD_ITEM* item = collector[ 0 ];
453 
454  if( m_subtractive || ( m_exclusive_or && item->IsSelected() ) )
455  {
456  unselect( item );
458  return false;
459  }
460  else
461  {
462  select( item );
464  return true;
465  }
466  }
467 
468  if( cleared )
470 
471  return false;
472 }
473 
474 
475 bool SELECTION_TOOL::selectCursor( bool aForceSelect, CLIENT_SELECTION_FILTER aClientFilter )
476 {
477  if( aForceSelect || m_selection.Empty() )
478  {
479  ClearSelection( true /*quiet mode*/ );
480  selectPoint( getViewControls()->GetCursorPosition( false ), false, NULL, aClientFilter );
481  }
482 
483  return !m_selection.Empty();
484 }
485 
486 
488 {
489  bool cancelled = false; // Was the tool cancelled while it was running?
490  m_multiple = true; // Multiple selection mode is active
491  KIGFX::VIEW* view = getView();
492 
494  view->Add( &area );
495 
496  bool anyAdded = false;
497  bool anySubtracted = false;
498 
499  while( TOOL_EVENT* evt = Wait() )
500  {
501  if( evt->IsCancelInteractive() || evt->IsActivate() )
502  {
503  cancelled = true;
504  break;
505  }
506 
507  if( evt->IsDrag( BUT_LEFT ) )
508  {
510  {
511  if( m_selection.GetSize() > 0 )
512  {
513  anySubtracted = true;
514  ClearSelection( true /*quiet mode*/ );
515  }
516  }
517 
518  // Start drawing a selection box
519  area.SetOrigin( evt->DragOrigin() );
520  area.SetEnd( evt->Position() );
521  area.SetAdditive( m_additive );
524 
525  view->SetVisible( &area, true );
526  view->Update( &area );
527  getViewControls()->SetAutoPan( true );
528  }
529 
530  if( evt->IsMouseUp( BUT_LEFT ) )
531  {
532  getViewControls()->SetAutoPan( false );
533 
534  // End drawing the selection box
535  view->SetVisible( &area, false );
536 
537  // Mark items within the selection box as selected
538  std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> selectedItems;
539 
540  // Filter the view items based on the selection box
541  BOX2I selectionBox = area.ViewBBox();
542  view->Query( selectionBox, selectedItems ); // Get the list of selected items
543 
544  std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR>::iterator it, it_end;
545 
546  int width = area.GetEnd().x - area.GetOrigin().x;
547  int height = area.GetEnd().y - area.GetOrigin().y;
548 
549  /* Selection mode depends on direction of drag-selection:
550  * Left > Right : Select objects that are fully enclosed by selection
551  * Right > Left : Select objects that are crossed by selection
552  */
553  bool windowSelection = width >= 0 ? true : false;
554 
555  if( view->IsMirroredX() )
556  windowSelection = !windowSelection;
557 
558  // Construct an EDA_RECT to determine BOARD_ITEM selection
559  EDA_RECT selectionRect( (wxPoint) area.GetOrigin(), wxSize( width, height ) );
560 
561  selectionRect.Normalize();
562 
563  for( it = selectedItems.begin(), it_end = selectedItems.end(); it != it_end; ++it )
564  {
565  BOARD_ITEM* item = static_cast<BOARD_ITEM*>( it->first );
566 
567  if( !item || !Selectable( item ) )
568  continue;
569 
570  if( item->HitTest( selectionRect, windowSelection ) )
571  {
572  if( m_subtractive || ( m_exclusive_or && item->IsSelected() ) )
573  {
574  unselect( item );
575  anySubtracted = true;
576  }
577  else
578  {
579  select( item );
580  anyAdded = true;
581  }
582  }
583  }
584 
585  m_selection.SetIsHover( false );
586 
587  // Inform other potentially interested tools
588  if( anyAdded )
590  else if( anySubtracted )
592 
593  break; // Stop waiting for events
594  }
595  }
596 
597  getViewControls()->SetAutoPan( false );
598 
599  // Stop drawing the selection box
600  view->Remove( &area );
601  m_multiple = false; // Multiple selection mode is inactive
602 
603  if( !cancelled )
605 
606  return cancelled;
607 }
608 
609 
611 {
612  if( !m_locked || m_editModules )
613  return SELECTION_UNLOCKED;
614 
615  bool containsLocked = false;
616 
617  // Check if the selection contains locked items
618  for( const auto& item : m_selection )
619  {
620  switch( item->Type() )
621  {
622  case PCB_MODULE_T:
623  if( static_cast<MODULE*>( item )->IsLocked() )
624  containsLocked = true;
625  break;
626 
627  case PCB_MODULE_EDGE_T:
628  case PCB_MODULE_TEXT_T:
629  if( static_cast<MODULE*>( item->GetParent() )->IsLocked() )
630  containsLocked = true;
631  break;
632 
633  default: // suppress warnings
634  break;
635  }
636  }
637 
638  if( containsLocked )
639  {
640  if( IsOK( m_frame, _( "Selection contains locked items. Do you want to continue?" ) ) )
641  {
642  m_locked = false;
644  }
645  else
646  return SELECTION_LOCKED;
647  }
648 
649  return SELECTION_UNLOCKED;
650 }
651 
652 
654 {
656 
657  selectCursor( false, aClientFilter );
658 
659  return 0;
660 }
661 
662 
664 {
665  ClearSelection();
666 
667  return 0;
668 }
669 
670 
672 {
673  std::vector<BOARD_ITEM*>* items = aEvent.Parameter<std::vector<BOARD_ITEM*>*>();
674 
675  if( items )
676  {
677  // Perform individual selection of each item before processing the event.
678  for( auto item : *items )
679  select( item );
680 
682  }
683 
684  return 0;
685 }
686 
687 
689 {
690  AddItemToSel( aEvent.Parameter<BOARD_ITEM*>() );
691  return 0;
692 }
693 
694 
695 void SELECTION_TOOL::AddItemToSel( BOARD_ITEM* aItem, bool aQuietMode )
696 {
697  if( aItem )
698  {
699  select( aItem );
700 
701  // Inform other potentially interested tools
702  if( !aQuietMode )
704  }
705 }
706 
707 
709 {
710  std::vector<BOARD_ITEM*>* items = aEvent.Parameter<std::vector<BOARD_ITEM*>*>();
711 
712  if( items )
713  {
714  // Perform individual unselection of each item before processing the event
715  for( auto item : *items )
716  unselect( item );
717 
719  }
720 
721  return 0;
722 }
723 
724 
726 {
727  RemoveItemFromSel( aEvent.Parameter<BOARD_ITEM*>() );
728  return 0;
729 }
730 
731 
732 void SELECTION_TOOL::RemoveItemFromSel( BOARD_ITEM* aItem, bool aQuietMode )
733 {
734  if( aItem )
735  {
736  unselect( aItem );
737 
738  // Inform other potentially interested tools
740  }
741 }
742 
743 
745 {
746  highlight( aItem, BRIGHTENED );
747 }
748 
749 
751 {
752  unhighlight( aItem, BRIGHTENED );
753 }
754 
755 
756 void connectedTrackFilter( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector )
757 {
758  // Narrow the collection down to a single TRACK item for a trivial connection, or
759  // multiple TRACK items for non-trivial connections.
760  for( int i = aCollector.GetCount() - 1; i >= 0; i-- )
761  {
762  if( !dynamic_cast<TRACK*>( aCollector[i] ) )
763  aCollector.Remove( i );
764  }
765 
766  ROUTER_TOOL::NeighboringSegmentFilter( aPt, aCollector );
767 }
768 
769 
771 {
774 
776  return 0;
777 
778  return expandConnection( aEvent );
779 }
780 
781 
783 {
784  // copy the selection, since we're going to iterate and modify
785  auto selection = m_selection.GetItems();
786 
787  // We use the BUSY flag to mark connections
788  for( auto item : selection )
789  item->SetState( BUSY, false );
790 
791  for( auto item : selection )
792  {
793  TRACK* trackItem = dynamic_cast<TRACK*>( item );
794 
795  // Track items marked BUSY have already been visited
796  // therefore their connections have already been marked
797  if( trackItem && !trackItem->GetState( BUSY ) )
798  {
799  if( aEvent.GetCommandId()
801  selectAllItemsConnectedToItem( *trackItem );
802  else
803  selectAllItemsConnectedToTrack( *trackItem );
804  }
805  }
806 
807  // Inform other potentially interested tools
808  if( m_selection.Size() > 0 )
810 
811  return 0;
812 }
813 
814 
815 void connectedItemFilter( const VECTOR2I&, GENERAL_COLLECTOR& aCollector )
816 {
817  // Narrow the collection down to a single BOARD_CONNECTED_ITEM for each represented net.
818  // All other items types are removed.
819  std::set<int> representedNets;
820 
821  for( int i = aCollector.GetCount() - 1; i >= 0; i-- )
822  {
823  BOARD_CONNECTED_ITEM* item = dynamic_cast<BOARD_CONNECTED_ITEM*>( aCollector[i] );
824  if( !item )
825  aCollector.Remove( i );
826  else if ( representedNets.count( item->GetNetCode() ) )
827  aCollector.Remove( i );
828  else
829  representedNets.insert( item->GetNetCode() );
830  }
831 }
832 
833 
835 {
836  bool haveCopper = false;
837 
838  for( auto item : m_selection.GetItems() )
839  {
840  if( dynamic_cast<BOARD_CONNECTED_ITEM*>( item ) )
841  haveCopper = true;;
842  }
843 
844  if( !haveCopper )
846 
847  // copy the selection, since we're going to iterate and modify
848  auto selection = m_selection.GetItems();
849 
850  for( auto item : selection )
851  {
852  BOARD_CONNECTED_ITEM* connItem = dynamic_cast<BOARD_CONNECTED_ITEM*>( item );
853 
854  if( connItem )
855  selectAllItemsConnectedToItem( *connItem );
856  }
857 
858  // Inform other potentially interested tools
859  if( m_selection.Size() > 0 )
861 
862  return 0;
863 }
864 
865 
867 {
868  constexpr KICAD_T types[] = { PCB_TRACE_T, PCB_VIA_T, EOT };
869  auto connectivity = board()->GetConnectivity();
870 
871  for( auto item : connectivity->GetConnectedItems(
872  static_cast<BOARD_CONNECTED_ITEM*>( &aSourceTrack ), types ) )
873  select( item );
874 }
875 
876 
878 {
879  constexpr KICAD_T types[] = { PCB_TRACE_T, PCB_VIA_T, PCB_PAD_T, EOT };
880  auto connectivity = board()->GetConnectivity();
881 
882  for( auto item : connectivity->GetConnectedItems( &aSourceItem, types ) )
883  {
884  // We want to select items connected through pads but not pads
885  // otherwise, the common use case of "Select Copper"->Delete will
886  // remove footprints in addition to traces and vias
887  if( item->Type() != PCB_PAD_T )
888  select( item );
889  }
890 }
891 
892 
894 {
895  constexpr KICAD_T types[] = { PCB_TRACE_T, PCB_VIA_T, EOT };
896  auto connectivity = board()->GetConnectivity();
897 
898  for( auto item : connectivity->GetNetItems( aNetCode, types ) )
899  select( item );
900 }
901 
902 
904 {
905  if( !selectCursor() )
906  return 0;
907 
908  // copy the selection, since we're going to iterate and modify
909  auto selection = m_selection.GetItems();
910 
911  for( auto i : selection )
912  {
913  auto item = static_cast<BOARD_ITEM*>( i );
914 
915  // only connected items get a net code
916  if( item->IsConnected() )
917  {
918  auto& connItem = static_cast<BOARD_CONNECTED_ITEM&>( *item );
919 
920  selectAllItemsOnNet( connItem.GetNetCode() );
921  }
922  }
923 
924  // Inform other potentially interested tools
925  if( m_selection.Size() > 0 )
927 
928  return 0;
929 }
930 
931 
932 void SELECTION_TOOL::selectAllItemsOnSheet( wxString& aSheetpath )
933 {
934  std::list<MODULE*> modList;
935 
936  // store all modules that are on that sheet
937  for( auto mitem : board()->Modules() )
938  {
939  if( mitem != NULL && mitem->GetPath().Contains( aSheetpath ) )
940  {
941  modList.push_back( mitem );
942  }
943  }
944 
945  //Generate a list of all pads, and of all nets they belong to.
946  std::list<int> netcodeList;
947  std::list<BOARD_CONNECTED_ITEM*> padList;
948  for( MODULE* mmod : modList )
949  {
950  for( auto pad : mmod->Pads() )
951  {
952  if( pad->IsConnected() )
953  {
954  netcodeList.push_back( pad->GetNetCode() );
955  padList.push_back( pad );
956  }
957  }
958  }
959  // remove all duplicates
960  netcodeList.sort();
961  netcodeList.unique();
962 
963  // auto select trivial connections segments which are launched from the pads
964  std::list<TRACK*> launchTracks;
965 
966  for( auto pad : padList )
967  {
969  }
970 
971  // now we need to find all modules that are connected to each of these nets
972  // then we need to determine if these modules are in the list of modules
973  // belonging to this sheet ( modList )
974  std::list<int> removeCodeList;
975  constexpr KICAD_T padType[] = { PCB_PAD_T, EOT };
976 
977  for( int netCode : netcodeList )
978  {
979  for( BOARD_CONNECTED_ITEM* mitem : board()->GetConnectivity()->GetNetItems( netCode, padType ) )
980  {
981  if( mitem->Type() == PCB_PAD_T)
982  {
983  bool found = ( std::find( modList.begin(), modList.end(),
984  mitem->GetParent() ) != modList.end() );
985 
986  if( !found )
987  {
988  // if we cannot find the module of the pad in the modList
989  // then we can assume that that module is not located in the same
990  // schematic, therefore invalidate this netcode.
991  removeCodeList.push_back( netCode );
992  break;
993  }
994  }
995  }
996  }
997 
998  // remove all duplicates
999  removeCodeList.sort();
1000  removeCodeList.unique();
1001 
1002  for( int removeCode : removeCodeList )
1003  {
1004  netcodeList.remove( removeCode );
1005  }
1006 
1007  std::list<BOARD_CONNECTED_ITEM*> localConnectionList;
1008  constexpr KICAD_T trackViaType[] = { PCB_TRACE_T, PCB_VIA_T, EOT };
1009 
1010  for( int netCode : netcodeList )
1011  {
1012  for( BOARD_CONNECTED_ITEM* item : board()->GetConnectivity()->GetNetItems( netCode, trackViaType ) )
1013  {
1014  localConnectionList.push_back( item );
1015  }
1016  }
1017 
1018  for( BOARD_ITEM* i : modList )
1019  {
1020  if( i != NULL )
1021  select( i );
1022  }
1023 
1024  for( BOARD_CONNECTED_ITEM* i : localConnectionList )
1025  {
1026  if( i != NULL )
1027  select( i );
1028  }
1029 }
1030 
1031 
1033 {
1034  //Should recalculate the view to zoom in on the selection
1035  auto selectionBox = m_selection.ViewBBox();
1036  auto view = getView();
1037 
1038  VECTOR2D screenSize = view->ToWorld( m_frame->GetCanvas()->GetClientSize(), false );
1039 
1040  if( selectionBox.GetWidth() != 0 || selectionBox.GetHeight() != 0 )
1041  {
1042  VECTOR2D vsize = selectionBox.GetSize();
1043  double scale = view->GetScale() / std::max( fabs( vsize.x / screenSize.x ),
1044  fabs( vsize.y / screenSize.y ) );
1045  view->SetScale( scale );
1046  view->SetCenter( selectionBox.Centre() );
1047  view->Add( &m_selection );
1048  }
1049 
1051 }
1052 
1053 
1055 {
1056  ClearSelection( true /*quiet mode*/ );
1057  wxString* sheetpath = aEvent.Parameter<wxString*>();
1058 
1059  selectAllItemsOnSheet( *sheetpath );
1060 
1061  zoomFitSelection();
1062 
1063  if( m_selection.Size() > 0 )
1065 
1066  return 0;
1067 }
1068 
1069 
1071 {
1072  if( !selectCursor( true ) )
1073  return 0;
1074 
1075  // this function currently only supports modules since they are only
1076  // on one sheet.
1077  auto item = m_selection.Front();
1078 
1079  if( !item )
1080  return 0;
1081 
1082  if( item->Type() != PCB_MODULE_T )
1083  return 0;
1084 
1085  auto mod = dynamic_cast<MODULE*>( item );
1086 
1087  ClearSelection( true /*quiet mode*/ );
1088 
1089  // get the lowest subsheet name for this.
1090  wxString sheetPath = mod->GetPath();
1091  sheetPath = sheetPath.BeforeLast( '/' );
1092  sheetPath = sheetPath.AfterLast( '/' );
1093 
1094  selectAllItemsOnSheet( sheetPath );
1095 
1096  // Inform other potentially interested tools
1097  if( m_selection.Size() > 0 )
1099 
1100  return 0;
1101 }
1102 
1103 
1105 {
1106  bool cleared = false;
1107 
1108  if( m_selection.GetSize() > 0 )
1109  {
1110  // Don't fire an event now; most of the time it will be redundant as we're about to
1111  // fire a SelectedEvent.
1112  cleared = true;
1113  ClearSelection( true /*quiet mode*/ );
1114  }
1115 
1116  if( aItem )
1117  {
1118  select( aItem );
1119  m_frame->FocusOnLocation( aItem->GetPosition() );
1120 
1121  // Inform other potentially interested tools
1123  }
1124  else if( cleared )
1125  {
1127  }
1128 
1130 }
1131 
1132 
1133 int SELECTION_TOOL::find( const TOOL_EVENT& aEvent )
1134 {
1135  DIALOG_FIND dlg( m_frame );
1136  dlg.SetCallback( std::bind( &SELECTION_TOOL::findCallback, this, _1 ) );
1137  dlg.ShowModal();
1138 
1139  return 0;
1140 }
1141 
1142 
1151 static bool itemIsIncludedByFilter( const BOARD_ITEM& aItem,
1152  const BOARD& aBoard,
1153  const DIALOG_BLOCK_OPTIONS::OPTIONS& aBlockOpts )
1154 {
1155  bool include = true;
1156  const PCB_LAYER_ID layer = aItem.GetLayer();
1157 
1158  // can skip without even checking item type
1159  // fixme: selecting items on invisible layers does not work in GAL
1160  if( !aBlockOpts.includeItemsOnInvisibleLayers
1161  && !aBoard.IsLayerVisible( layer ) )
1162  {
1163  include = false;
1164  }
1165 
1166  // if the item needs to be checked against the options
1167  if( include )
1168  {
1169  switch( aItem.Type() )
1170  {
1171  case PCB_MODULE_T:
1172  {
1173  const auto& module = static_cast<const MODULE&>( aItem );
1174 
1175  include = aBlockOpts.includeModules;
1176 
1177  if( include && !aBlockOpts.includeLockedModules )
1178  {
1179  include = !module.IsLocked();
1180  }
1181 
1182  break;
1183  }
1184  case PCB_TRACE_T:
1185  {
1186  include = aBlockOpts.includeTracks;
1187  break;
1188  }
1189  case PCB_VIA_T:
1190  {
1191  include = aBlockOpts.includeVias;
1192  break;
1193  }
1194  case PCB_ZONE_AREA_T:
1195  {
1196  include = aBlockOpts.includeZones;
1197  break;
1198  }
1199  case PCB_LINE_T:
1200  case PCB_TARGET_T:
1201  case PCB_DIMENSION_T:
1202  {
1203  if( layer == Edge_Cuts )
1204  include = aBlockOpts.includeBoardOutlineLayer;
1205  else
1206  include = aBlockOpts.includeItemsOnTechLayers;
1207  break;
1208  }
1209  case PCB_TEXT_T:
1210  {
1211  include = aBlockOpts.includePcbTexts;
1212  break;
1213  }
1214  default:
1215  {
1216  // no filtering, just select it
1217  break;
1218  }
1219  }
1220  }
1221 
1222  return include;
1223 }
1224 
1225 
1227 {
1228  const BOARD& board = *getModel<BOARD>();
1229  DIALOG_BLOCK_OPTIONS::OPTIONS& opts = m_priv->m_filterOpts;
1230  DIALOG_BLOCK_OPTIONS dlg( m_frame, opts, false, _( "Filter selection" ) );
1231 
1232  const int cmd = dlg.ShowModal();
1233 
1234  if( cmd != wxID_OK )
1235  return 0;
1236 
1237  // copy current selection
1238  std::deque<EDA_ITEM*> selection = m_selection.GetItems();
1239 
1240  ClearSelection( true /*quiet mode*/ );
1241 
1242  // re-select items from the saved selection according to the dialog options
1243  for( EDA_ITEM* i : selection )
1244  {
1245  BOARD_ITEM* item = static_cast<BOARD_ITEM*>( i );
1246  bool include = itemIsIncludedByFilter( *item, board, opts );
1247 
1248  if( include )
1249  select( item );
1250  }
1251 
1253 
1254  return 0;
1255 }
1256 
1257 
1258 void SELECTION_TOOL::ClearSelection( bool aQuietMode )
1259 {
1260  if( m_selection.Empty() )
1261  return;
1262 
1263  while( m_selection.GetSize() )
1264  unhighlight( static_cast<BOARD_ITEM*>( m_selection.Front() ), SELECTED, &m_selection );
1265 
1266  view()->Update( &m_selection );
1267 
1268  m_selection.SetIsHover( false );
1270 
1271  m_locked = true;
1272 
1273  // Inform other potentially interested tools
1274  if( !aQuietMode )
1275  {
1278  }
1279 }
1280 
1281 
1283 {
1284  m_selection.Clear();
1285 
1286  INSPECTOR_FUNC inspector = [&] ( EDA_ITEM* item, void* testData )
1287  {
1288  if( item->IsSelected() )
1289  {
1290  EDA_ITEM* parent = item->GetParent();
1291 
1292  // Flags on module children might be set only because the parent is selected.
1293  if( parent && parent->Type() == PCB_MODULE_T && parent->IsSelected() )
1294  return SEARCH_CONTINUE;
1295 
1296  highlight( (BOARD_ITEM*) item, SELECTED, &m_selection );
1297  }
1298 
1299  return SEARCH_CONTINUE;
1300  };
1301 
1302  board()->Visit( inspector, nullptr, m_editModules ? GENERAL_COLLECTOR::ModuleItems
1304 }
1305 
1306 
1308 {
1309  GENERAL_COLLECTOR* collector = aEvent.Parameter<GENERAL_COLLECTOR*>();
1310 
1311  doSelectionMenu( collector, wxEmptyString );
1312 
1313  return 0;
1314 }
1315 
1316 
1317 bool SELECTION_TOOL::doSelectionMenu( GENERAL_COLLECTOR* aCollector, const wxString& aTitle )
1318 {
1319  BOARD_ITEM* current = nullptr;
1320  PCBNEW_SELECTION highlightGroup;
1321  ACTION_MENU menu( true );
1322 
1323  highlightGroup.SetLayer( LAYER_SELECT_OVERLAY );
1324  getView()->Add( &highlightGroup );
1325 
1326  int limit = std::min( 9, aCollector->GetCount() );
1327 
1328  for( int i = 0; i < limit; ++i )
1329  {
1330  wxString text;
1331  BOARD_ITEM* item = ( *aCollector )[i];
1332  text = item->GetSelectMenuText( m_frame->GetUserUnits() );
1333 
1334  wxString menuText = wxString::Format("&%d. %s", i + 1, text );
1335  menu.Add( menuText, i + 1, item->GetMenuImage() );
1336  }
1337 
1338  if( aTitle.Length() )
1339  menu.SetTitle( aTitle );
1340 
1341  menu.SetIcon( info_xpm );
1342  menu.DisplayTitle( true );
1343  SetContextMenu( &menu, CMENU_NOW );
1344 
1345  while( TOOL_EVENT* evt = Wait() )
1346  {
1347  if( evt->Action() == TA_CHOICE_MENU_UPDATE )
1348  {
1349  if( current )
1350  unhighlight( current, BRIGHTENED, &highlightGroup );
1351 
1352  int id = *evt->GetCommandId();
1353 
1354  // User has pointed an item, so show it in a different way
1355  if( id > 0 && id <= limit )
1356  {
1357  current = ( *aCollector )[id - 1];
1358  highlight( current, BRIGHTENED, &highlightGroup );
1359  }
1360  else
1361  {
1362  current = NULL;
1363  }
1364  }
1365  else if( evt->Action() == TA_CHOICE_MENU_CHOICE )
1366  {
1367  if( current )
1368  unhighlight( current, BRIGHTENED, &highlightGroup );
1369 
1370  OPT<int> id = evt->GetCommandId();
1371 
1372  // User has selected an item, so this one will be returned
1373  if( id && ( *id > 0 ) )
1374  current = ( *aCollector )[*id - 1];
1375  else
1376  current = NULL;
1377 
1378  break;
1379  }
1380  }
1381  getView()->Remove( &highlightGroup );
1382 
1383  if( current )
1384  {
1385  aCollector->Empty();
1386  aCollector->Append( current );
1387  return true;
1388  }
1389 
1390  return false;
1391 }
1392 
1393 
1395 {
1396  int count = aCollector->GetPrimaryCount(); // try to use preferred layer
1397 
1398  if( 0 == count )
1399  count = aCollector->GetCount();
1400 
1401  for( int i = 0; i < count; ++i )
1402  {
1403  if( ( *aCollector )[i]->Type() != PCB_MODULE_T )
1404  return NULL;
1405  }
1406 
1407  // All are modules, now find smallest MODULE
1408  int minDim = 0x7FFFFFFF;
1409  int minNdx = 0;
1410 
1411  for( int i = 0; i < count; ++i )
1412  {
1413  MODULE* module = (MODULE*) ( *aCollector )[i];
1414 
1415  int lx = module->GetFootprintRect().GetWidth();
1416  int ly = module->GetFootprintRect().GetHeight();
1417 
1418  int lmin = std::min( lx, ly );
1419 
1420  if( lmin < minDim )
1421  {
1422  minDim = lmin;
1423  minNdx = i;
1424  }
1425  }
1426 
1427  return (*aCollector)[minNdx];
1428 }
1429 
1430 
1431 bool SELECTION_TOOL::Selectable( const BOARD_ITEM* aItem, bool checkVisibilityOnly ) const
1432 {
1433  // Is high contrast mode enabled?
1434  bool highContrast = getView()->GetPainter()->GetSettings()->GetHighContrast();
1435 
1436  int layers[KIGFX::VIEW::VIEW_MAX_LAYERS], layers_count;
1437 
1438  // Filter out items that do not belong to active layers
1439  std::set<unsigned int> activeLayers = getView()->GetPainter()->GetSettings()->GetActiveLayers();
1440 
1441  // The markers layer is considered to be always active
1442  activeLayers.insert( (unsigned int) LAYER_DRC );
1443 
1444  aItem->ViewGetLayers( layers, layers_count );
1445 
1446  if( highContrast )
1447  {
1448  bool onActive = false; // Is the item on any of active layers?
1449 
1450  for( int i = 0; i < layers_count; ++i )
1451  {
1452  if( activeLayers.count( layers[i] ) > 0 ) // Item is on at least one of the active layers
1453  {
1454  onActive = true;
1455  break;
1456  }
1457  }
1458 
1459  if( !onActive ) // We do not want to select items that are in the background
1460  {
1461  return false;
1462  }
1463  }
1464 
1465  switch( aItem->Type() )
1466  {
1467  case PCB_ZONE_AREA_T:
1468  {
1469  // Check to see if this keepout is part of a footprint
1470  // If it is, and we are not editing the footprint, it should not be selectable
1471  const bool zoneInFootprint =
1472  aItem->GetParent() != nullptr && aItem->GetParent()->Type() == PCB_MODULE_T;
1473  if( zoneInFootprint && !m_editModules && !checkVisibilityOnly )
1474  return false;
1475 
1476  // Keepout zones can exist on multiple layers!
1477  {
1478  auto* zone = static_cast<const ZONE_CONTAINER*>( aItem );
1479 
1480  if( zone->GetIsKeepout() )
1481  {
1482  auto zoneLayers = zone->GetLayerSet().Seq();
1483 
1484  for( unsigned int i = 0; i < zoneLayers.size(); i++ )
1485  {
1486  if( board()->IsLayerVisible( zoneLayers[i] ) )
1487  {
1488  return true;
1489  }
1490  }
1491 
1492  // No active layers selected!
1493  return false;
1494  }
1495  }
1496  }
1497  break;
1498 
1499  case PCB_TRACE_T:
1500  {
1501  if( !board()->IsElementVisible( LAYER_TRACKS ) )
1502  return false;
1503  }
1504  break;
1505 
1506  case PCB_VIA_T:
1507  {
1508  const VIA* via = static_cast<const VIA*>( aItem );
1509 
1510  // Check if appropriate element layer is visible
1511  switch( via->GetViaType() )
1512  {
1513  case VIA_THROUGH:
1515  return false;
1516  break;
1517 
1518  case VIA_BLIND_BURIED:
1520  return false;
1521  break;
1522 
1523  case VIA_MICROVIA:
1525  return false;
1526  break;
1527 
1528  default:
1529  wxFAIL;
1530  return false;
1531  }
1532 
1533  // For vias it is enough if only one of its layers is visible
1534  return ( board()->GetVisibleLayers() & via->GetLayerSet() ).any();
1535  }
1536 
1537  case PCB_MODULE_T:
1538  {
1539  // In modedit, we do not want to select the module itself.
1540  if( m_editModules )
1541  return false;
1542 
1543  // Allow selection of footprints if some part of the footprint is visible.
1544 
1545  MODULE* module = const_cast<MODULE*>( static_cast<const MODULE*>( aItem ) );
1546 
1547  for( auto item : module->GraphicalItems() )
1548  {
1549  if( Selectable( item, true ) )
1550  return true;
1551  }
1552 
1553  for( auto pad : module->Pads() )
1554  {
1555  if( Selectable( pad, true ) )
1556  return true;
1557  }
1558 
1559  for( auto zone : module->Zones() )
1560  {
1561  if( Selectable( zone, true ) )
1562  return true;
1563  }
1564 
1565  return false;
1566  }
1567 
1568  case PCB_MODULE_TEXT_T:
1569  // Multiple selection is only allowed in modedit mode. In pcbnew, you have to select
1570  // module subparts one by one, rather than with a drag selection. This is so you can
1571  // pick up items under an (unlocked) module without also moving the module's sub-parts.
1572  if( !m_editModules && !checkVisibilityOnly )
1573  {
1574  if( m_multiple )
1575  return false;
1576  }
1577 
1578  if( !m_editModules && !view()->IsVisible( aItem ) )
1579  return false;
1580 
1581  break;
1582 
1583  case PCB_MODULE_EDGE_T:
1584  case PCB_PAD_T:
1585  {
1586  // Multiple selection is only allowed in modedit mode. In pcbnew, you have to select
1587  // module subparts one by one, rather than with a drag selection. This is so you can
1588  // pick up items under an (unlocked) module without also moving the module's sub-parts.
1589  if( !m_editModules && !checkVisibilityOnly )
1590  {
1591  if( m_multiple )
1592  return false;
1593  }
1594 
1595  if( aItem->Type() == PCB_PAD_T )
1596  {
1597  auto pad = static_cast<const D_PAD*>( aItem );
1598 
1599  // In pcbnew, locked modules prevent individual pad selection.
1600  // In modedit, we don't enforce this as the module is assumed to be edited by design.
1601  if( !m_editModules && !checkVisibilityOnly )
1602  {
1603  if( pad->GetParent() && pad->GetParent()->IsLocked() )
1604  return false;
1605  }
1606 
1607  // Check render mode (from the Items tab) first
1608  switch( pad->GetAttribute() )
1609  {
1610  case PAD_ATTRIB_STANDARD:
1612  if( !board()->IsElementVisible( LAYER_PADS_TH ) )
1613  return false;
1614  break;
1615 
1616  case PAD_ATTRIB_CONN:
1617  case PAD_ATTRIB_SMD:
1618  if( pad->IsOnLayer( F_Cu ) && !board()->IsElementVisible( LAYER_PAD_FR ) )
1619  return false;
1620  else if( pad->IsOnLayer( B_Cu ) && !board()->IsElementVisible( LAYER_PAD_BK ) )
1621  return false;
1622  break;
1623  }
1624 
1625  // Otherwise, pads are selectable if any draw layer is visible
1626 
1627  // Shortcut: check copper layer visibility
1628  if( board()->IsLayerVisible( F_Cu ) && pad->IsOnLayer( F_Cu ) )
1629  return true;
1630 
1631  if( board()->IsLayerVisible( B_Cu ) && pad->IsOnLayer( B_Cu ) )
1632  return true;
1633 
1634  // Now check the non-copper layers
1635 
1636  bool draw_layer_visible = false;
1637 
1638  int pad_layers[KIGFX::VIEW::VIEW_MAX_LAYERS], pad_layers_count;
1639  pad->ViewGetLayers( pad_layers, pad_layers_count );
1640 
1641  for( int i = 0; i < pad_layers_count; ++i )
1642  {
1643  // NOTE: Only checking the regular layers (not GAL meta-layers)
1644  if( ( ( pad_layers[i] < PCB_LAYER_ID_COUNT ) &&
1645  board()->IsLayerVisible( static_cast<PCB_LAYER_ID>( pad_layers[i] ) ) ) )
1646  {
1647  draw_layer_visible = true;
1648  }
1649  }
1650 
1651  return draw_layer_visible;
1652  }
1653 
1654  break;
1655  }
1656 
1657 
1658  case PCB_MARKER_T: // Always selectable
1659  return true;
1660 
1661  // These are not selectable
1662  case NOT_USED:
1663  case TYPE_NOT_INIT:
1664  return false;
1665 
1666  default: // Suppress warnings
1667  break;
1668  }
1669 
1670  // All other items are selected only if the layer on which they exist is visible
1671  return board()->IsLayerVisible( aItem->GetLayer() )
1672  && aItem->ViewGetLOD( aItem->GetLayer(), view() ) < view()->GetScale();
1673 }
1674 
1675 
1677 {
1678  if( aItem->IsSelected() )
1679  {
1680  return;
1681  }
1682 
1683  if( aItem->Type() == PCB_PAD_T )
1684  {
1685  MODULE* module = static_cast<MODULE*>( aItem->GetParent() );
1686 
1687  if( m_selection.Contains( module ) )
1688  return;
1689  }
1690 
1691  highlight( aItem, SELECTED, &m_selection );
1692 }
1693 
1694 
1696 {
1697  unhighlight( aItem, SELECTED, &m_selection );
1698 
1699  if( m_selection.Empty() )
1700  m_locked = true;
1701 }
1702 
1703 
1704 void SELECTION_TOOL::highlight( BOARD_ITEM* aItem, int aMode, PCBNEW_SELECTION* aGroup )
1705 {
1706  if( aMode == SELECTED )
1707  aItem->SetSelected();
1708  else if( aMode == BRIGHTENED )
1709  aItem->SetBrightened();
1710 
1711  if( aGroup )
1712  {
1713  // Hide the original item, so it is shown only on overlay
1714  view()->Hide( aItem, true );
1715 
1716  aGroup->Add( aItem );
1717  }
1718 
1719  // Modules are treated in a special way - when they are highlighted, we have to
1720  // highlight all the parts that make the module, not the module itself
1721  if( aItem->Type() == PCB_MODULE_T )
1722  {
1723  static_cast<MODULE*>( aItem )->RunOnChildren( [&] ( BOARD_ITEM* item )
1724  {
1725  if( aMode == SELECTED )
1726  item->SetSelected();
1727  else if( aMode == BRIGHTENED )
1728  {
1729  item->SetBrightened();
1730 
1731  if( aGroup )
1732  aGroup->Add( item );
1733  }
1734 
1735  if( aGroup )
1736  view()->Hide( item, true );
1737  });
1738  }
1739 
1740  view()->Update( aItem );
1741 
1742  // Many selections are very temporal and updating the display each time just
1743  // creates noise.
1744  if( aMode == BRIGHTENED )
1746 }
1747 
1748 
1749 void SELECTION_TOOL::unhighlight( BOARD_ITEM* aItem, int aMode, PCBNEW_SELECTION* aGroup )
1750 {
1751  if( aMode == SELECTED )
1752  aItem->ClearSelected();
1753  else if( aMode == BRIGHTENED )
1754  aItem->ClearBrightened();
1755 
1756  if( aGroup )
1757  {
1758  aGroup->Remove( aItem );
1759 
1760  // Restore original item visibility
1761  view()->Hide( aItem, false );
1762  }
1763 
1764  // Modules are treated in a special way - when they are highlighted, we have to
1765  // highlight all the parts that make the module, not the module itself
1766  if( aItem->Type() == PCB_MODULE_T )
1767  {
1768  static_cast<MODULE*>( aItem )->RunOnChildren( [&] ( BOARD_ITEM* item )
1769  {
1770  if( aMode == SELECTED )
1771  item->ClearSelected();
1772  else if( aMode == BRIGHTENED )
1773  item->ClearBrightened();
1774 
1775  // N.B. if we clear the selection flag for sub-elements, we need to also
1776  // remove the element from the selection group (if it exists)
1777  if( aGroup )
1778  {
1779  aGroup->Remove( item );
1780 
1781  view()->Hide( item, false );
1782  view()->Update( item );
1783  }
1784  });
1785  }
1786 
1787  view()->Update( aItem );
1788 
1789  // Many selections are very temporal and updating the display each time just
1790  // creates noise.
1791  if( aMode == BRIGHTENED )
1793 }
1794 
1795 
1796 bool SELECTION_TOOL::selectionContains( const VECTOR2I& aPoint ) const
1797 {
1798  const unsigned GRIP_MARGIN = 20;
1799  VECTOR2I margin = getView()->ToWorld( VECTOR2I( GRIP_MARGIN, GRIP_MARGIN ), false );
1800 
1801  // Check if the point is located within any of the currently selected items bounding boxes
1802  for( auto item : m_selection )
1803  {
1804  BOX2I itemBox = item->ViewBBox();
1805  itemBox.Inflate( margin.x, margin.y ); // Give some margin for gripping an item
1806 
1807  if( itemBox.Contains( aPoint ) )
1808  return true;
1809  }
1810 
1811  return false;
1812 }
1813 
1814 
1815 static EDA_RECT getRect( const BOARD_ITEM* aItem )
1816 {
1817  if( aItem->Type() == PCB_MODULE_T )
1818  return static_cast<const MODULE*>( aItem )->GetFootprintRect();
1819 
1820  return aItem->GetBoundingBox();
1821 }
1822 
1823 
1824 static double calcArea( const BOARD_ITEM* aItem )
1825 {
1826  if( aItem->Type() == PCB_TRACE_T )
1827  {
1828  const TRACK* t = static_cast<const TRACK*>( aItem );
1829  return ( t->GetWidth() + t->GetLength() ) * t->GetWidth();
1830  }
1831 
1832  return getRect( aItem ).GetArea();
1833 }
1834 
1835 
1836 /*static double calcMinArea( GENERAL_COLLECTOR& aCollector, KICAD_T aType )
1837 {
1838  double best = std::numeric_limits<double>::max();
1839 
1840  if( !aCollector.GetCount() )
1841  return 0.0;
1842 
1843  for( int i = 0; i < aCollector.GetCount(); i++ )
1844  {
1845  BOARD_ITEM* item = aCollector[i];
1846  if( item->Type() == aType )
1847  best = std::min( best, calcArea( item ) );
1848  }
1849 
1850  return best;
1851 }*/
1852 
1853 
1854 static double calcMaxArea( GENERAL_COLLECTOR& aCollector, KICAD_T aType )
1855 {
1856  double best = 0.0;
1857 
1858  for( int i = 0; i < aCollector.GetCount(); i++ )
1859  {
1860  BOARD_ITEM* item = aCollector[i];
1861  if( item->Type() == aType )
1862  best = std::max( best, calcArea( item ) );
1863  }
1864 
1865  return best;
1866 }
1867 
1868 
1869 static inline double calcCommonArea( const BOARD_ITEM* aItem, const BOARD_ITEM* aOther )
1870 {
1871  if( !aItem || !aOther )
1872  return 0;
1873 
1874  return getRect( aItem ).Common( getRect( aOther ) ).GetArea();
1875 }
1876 
1877 
1878 double calcRatio( double a, double b )
1879 {
1880  if( a == 0.0 && b == 0.0 )
1881  return 1.0;
1882 
1883  if( b == 0.0 )
1885 
1886  return a / b;
1887 }
1888 
1889 
1890 // The general idea here is that if the user clicks directly on a small item inside a larger
1891 // one, then they want the small item. The quintessential case of this is clicking on a pad
1892 // within a footprint, but we also apply it for text within a footprint, footprints within
1893 // larger footprints, and vias within either larger pads or longer tracks.
1894 //
1895 // These "guesses" presume there is area within the larger item to click in to select it. If
1896 // an item is mostly covered by smaller items within it, then the guesses are inappropriate as
1897 // there might not be any area left to click to select the larger item. In this case we must
1898 // leave the items in the collector and bring up a Selection Clarification menu.
1899 //
1900 // We currently check for pads and text mostly covering a footprint, but we don’t check for
1901 // smaller footprints mostly covering a larger footprint.
1902 //
1904  const VECTOR2I& aWhere ) const
1905 {
1906  std::set<BOARD_ITEM*> preferred;
1907  std::set<BOARD_ITEM*> rejected;
1908  std::set<BOARD_ITEM*> forced;
1909  wxPoint where( aWhere.x, aWhere.y );
1910 
1911  // footprints which are below this percentage of the largest footprint will be considered
1912  // for selection; all others will not
1913  constexpr double footprintToFootprintMinRatio = 0.20;
1914  // pads which are below this percentage of their parent's area will exclude their parent
1915  constexpr double padToFootprintMinRatio = 0.45;
1916  // footprints containing items with items-to-footprint area ratio higher than this will be
1917  // forced to stay on the list
1918  constexpr double footprintMaxCoverRatio = 0.80;
1919  constexpr double viaToPadMinRatio = 0.50;
1920  constexpr double trackViaLengthRatio = 2.0;
1921  constexpr double trackTrackLengthRatio = 0.3;
1922  constexpr double textToFeatureMinRatio = 0.2;
1923  constexpr double textToFootprintMinRatio = 0.4;
1924  // If the common area of two compared items is above the following threshold, they cannot
1925  // be rejected (it means they overlap and it might be hard to pick one by selecting
1926  // its unique area).
1927  constexpr double commonAreaRatio = 0.6;
1928 
1929  PCB_LAYER_ID activeLayer = (PCB_LAYER_ID) view()->GetTopLayer();
1930  LSET silkLayers( 2, B_SilkS, F_SilkS );
1931 
1932  if( silkLayers[activeLayer] )
1933  {
1934  for( int i = 0; i < aCollector.GetCount(); ++i )
1935  {
1936  BOARD_ITEM* item = aCollector[i];
1937  KICAD_T type = item->Type();
1938 
1939  if( ( type == PCB_MODULE_TEXT_T || type == PCB_TEXT_T || type == PCB_LINE_T )
1940  && silkLayers[item->GetLayer()] )
1941  {
1942  preferred.insert( item );
1943  }
1944  }
1945 
1946  if( preferred.size() > 0 )
1947  {
1948  aCollector.Empty();
1949 
1950  for( BOARD_ITEM* item : preferred )
1951  aCollector.Append( item );
1952  return;
1953  }
1954  }
1955 
1956  int numZones = aCollector.CountType( PCB_ZONE_AREA_T );
1957 
1958  // Zone edges are very specific; zone fills much less so.
1959  if( numZones > 0 )
1960  {
1961  for( int i = aCollector.GetCount() - 1; i >= 0; i-- )
1962  {
1963  if( aCollector[i]->Type() == PCB_ZONE_AREA_T )
1964  {
1965  auto zone = static_cast<ZONE_CONTAINER*>( aCollector[i] );
1966 
1967  if( zone->HitTestForEdge( where, 5 * aCollector.GetGuide()->OnePixelInIU() ) )
1968  preferred.insert( zone );
1969  else
1970  rejected.insert( zone );
1971  }
1972  }
1973 
1974  if( preferred.size() > 0 )
1975  {
1976  aCollector.Empty();
1977 
1978  for( BOARD_ITEM* item : preferred )
1979  aCollector.Append( item );
1980  return;
1981  }
1982  }
1983 
1984  if( aCollector.CountType( PCB_MODULE_TEXT_T ) > 0 )
1985  {
1986  for( int i = 0; i < aCollector.GetCount(); ++i )
1987  {
1988  if( TEXTE_MODULE* txt = dyn_cast<TEXTE_MODULE*>( aCollector[i] ) )
1989  {
1990  double textArea = calcArea( txt );
1991 
1992  for( int j = 0; j < aCollector.GetCount(); ++j )
1993  {
1994  if( i == j )
1995  continue;
1996 
1997  BOARD_ITEM* item = aCollector[j];
1998  double itemArea = calcArea( item );
1999  double areaRatio = calcRatio( textArea, itemArea );
2000  double commonArea = calcCommonArea( txt, item );
2001  double itemCommonRatio = calcRatio( commonArea, itemArea );
2002  double txtCommonRatio = calcRatio( commonArea, textArea );
2003 
2004  if( item->Type() == PCB_MODULE_T )
2005  {
2006  // when text area is small compared to an overlapping footprint,
2007  // then it's a clear sign the text is the selection target
2008  if( areaRatio < textToFootprintMinRatio && itemCommonRatio < commonAreaRatio )
2009  rejected.insert( item );
2010  }
2011 
2012  switch( item->Type() )
2013  {
2014  case PCB_TRACE_T:
2015  case PCB_PAD_T:
2016  case PCB_LINE_T:
2017  case PCB_VIA_T:
2018  case PCB_MODULE_T:
2019  if( areaRatio > textToFeatureMinRatio && txtCommonRatio < commonAreaRatio )
2020  rejected.insert( txt );
2021  break;
2022  default:
2023  break;
2024  }
2025  }
2026  }
2027  }
2028  }
2029 
2030  if( aCollector.CountType( PCB_PAD_T ) > 0 )
2031  {
2032  for( int i = 0; i < aCollector.GetCount(); ++i )
2033  {
2034  if( D_PAD* pad = dyn_cast<D_PAD*>( aCollector[i] ) )
2035  {
2036  MODULE* parent = pad->GetParent();
2037  double ratio = calcRatio( calcArea( pad ), calcArea( parent ) );
2038 
2039  // when pad area is small compared to the parent footprint,
2040  // then it is a clear sign the pad is the selection target
2041  if( ratio < padToFootprintMinRatio )
2042  rejected.insert( pad->GetParent() );
2043  }
2044  }
2045  }
2046 
2047  int moduleCount = aCollector.CountType( PCB_MODULE_T );
2048 
2049  if( moduleCount > 0 )
2050  {
2051  double maxArea = calcMaxArea( aCollector, PCB_MODULE_T );
2052  BOX2D viewportD = getView()->GetViewport();
2053  BOX2I viewport( VECTOR2I( viewportD.GetPosition() ), VECTOR2I( viewportD.GetSize() ) );
2054  double maxCoverRatio = footprintMaxCoverRatio;
2055 
2056  // MODULE::CoverageRatio() doesn't take zone handles & borders into account so just
2057  // use a more aggressive cutoff point if zones are involved.
2058  if( aCollector.CountType( PCB_ZONE_AREA_T ) )
2059  maxCoverRatio /= 2;
2060 
2061  for( int i = 0; i < aCollector.GetCount(); ++i )
2062  {
2063  if( MODULE* mod = dyn_cast<MODULE*>( aCollector[i] ) )
2064  {
2065  // filter out components larger than the viewport
2066  if( mod->ViewBBox().Contains( viewport ) )
2067  rejected.insert( mod );
2068  // footprints completely covered with other features have no other
2069  // means of selection, so must be kept
2070  else if( mod->CoverageRatio( aCollector ) > maxCoverRatio )
2071  rejected.erase( mod );
2072  // if a footprint is much smaller than the largest overlapping
2073  // footprint then it should be considered for selection
2074  else if( calcRatio( calcArea( mod ), maxArea ) <= footprintToFootprintMinRatio )
2075  continue;
2076  // if there are multiple footprints for selection at this point, prefer
2077  // one that is on the active layer
2078  else if( moduleCount > 1 && mod->GetLayer() == activeLayer )
2079  preferred.insert( mod );
2080  // reject ALL OTHER footprints if there's still something else left
2081  // to select
2082  else if( (int)( rejected.size() + 1 ) < aCollector.GetCount() )
2083  rejected.insert( mod );
2084  }
2085  }
2086  }
2087 
2088  if( aCollector.CountType( PCB_VIA_T ) > 0 )
2089  {
2090  for( int i = 0; i < aCollector.GetCount(); ++i )
2091  {
2092  if( VIA* via = dyn_cast<VIA*>( aCollector[i] ) )
2093  {
2094  double viaArea = calcArea( via );
2095 
2096  for( int j = 0; j < aCollector.GetCount(); ++j )
2097  {
2098  if( i == j )
2099  continue;
2100 
2101  BOARD_ITEM* item = aCollector[j];
2102  double areaRatio = calcRatio( viaArea, calcArea( item ) );
2103 
2104  if( item->Type() == PCB_MODULE_T && areaRatio < padToFootprintMinRatio )
2105  rejected.insert( item );
2106 
2107  if( item->Type() == PCB_PAD_T && areaRatio < viaToPadMinRatio )
2108  rejected.insert( item );
2109 
2110  if( TRACK* track = dyn_cast<TRACK*>( item ) )
2111  {
2112  if( track->GetNetCode() != via->GetNetCode() )
2113  continue;
2114 
2115  double lenRatio = (double) ( track->GetLength() + track->GetWidth() ) /
2116  (double) via->GetWidth();
2117 
2118  if( lenRatio > trackViaLengthRatio )
2119  rejected.insert( track );
2120  }
2121  }
2122  }
2123  }
2124  }
2125 
2126  int nTracks = aCollector.CountType( PCB_TRACE_T );
2127 
2128  if( nTracks > 0 )
2129  {
2130  double maxLength = 0.0;
2131  double minLength = std::numeric_limits<double>::max();
2132  double maxArea = 0.0;
2133  const TRACK* maxTrack = nullptr;
2134 
2135  for( int i = 0; i < aCollector.GetCount(); ++i )
2136  {
2137  if( TRACK* track = dyn_cast<TRACK*>( aCollector[i] ) )
2138  {
2139  maxLength = std::max( track->GetLength(), maxLength );
2140  maxLength = std::max( (double) track->GetWidth(), maxLength );
2141 
2142  minLength = std::min( std::max( track->GetLength(), (double) track->GetWidth() ), minLength );
2143 
2144  double area = track->GetLength() * track->GetWidth();
2145 
2146  if( area > maxArea )
2147  {
2148  maxArea = area;
2149  maxTrack = track;
2150  }
2151  }
2152  }
2153 
2154  if( maxLength > 0.0 && minLength / maxLength < trackTrackLengthRatio && nTracks > 1 )
2155  {
2156  for( int i = 0; i < aCollector.GetCount(); ++i )
2157  {
2158  if( TRACK* track = dyn_cast<TRACK*>( aCollector[i] ) )
2159  {
2160  double ratio = std::max( (double) track->GetWidth(), track->GetLength() ) / maxLength;
2161 
2162  if( ratio > trackTrackLengthRatio )
2163  rejected.insert( track );
2164  }
2165  }
2166  }
2167 
2168  for( int j = 0; j < aCollector.GetCount(); ++j )
2169  {
2170  if( MODULE* mod = dyn_cast<MODULE*>( aCollector[j] ) )
2171  {
2172  double ratio = calcRatio( maxArea, mod->GetFootprintRect().GetArea() );
2173 
2174  if( ratio < padToFootprintMinRatio && calcCommonArea( maxTrack, mod ) < commonAreaRatio )
2175  rejected.insert( mod );
2176  }
2177  }
2178  }
2179 
2180  if( (unsigned) aCollector.GetCount() > rejected.size() ) // do not remove everything
2181  {
2182  for( BOARD_ITEM* item : rejected )
2183  {
2184  aCollector.Remove( item );
2185  }
2186  }
2187 }
2188 
2189 
2191 {
2192  getView()->Update( &m_selection );
2193 
2194  return 0;
2195 }
2196 
2197 
2199 {
2200  ACTION_MENU* actionMenu = aEvent.Parameter<ACTION_MENU*>();
2201  CONDITIONAL_MENU* conditionalMenu = dynamic_cast<CONDITIONAL_MENU*>( actionMenu );
2202 
2203  if( conditionalMenu )
2204  conditionalMenu->Evaluate( m_selection );
2205 
2206  if( actionMenu )
2207  actionMenu->UpdateAll();
2208 
2209  return 0;
2210 }
2211 
2212 
2214 {
2216 
2220 
2226 
2227  Go( &SELECTION_TOOL::find, ACTIONS::find.MakeEvent() );
2228 
2237 }
2238 
2239 
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:458
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:479
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
virtual unsigned int ViewGetLOD(int aLayer, VIEW *aView) const
Function ViewGetLOD() Returns the level of detail (LOD) of the item.
Definition: view_item.h:140
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:101
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:125
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:176
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:186
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()
const PCB_DISPLAY_OPTIONS & GetDisplayOptions() const
Function GetDisplayOptions returns the display options current in use Display options are relative to...
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
bool Contains(const wxPoint &aPoint) const
Function Contains.
void Remove(int aIndex)
Function Remove removes the item at aIndex (first position is 0);.
Definition: collector.h: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:96
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...
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:435
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:171
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:301
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
void RemoveItemFromSel(BOARD_ITEM *aItem, bool aQuietMode=false)
bool Init() override
Function Init() Init() is called once upon a registration of the tool.
EDA_ITEM * GetParent() const
Definition: base_struct.h: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:99
#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:421
const MODULE_ZONE_CONTAINERS & Zones() const
Definition: class_module.h:191
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:100
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:408
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:450
class MARKER_PCB, a marker used to show something
Definition: typeinfo.h:98
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:649
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:97
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
EDA_RECT GetBoundingBox() const
Definition: selection.h:154
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