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