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