KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pcb_selection_tool.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2013-2017 CERN
5 * Copyright (C) 2018-2024 KiCad Developers, see AUTHORS.txt for contributors.
6 * @author Tomasz Wlostowski <[email protected]>
7 * @author Maciej Suminski <[email protected]>
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 <cmath>
29#include <functional>
30#include <stack>
31using namespace std::placeholders;
32
33#include <advanced_config.h>
34#include <macros.h>
35#include <core/kicad_algo.h>
36#include <board.h>
38#include <board_item.h>
39#include <clipper.hpp>
40#include <pcb_reference_image.h>
41#include <pcb_track.h>
42#include <footprint.h>
43#include <pad.h>
44#include <pcb_group.h>
45#include <pcb_shape.h>
46#include <pcb_text.h>
47#include <pcb_textbox.h>
48#include <pcb_table.h>
49#include <pcb_tablecell.h>
50#include <pcb_marker.h>
51#include <pcb_generator.h>
52#include <zone.h>
53#include <collectors.h>
57#include <view/view_controls.h>
59#include <gal/painter.h>
60#include <router/router_tool.h>
61#include <pcbnew_settings.h>
62#include <tool/tool_event.h>
63#include <tool/tool_manager.h>
67#include <tools/pcb_actions.h>
72#include <wx/event.h>
73#include <wx/timer.h>
74#include <wx/log.h>
75#include <wx/debug.h>
76#include <core/profile.h>
77#include <math/vector2wx.h>
78
79
81{
83 double m_Opacity;
85};
86
87
89{
90public:
92 ACTION_MENU( true )
93 {
94 SetTitle( _( "Select" ) );
95
97
98 AppendSeparator();
99
102
103 // This could be enabled if we have better logic for picking the target net with the mouse
104 // Add( PCB_ACTIONS::deselectNet );
107
110 }
111
112private:
113 ACTION_MENU* create() const override
114 {
115 return new SELECT_MENU();
116 }
117};
118
119
124{
125public:
127};
128
129
131 SELECTION_TOOL( "pcbnew.InteractiveSelection" ),
132 m_frame( nullptr ),
133 m_isFootprintEditor( false ),
134 m_nonModifiedCursor( KICURSOR::ARROW ),
135 m_enteredGroup( nullptr ),
136 m_priv( std::make_unique<PRIV>() )
137{
138 m_filter.lockedItems = false;
139 m_filter.footprints = true;
140 m_filter.text = true;
141 m_filter.tracks = true;
142 m_filter.vias = true;
143 m_filter.pads = true;
144 m_filter.graphics = true;
145 m_filter.zones = true;
146 m_filter.keepouts = true;
147 m_filter.dimensions = true;
148 m_filter.otherItems = true;
149}
150
151
153{
156
157 Disconnect( wxEVT_TIMER, wxTimerEventHandler( PCB_SELECTION_TOOL::onDisambiguationExpire ),
158 nullptr, this );
159}
160
161
163{
164 PCB_BASE_FRAME* frame = getEditFrame<PCB_BASE_FRAME>();
165
167 {
169 return true;
170 }
171
172 std::shared_ptr<SELECT_MENU> selectMenu = std::make_shared<SELECT_MENU>();
173 selectMenu->SetTool( this );
174 m_menu->RegisterSubMenu( selectMenu );
175
176 static const std::vector<KICAD_T> tableCellTypes = { PCB_TABLECELL_T };
177
178 auto& menu = m_menu->GetMenu();
179
180 auto activeToolCondition =
181 [ frame ] ( const SELECTION& aSel )
182 {
183 return !frame->ToolStackIsEmpty();
184 };
185
186 auto haveHighlight =
187 [&]( const SELECTION& sel )
188 {
190
191 return !cfg->GetHighlightNetCodes().empty();
192 };
193
194 auto groupEnterCondition =
196
197 auto inGroupCondition =
198 [this] ( const SELECTION& )
199 {
200 return m_enteredGroup != nullptr;
201 };
202
203 auto tableCellSelection = SELECTION_CONDITIONS::MoreThan( 0 )
205
207 {
208 menu.AddMenu( selectMenu.get(), SELECTION_CONDITIONS::NotEmpty );
209 menu.AddSeparator( 1000 );
210 }
211
212 // "Cancel" goes at the top of the context menu when a tool is active
213 menu.AddItem( ACTIONS::cancelInteractive, activeToolCondition, 1 );
214 menu.AddItem( PCB_ACTIONS::groupEnter, groupEnterCondition, 1 );
215 menu.AddItem( PCB_ACTIONS::groupLeave, inGroupCondition, 1 );
216 menu.AddItem( PCB_ACTIONS::clearHighlight, haveHighlight, 1 );
217 menu.AddSeparator( haveHighlight, 1 );
218
219 menu.AddItem( ACTIONS::selectColumns, tableCellSelection, 2 );
220 menu.AddItem( ACTIONS::selectRows, tableCellSelection, 2 );
221 menu.AddItem( ACTIONS::selectTable, tableCellSelection, 2 );
222
223 menu.AddSeparator( 1 );
224
225 if( frame )
227
228 m_disambiguateTimer.SetOwner( this );
229 Connect( wxEVT_TIMER, wxTimerEventHandler( PCB_SELECTION_TOOL::onDisambiguationExpire ),
230 nullptr, this );
231
232 return true;
233}
234
235
237{
238 m_frame = getEditFrame<PCB_BASE_FRAME>();
240
241 if( aReason != TOOL_BASE::REDRAW )
242 {
243 if( m_enteredGroup )
244 ExitGroup();
245
246 // Deselect any item being currently in edit, to avoid unexpected behavior and remove
247 // pointers to the selected items from containers.
248 ClearSelection( true );
249 }
250
251 if( aReason == TOOL_BASE::MODEL_RELOAD )
252 getView()->GetPainter()->GetSettings()->SetHighlight( false );
253
254 // Reinsert the VIEW_GROUP, in case it was removed from the VIEW
255 view()->Remove( &m_selection );
256 view()->Add( &m_selection );
257
260}
261
262
263void PCB_SELECTION_TOOL::OnIdle( wxIdleEvent& aEvent )
264{
266 {
267 wxMouseState keyboardState = wxGetMouseState();
268
269 setModifiersState( keyboardState.ShiftDown(), keyboardState.ControlDown(),
270 keyboardState.AltDown() );
271
272 if( m_additive )
273 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ADD );
274 else if( m_subtractive )
275 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::SUBTRACT );
276 else if( m_exclusive_or )
277 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::XOR );
278 else
280 }
281}
282
283
285{
286 // Main loop: keep receiving events
287 while( TOOL_EVENT* evt = Wait() )
288 {
290 TRACK_DRAG_ACTION trackDragAction = TRACK_DRAG_ACTION::MOVE;
291
292 try
293 {
294 trackDragAction = m_frame->GetPcbNewSettings()->m_TrackDragAction;
295 }
296 catch( const std::runtime_error& e )
297 {
298 wxFAIL_MSG( e.what() );
299 }
300
301 // on left click, a selection is made, depending on modifiers ALT, SHIFT, CTRL:
302 setModifiersState( evt->Modifier( MD_SHIFT ), evt->Modifier( MD_CTRL ),
303 evt->Modifier( MD_ALT ) );
304
305 PCB_BASE_FRAME* frame = getEditFrame<PCB_BASE_FRAME>();
306 bool brd_editor = frame && frame->IsType( FRAME_PCB_EDITOR );
308
309 // If the router tool is active, don't override
310 if( router && router->IsToolActive() && router->RoutingInProgress() )
311 {
312 evt->SetPassEvent();
313 }
314 else if( evt->IsMouseDown( BUT_LEFT ) )
315 {
316 // Avoid triggering when running under other tools
318
319 if( m_frame->ToolStackIsEmpty() && pt_tool && !pt_tool->HasPoint() )
320 {
323 }
324 }
325 else if( evt->IsClick( BUT_LEFT ) )
326 {
327 // If there is no disambiguation, this routine is still running and will
328 // register a `click` event when released
329 if( m_disambiguateTimer.IsRunning() )
330 {
331 m_disambiguateTimer.Stop();
332
333 // Single click? Select single object
334 if( m_highlight_modifier && brd_editor )
335 {
337 }
338 else
339 {
340 m_frame->FocusOnItem( nullptr );
341 selectPoint( evt->Position() );
342 }
343 }
344
345 m_canceledMenu = false;
346 }
347 else if( evt->IsClick( BUT_RIGHT ) )
348 {
349 m_disambiguateTimer.Stop();
350
351 // Right click? if there is any object - show the context menu
352 bool selectionCancelled = false;
353
354 if( m_selection.Empty() )
355 {
356 selectPoint( evt->Position(), false, &selectionCancelled );
357 m_selection.SetIsHover( true );
358 }
359
360 // Show selection before opening menu
362
363 if( !selectionCancelled )
364 {
366 m_menu->ShowContextMenu( m_selection );
367 }
368 }
369 else if( evt->IsDblClick( BUT_LEFT ) )
370 {
371 m_disambiguateTimer.Stop();
372
373 // Double clicks make no sense in the footprint viewer
375 {
376 evt->SetPassEvent();
377 continue;
378 }
379
380 // Double click? Display the properties window
381 m_frame->FocusOnItem( nullptr );
382
383 if( m_selection.Empty() )
384 selectPoint( evt->Position() );
385
386 if( m_selection.GetSize() == 1 && m_selection[0]->Type() == PCB_GROUP_T )
387 EnterGroup();
388 else
390 }
391 else if( evt->IsDblClick( BUT_MIDDLE ) )
392 {
393 // Middle double click? Do zoom to fit or zoom to objects
394 if( evt->Modifier( MD_CTRL ) ) // Is CTRL key down?
396 else
398 }
399 else if( evt->Action() == TA_MOUSE_WHEEL )
400 {
401 int field = -1;
402
403 if( evt->Modifier() == ( MD_SHIFT | MD_ALT ) )
404 field = 0;
405 else if( evt->Modifier() == ( MD_CTRL | MD_ALT ) )
406 field = 1;
407 // any more?
408
409 if( field >= 0 )
410 {
411 const int delta = evt->Parameter<int>();
412 ACTIONS::INCREMENT incParams{
413 delta > 0 ? 1 : -1,
414 field,
415 };
416
418 }
419 }
420 else if( evt->IsDrag( BUT_LEFT ) )
421 {
422 m_disambiguateTimer.Stop();
423
424 // Is another tool already moving a new object? Don't allow a drag start
425 if( !m_selection.Empty() && m_selection[0]->HasFlag( IS_NEW | IS_MOVING ) )
426 {
427 evt->SetPassEvent();
428 continue;
429 }
430
431 // Drag with LMB? Select multiple objects (or at least draw a selection box)
432 // or drag them
433 m_frame->FocusOnItem( nullptr );
435
437 GENERAL_COLLECTOR collector;
438
440 {
441 if( board()->GetFirstFootprint() )
442 {
443 collector.Collect( board()->GetFirstFootprint(), { PCB_TABLECELL_T },
444 evt->DragOrigin(), guide );
445 }
446 }
447 else
448 {
449 collector.Collect( board(), { PCB_TABLECELL_T }, evt->DragOrigin(), guide );
450 }
451
452 if( collector.GetCount() )
453 {
454 if( m_selection.GetSize() == 1 && dynamic_cast<PCB_TABLE*>( m_selection.GetItem( 0 ) ) )
455 {
457 }
458 else
459 {
460 selectTableCells( static_cast<PCB_TABLE*>( collector[0]->GetParent() ) );
461 }
462 }
463 else if( hasModifier() || dragAction == MOUSE_DRAG_ACTION::SELECT )
464 {
466 }
467 else if( m_selection.Empty() && dragAction != MOUSE_DRAG_ACTION::DRAG_ANY )
468 {
470 }
471 else
472 {
473 // Don't allow starting a drag from a zone filled area that isn't already selected
474 auto zoneFilledAreaFilter =
475 []( const VECTOR2I& aWhere, GENERAL_COLLECTOR& aCollector,
476 PCB_SELECTION_TOOL* aTool )
477 {
478 int accuracy = aCollector.GetGuide()->Accuracy();
479 std::set<EDA_ITEM*> remove;
480
481 for( EDA_ITEM* item : aCollector )
482 {
483 if( item->Type() == PCB_ZONE_T )
484 {
485 ZONE* zone = static_cast<ZONE*>( item );
486
487 if( !zone->HitTestForCorner( aWhere, accuracy * 2 )
488 && !zone->HitTestForEdge( aWhere, accuracy ) )
489 {
490 remove.insert( zone );
491 }
492 }
493 }
494
495 for( EDA_ITEM* item : remove )
496 aCollector.Remove( item );
497 };
498
499 // See if we can drag before falling back to selectMultiple()
500 bool doDrag = false;
501
502 if( evt->HasPosition() )
503 {
504 if( m_selection.Empty()
505 && selectPoint( evt->DragOrigin(), false, nullptr, zoneFilledAreaFilter ) )
506 {
507 m_selection.SetIsHover( true );
508 doDrag = true;
509 }
510 // Check if dragging has started within any of selected items bounding box.
511 else if( selectionContains( evt->DragOrigin() ) )
512 {
513 doDrag = true;
514 }
515 }
516
517 if( doDrag )
518 {
519 bool haveTrack = m_selection.GetSize() >= 1 && ( m_selection.CountType( PCB_TRACE_T ) ||
522
523 if( haveTrack && trackDragAction == TRACK_DRAG_ACTION::DRAG )
525 else if( haveTrack && trackDragAction == TRACK_DRAG_ACTION::DRAG_FREE_ANGLE )
527 else
529 }
530 else
531 {
532 // Otherwise drag a selection box
534 }
535 }
536 }
537 else if( evt->IsCancel() )
538 {
539 m_disambiguateTimer.Stop();
540 m_frame->FocusOnItem( nullptr );
541
542 if( !GetSelection().Empty() )
543 {
545 }
546 else if( evt->FirstResponder() == this && evt->GetCommandId() == (int) WXK_ESCAPE )
547 {
548 if( m_enteredGroup )
549 {
550 ExitGroup();
551 }
552 else
553 {
555
556 try
557 {
559 controller->ClearHighlight( *evt );
560 }
561 catch( const std::runtime_error& e )
562 {
563 wxCHECK_MSG( false, 0, e.what() );
564 }
565 }
566 }
567 }
568 else
569 {
570 evt->SetPassEvent();
571 }
572
573
575 {
576 // move cursor prediction
577 if( !hasModifier()
578 && dragAction == MOUSE_DRAG_ACTION::DRAG_SELECTED
579 && !m_selection.Empty()
580 && evt->HasPosition()
581 && selectionContains( evt->Position() ) )
582 {
583 m_nonModifiedCursor = KICURSOR::MOVING;
584 }
585 else
586 {
587 m_nonModifiedCursor = KICURSOR::ARROW;
588 }
589 }
590 }
591
592 // Shutting down; clear the selection
594 m_disambiguateTimer.Stop();
595
596 return 0;
597}
598
599
601{
602 wxCHECK_RET( m_selection.GetSize() == 1 && m_selection[0]->Type() == PCB_GROUP_T,
603 wxT( "EnterGroup called when selection is not a single group" ) );
604 PCB_GROUP* aGroup = static_cast<PCB_GROUP*>( m_selection[0] );
605
606 if( m_enteredGroup != nullptr )
607 ExitGroup();
608
610 m_enteredGroup = aGroup;
613 {
614 select( titem );
615 } );
616
618
619 view()->Hide( m_enteredGroup, true );
622}
623
624
625void PCB_SELECTION_TOOL::ExitGroup( bool aSelectGroup )
626{
627 // Only continue if there is a group entered
628 if( m_enteredGroup == nullptr )
629 return;
630
632 view()->Hide( m_enteredGroup, false );
634
635 if( aSelectGroup )
636 {
639 }
640
642 m_enteredGroup = nullptr;
644}
645
646
648{
649 return m_selection;
650}
651
652
654 bool aConfirmLockedItems )
655{
656 bool selectionEmpty = m_selection.Empty();
657 m_selection.SetIsHover( selectionEmpty );
658
659 if( selectionEmpty )
660 {
663 }
664
665 if( aClientFilter )
666 {
667 enum DISPOSITION { BEFORE = 1, AFTER, BOTH };
668
669 std::map<EDA_ITEM*, DISPOSITION> itemDispositions;
671 GENERAL_COLLECTOR collector;
672
673 collector.SetGuide( &guide );
674
675 for( EDA_ITEM* item : m_selection )
676 {
677 collector.Append( item );
678 itemDispositions[ item ] = BEFORE;
679 }
680
681 aClientFilter( VECTOR2I(), collector, this );
682
683 for( EDA_ITEM* item : collector )
684 {
685 if( itemDispositions.count( item ) )
686 itemDispositions[ item ] = BOTH;
687 else
688 itemDispositions[ item ] = AFTER;
689 }
690
691 // Unhighlight the BEFORE items before highlighting the AFTER items.
692 // This is so that in the case of groups, if aClientFilter replaces a selection
693 // with the enclosing group, the unhighlight of the element doesn't undo the
694 // recursive highlighting of that element by the group.
695
696 for( std::pair<EDA_ITEM* const, DISPOSITION> itemDisposition : itemDispositions )
697 {
698 EDA_ITEM* item = itemDisposition.first;
699 DISPOSITION disposition = itemDisposition.second;
700
701 if( disposition == BEFORE )
703 }
704
705 for( std::pair<EDA_ITEM* const, DISPOSITION> itemDisposition : itemDispositions )
706 {
707 EDA_ITEM* item = itemDisposition.first;
708 DISPOSITION disposition = itemDisposition.second;
709
710 // Note that we must re-highlight even previously-highlighted items
711 // (ie: disposition BOTH) in case we removed any of their children.
712 if( disposition == AFTER || disposition == BOTH )
713 highlight( item, SELECTED, &m_selection );
714 }
715
717 }
718
719 if( aConfirmLockedItems )
720 {
721 std::vector<BOARD_ITEM*> lockedItems;
722
723 for( EDA_ITEM* item : m_selection )
724 {
725 BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( item );
726 bool lockedDescendant = false;
727
728 boardItem->RunOnDescendants(
729 [&]( BOARD_ITEM* curr_item )
730 {
731 if( curr_item->IsLocked() )
732 lockedDescendant = true;
733 } );
734
735 if( boardItem->IsLocked() || lockedDescendant )
736 lockedItems.push_back( boardItem );
737 }
738
740 if( !lockedItems.empty() && !settings->m_LockingOptions.m_sessionSkipPrompts )
741 {
742 DIALOG_LOCKED_ITEMS_QUERY dlg( frame(), lockedItems.size(),
743 settings->m_LockingOptions );
744
745 switch( dlg.ShowModal() )
746 {
747 case wxID_OK:
748 // remove locked items from selection
749 for( BOARD_ITEM* item : lockedItems )
750 unselect( item );
751
752 break;
753
754 case wxID_CANCEL:
755 // cancel operation
757 break;
758
759 case wxID_APPLY:
760 // continue with operation with current selection
761 break;
762 }
763 }
764 }
765
766 return m_selection;
767}
768
769
771{
772 GENERAL_COLLECTORS_GUIDE guide( board()->GetVisibleLayers(),
773 (PCB_LAYER_ID) view()->GetTopLayer(), view() );
774
775 bool padsDisabled = !board()->IsElementVisible( LAYER_PADS );
776
777 // account for the globals
778 guide.SetIgnoreFPTextOnBack( !board()->IsElementVisible( LAYER_FP_TEXT ) );
779 guide.SetIgnoreFPTextOnFront( !board()->IsElementVisible( LAYER_FP_TEXT ) );
780 guide.SetIgnoreFootprintsOnBack( !board()->IsElementVisible( LAYER_FOOTPRINTS_BK ) );
781 guide.SetIgnoreFootprintsOnFront( !board()->IsElementVisible( LAYER_FOOTPRINTS_FR ) );
782 guide.SetIgnorePadsOnBack( padsDisabled );
783 guide.SetIgnorePadsOnFront( padsDisabled );
784 guide.SetIgnoreThroughHolePads( padsDisabled );
785 guide.SetIgnoreFPValues( !board()->IsElementVisible( LAYER_FP_VALUES ) );
786 guide.SetIgnoreFPReferences( !board()->IsElementVisible( LAYER_FP_REFERENCES ) );
787 guide.SetIgnoreThroughVias( ! board()->IsElementVisible( LAYER_VIAS ) );
788 guide.SetIgnoreBlindBuriedVias( ! board()->IsElementVisible( LAYER_VIAS ) );
789 guide.SetIgnoreMicroVias( ! board()->IsElementVisible( LAYER_VIAS ) );
790 guide.SetIgnoreTracks( ! board()->IsElementVisible( LAYER_TRACKS ) );
791
792 return guide;
793}
794
795
797{
799}
800
801
802bool PCB_SELECTION_TOOL::selectPoint( const VECTOR2I& aWhere, bool aOnDrag,
803 bool* aSelectionCancelledFlag,
804 CLIENT_SELECTION_FILTER aClientFilter )
805{
807 GENERAL_COLLECTOR collector;
808 const PCB_DISPLAY_OPTIONS& displayOpts = m_frame->GetDisplayOptions();
809
810 guide.SetIgnoreZoneFills( displayOpts.m_ZoneDisplayMode != ZONE_DISPLAY_MODE::SHOW_FILLED );
811
813 ExitGroup();
814
817 aWhere, guide );
818
819 // Remove unselectable items
820 for( int i = collector.GetCount() - 1; i >= 0; --i )
821 {
822 if( !Selectable( collector[ i ] ) || ( aOnDrag && collector[i]->IsLocked() ) )
823 collector.Remove( i );
824 }
825
827
828 // Apply the stateful filter (remove items disabled by the Selection Filter)
829 FilterCollectedItems( collector, false );
830
831 // Allow the client to do tool- or action-specific filtering to see if we can get down
832 // to a single item
833 if( aClientFilter )
834 aClientFilter( aWhere, collector, this );
835
836 FilterCollectorForHierarchy( collector, false );
837
838 FilterCollectorForFootprints( collector, aWhere );
839
840 // For subtracting, we only want items that are selected
841 if( m_subtractive )
842 {
843 for( int i = collector.GetCount() - 1; i >= 0; --i )
844 {
845 if( !collector[i]->IsSelected() )
846 collector.Remove( i );
847 }
848 }
849
850 // Apply some ugly heuristics to avoid disambiguation menus whenever possible
851 if( collector.GetCount() > 1 && !m_skip_heuristics )
852 {
853 try
854 {
855 GuessSelectionCandidates( collector, aWhere );
856 }
857 catch( const std::exception& exc )
858 {
859 wxLogWarning( wxS( "Exception \"%s\" occurred attempting to guess selection "
860 "candidates." ), exc.what() );
861 return false;
862 }
863 }
864
865 // If still more than one item we're going to have to ask the user.
866 if( collector.GetCount() > 1 )
867 {
868 if( aOnDrag )
870
871 if( !doSelectionMenu( &collector ) )
872 {
873 if( aSelectionCancelledFlag )
874 *aSelectionCancelledFlag = true;
875
876 return false;
877 }
878 }
879
880 int addedCount = 0;
881 bool anySubtracted = false;
882
884 {
885 if( m_selection.GetSize() > 0 )
886 {
887 ClearSelection( true /*quiet mode*/ );
888 anySubtracted = true;
889 }
890 }
891
892 if( collector.GetCount() > 0 )
893 {
894 for( int i = 0; i < collector.GetCount(); ++i )
895 {
896 if( m_subtractive || ( m_exclusive_or && collector[i]->IsSelected() ) )
897 {
898 unselect( collector[i] );
899 anySubtracted = true;
900 }
901 else
902 {
903 select( collector[i] );
904 addedCount++;
905 }
906 }
907 }
908
909 if( addedCount == 1 )
910 {
912 return true;
913 }
914 else if( addedCount > 1 )
915 {
917 return true;
918 }
919 else if( anySubtracted )
920 {
922 return true;
923 }
924
925 return false;
926}
927
928
929bool PCB_SELECTION_TOOL::selectCursor( bool aForceSelect, CLIENT_SELECTION_FILTER aClientFilter )
930{
931 if( aForceSelect || m_selection.Empty() )
932 {
933 ClearSelection( true /*quiet mode*/ );
934 selectPoint( getViewControls()->GetCursorPosition( false ), false, nullptr, aClientFilter );
935 }
936
937 return !m_selection.Empty();
938}
939
940
941// Some navigation actions are allowed in selectMultiple
951 &ACTIONS::zoomFitObjects, nullptr };
952
953
955{
956 bool cancelled = false; // Was the tool canceled while it was running?
957 m_multiple = true; // Multiple selection mode is active
958
959 for( PCB_TABLECELL* cell : aTable->GetCells() )
960 {
961 if( cell->IsSelected() )
962 cell->SetFlags( CANDIDATE );
963 else
964 cell->ClearFlags( CANDIDATE );
965 }
966
967 auto wasSelected =
968 []( EDA_ITEM* aItem )
969 {
970 return ( aItem->GetFlags() & CANDIDATE ) > 0;
971 };
972
973 while( TOOL_EVENT* evt = Wait() )
974 {
975 if( evt->IsCancelInteractive() || evt->IsActivate() )
976 {
977 cancelled = true;
978 break;
979 }
980 else if( evt->IsDrag( BUT_LEFT ) )
981 {
982 getViewControls()->SetAutoPan( true );
983
984 BOX2I selectionRect( evt->DragOrigin(), evt->Position() - evt->DragOrigin() );
985 selectionRect.Normalize();
986
987 for( PCB_TABLECELL* cell : aTable->GetCells() )
988 {
989 bool doSelect = false;
990
991 if( cell->HitTest( selectionRect, false ) )
992 {
993 if( m_subtractive )
994 doSelect = false;
995 else if( m_exclusive_or )
996 doSelect = !wasSelected( cell );
997 else
998 doSelect = true;
999 }
1000 else if( wasSelected( cell ) )
1001 {
1002 doSelect = m_additive || m_subtractive || m_exclusive_or;
1003 }
1004
1005 if( doSelect && !cell->IsSelected() )
1006 select( cell );
1007 else if( !doSelect && cell->IsSelected() )
1008 unselect( cell );
1009 }
1010 }
1011 else if( evt->IsMouseUp( BUT_LEFT ) )
1012 {
1013 m_selection.SetIsHover( false );
1014
1015 bool anyAdded = false;
1016 bool anySubtracted = false;
1017
1018 for( PCB_TABLECELL* cell : aTable->GetCells() )
1019 {
1020 if( cell->IsSelected() && !wasSelected( cell ) )
1021 anyAdded = true;
1022 else if( wasSelected( cell ) && !cell->IsSelected() )
1023 anySubtracted = true;
1024 }
1025
1026 // Inform other potentially interested tools
1027 if( anyAdded )
1029
1030 if( anySubtracted )
1032
1033 break; // Stop waiting for events
1034 }
1035 else
1036 {
1037 // Allow some actions for navigation
1038 for( int i = 0; allowedActions[i]; ++i )
1039 {
1040 if( evt->IsAction( allowedActions[i] ) )
1041 {
1042 evt->SetPassEvent();
1043 break;
1044 }
1045 }
1046 }
1047 }
1048
1049 getViewControls()->SetAutoPan( false );
1050
1051 m_multiple = false; // Multiple selection mode is inactive
1052
1053 if( !cancelled )
1055
1056 return cancelled;
1057}
1058
1059
1061{
1062 bool cancelled = false; // Was the tool canceled while it was running?
1063 m_multiple = true; // Multiple selection mode is active
1065
1067 view->Add( &area );
1068
1069 bool anyAdded = false;
1070 bool anySubtracted = false;
1071
1072 while( TOOL_EVENT* evt = Wait() )
1073 {
1074 int width = area.GetEnd().x - area.GetOrigin().x;
1075
1076 /* Selection mode depends on direction of drag-selection:
1077 * Left > Right : Select objects that are fully enclosed by selection
1078 * Right > Left : Select objects that are crossed by selection
1079 */
1080 bool greedySelection = width >= 0 ? false : true;
1081
1082 if( view->IsMirroredX() )
1083 greedySelection = !greedySelection;
1084
1085 m_frame->GetCanvas()->SetCurrentCursor( !greedySelection ? KICURSOR::SELECT_WINDOW
1086 : KICURSOR::SELECT_LASSO );
1087
1088 if( evt->IsCancelInteractive() || evt->IsActivate() )
1089 {
1090 cancelled = true;
1091 break;
1092 }
1093
1094 if( evt->IsDrag( BUT_LEFT ) )
1095 {
1097 {
1098 if( m_selection.GetSize() > 0 )
1099 {
1100 anySubtracted = true;
1101 ClearSelection( true /*quiet mode*/ );
1102 }
1103 }
1104
1105 // Start drawing a selection box
1106 area.SetOrigin( evt->DragOrigin() );
1107 area.SetEnd( evt->Position() );
1110 area.SetExclusiveOr( false );
1111
1112 view->SetVisible( &area, true );
1113 view->Update( &area );
1114 getViewControls()->SetAutoPan( true );
1115 }
1116
1117 if( evt->IsMouseUp( BUT_LEFT ) )
1118 {
1119 getViewControls()->SetAutoPan( false );
1120
1121 // End drawing the selection box
1122 view->SetVisible( &area, false );
1123
1124 std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> candidates;
1125 BOX2I selectionBox = area.ViewBBox();
1126 view->Query( selectionBox, candidates ); // Get the list of nearby items
1127
1128 int height = area.GetEnd().y - area.GetOrigin().y;
1129
1130 // Construct a BOX2I to determine BOARD_ITEM selection
1131 BOX2I selectionRect( area.GetOrigin(), VECTOR2I( width, height ) );
1132
1133 selectionRect.Normalize();
1134
1135 GENERAL_COLLECTOR collector;
1136 GENERAL_COLLECTOR padsCollector;
1137 std::set<BOARD_ITEM*> group_items;
1138
1139 for( PCB_GROUP* group : board()->Groups() )
1140 {
1141 // The currently entered group does not get limited
1142 if( m_enteredGroup == group )
1143 continue;
1144
1145 std::unordered_set<BOARD_ITEM*>& newset = group->GetItems();
1146
1147 // If we are not greedy and have selected the whole group, add just one item
1148 // to allow it to be promoted to the group later
1149 if( !greedySelection && selectionRect.Contains( group->GetBoundingBox() )
1150 && newset.size() )
1151 {
1152 for( BOARD_ITEM* group_item : newset )
1153 {
1154 if( Selectable( group_item ) )
1155 collector.Append( *newset.begin() );
1156 }
1157 }
1158
1159 for( BOARD_ITEM* group_item : newset )
1160 group_items.emplace( group_item );
1161 }
1162
1163 for( const KIGFX::VIEW::LAYER_ITEM_PAIR& candidate : candidates )
1164 {
1165 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( candidate.first );
1166
1167
1168 if( item && Selectable( item ) && item->HitTest( selectionRect, !greedySelection )
1169 && ( greedySelection || !group_items.count( item ) ) )
1170 {
1171 if( item->Type() == PCB_PAD_T && !m_isFootprintEditor )
1172 padsCollector.Append( item );
1173 else
1174 collector.Append( item );
1175 }
1176 }
1177
1178 // Apply the stateful filter
1179 FilterCollectedItems( collector, true );
1180
1181 FilterCollectorForHierarchy( collector, true );
1182
1183 // If we selected nothing but pads, allow them to be selected
1184 if( collector.GetCount() == 0 )
1185 {
1186 collector = padsCollector;
1187 FilterCollectedItems( collector, true );
1188 FilterCollectorForHierarchy( collector, true );
1189 }
1190
1191 for( EDA_ITEM* i : collector )
1192 {
1193 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( i );
1194
1195 if( m_subtractive || ( m_exclusive_or && item->IsSelected() ) )
1196 {
1197 unselect( item );
1198 anySubtracted = true;
1199 }
1200 else
1201 {
1202 select( item );
1203 anyAdded = true;
1204 }
1205 }
1206
1207 m_selection.SetIsHover( false );
1208
1209 // Inform other potentially interested tools
1210 if( anyAdded )
1212 else if( anySubtracted )
1214
1215 break; // Stop waiting for events
1216 }
1217
1218 // Allow some actions for navigation
1219 for( int i = 0; allowedActions[i]; ++i )
1220 {
1221 if( evt->IsAction( allowedActions[i] ) )
1222 {
1223 evt->SetPassEvent();
1224 break;
1225 }
1226 }
1227 }
1228
1229 getViewControls()->SetAutoPan( false );
1230
1231 // Stop drawing the selection box
1232 view->Remove( &area );
1233 m_multiple = false; // Multiple selection mode is inactive
1234
1235 if( !cancelled )
1237
1239
1240 return cancelled;
1241}
1242
1243
1245{
1246 wxMouseState keyboardState = wxGetMouseState();
1247
1248 setModifiersState( keyboardState.ShiftDown(), keyboardState.ControlDown(),
1249 keyboardState.AltDown() );
1250
1251 m_skip_heuristics = true;
1253 m_skip_heuristics = false;
1254
1255 return 0;
1256}
1257
1258
1259
1261{
1263
1264 selectCursor( false, aClientFilter );
1265
1266 return 0;
1267}
1268
1269
1271{
1273
1274 return 0;
1275}
1276
1277
1279{
1280 GENERAL_COLLECTOR collection;
1281 BOX2I selectionBox;
1282
1283 selectionBox.SetMaximum();
1284
1285 getView()->Query( selectionBox,
1286 [&]( KIGFX::VIEW_ITEM* viewItem ) -> bool
1287 {
1288 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( viewItem );
1289
1290 if( !item || !Selectable( item ) || !itemPassesFilter( item, true ) )
1291 return true;
1292
1293 collection.Append( item );
1294 return true;
1295 } );
1296
1297 FilterCollectorForHierarchy( collection, true );
1298
1299 for( EDA_ITEM* item : collection )
1300 select( item );
1301
1303
1305
1306 return 0;
1307}
1308
1309
1311{
1312 BOX2I selectionBox;
1313
1314 selectionBox.SetMaximum();
1315
1316 getView()->Query( selectionBox,
1317 [&]( KIGFX::VIEW_ITEM* viewItem ) -> bool
1318 {
1319 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( viewItem );
1320
1321 if( !item || !Selectable( item ) )
1322 return true;
1323
1324 unselect( item );
1325 return true;
1326 } );
1327
1329
1331
1332 return 0;
1333}
1334
1335
1337 PCB_SELECTION_TOOL* sTool )
1338{
1339 // Narrow the collection down to a single BOARD_CONNECTED_ITEM for each represented net.
1340 // All other items types are removed.
1341 std::set<int> representedNets;
1342
1343 for( int i = aCollector.GetCount() - 1; i >= 0; i-- )
1344 {
1345 BOARD_CONNECTED_ITEM* item = dynamic_cast<BOARD_CONNECTED_ITEM*>( aCollector[i] );
1346
1347 if( !item )
1348 aCollector.Remove( i );
1349 else if ( representedNets.count( item->GetNetCode() ) )
1350 aCollector.Remove( i );
1351 else
1352 representedNets.insert( item->GetNetCode() );
1353 }
1354}
1355
1356
1358{
1359 std::deque<EDA_ITEM*> selectedItems = m_selection.GetItems();
1360
1361 // Get all footprints and pads
1362 std::vector<BOARD_CONNECTED_ITEM*> toUnroute;
1363
1364 for( EDA_ITEM* item : selectedItems )
1365 {
1366 if( item->Type() == PCB_FOOTPRINT_T )
1367 {
1368 for( PAD* pad : static_cast<FOOTPRINT*>( item )->Pads() )
1369 toUnroute.push_back( pad );
1370 }
1371 else if( BOARD_CONNECTED_ITEM::ClassOf( item ) )
1372 {
1373 toUnroute.push_back( static_cast<BOARD_CONNECTED_ITEM*>( item ) );
1374 }
1375 }
1376
1377 // Clear selection so we don't delete our footprints/pads
1378 ClearSelection( true );
1379
1380 // Get the tracks on our list of pads, then delete them
1383
1384 // Reselect our footprint/pads as they were in our original selection
1385 for( EDA_ITEM* item : selectedItems )
1386 {
1387 if( item->Type() == PCB_FOOTPRINT_T || item->Type() == PCB_PAD_T )
1388 select( item );
1389 }
1390
1391 return 0;
1392}
1393
1394
1396{
1397 // expandConnection will get called no matter whether the user selected a connected item or a
1398 // non-connected shape (graphic on a non-copper layer). The algorithm for expanding to connected
1399 // items is different from graphics, so they need to be handled separately.
1400 unsigned initialCount = 0;
1401
1402 for( const EDA_ITEM* item : m_selection.GetItems() )
1403 {
1404 if( item->Type() == PCB_FOOTPRINT_T
1405 || item->Type() == PCB_GENERATOR_T
1406 || ( static_cast<const BOARD_ITEM*>( item )->IsConnected() ) )
1407 {
1408 initialCount++;
1409 }
1410 }
1411
1412 if( initialCount == 0 )
1413 {
1414 // First, process any graphic shapes we have
1415 std::vector<PCB_SHAPE*> startShapes;
1416
1417 for( EDA_ITEM* item : m_selection.GetItems() )
1418 {
1419 if( isExpandableGraphicShape( item ) )
1420 startShapes.push_back( static_cast<PCB_SHAPE*>( item ) );
1421 }
1422
1423 // If no non-copper shapes; fall back to looking for connected items
1424 if( !startShapes.empty() )
1425 selectAllConnectedShapes( startShapes );
1426 else
1428 }
1429
1430 m_frame->SetStatusText( _( "Select/Expand Connection..." ) );
1431
1432 for( STOP_CONDITION stopCondition : { STOP_AT_JUNCTION, STOP_AT_PAD, STOP_NEVER } )
1433 {
1434 std::deque<EDA_ITEM*> selectedItems = m_selection.GetItems();
1435
1436 for( EDA_ITEM* item : selectedItems )
1437 item->ClearTempFlags();
1438
1439 std::vector<BOARD_CONNECTED_ITEM*> startItems;
1440
1441 for( EDA_ITEM* item : selectedItems )
1442 {
1443 if( item->Type() == PCB_FOOTPRINT_T )
1444 {
1445 FOOTPRINT* footprint = static_cast<FOOTPRINT*>( item );
1446
1447 for( PAD* pad : footprint->Pads() )
1448 startItems.push_back( pad );
1449 }
1450 else if( item->Type() == PCB_GENERATOR_T )
1451 {
1452 for( BOARD_ITEM* generatedItem : static_cast<PCB_GENERATOR*>( item )->GetItems() )
1453 {
1454 if( BOARD_CONNECTED_ITEM::ClassOf( generatedItem ) )
1455 startItems.push_back( static_cast<BOARD_CONNECTED_ITEM*>( generatedItem ) );
1456 }
1457 }
1458 else if( BOARD_CONNECTED_ITEM::ClassOf( item ) )
1459 {
1460 startItems.push_back( static_cast<BOARD_CONNECTED_ITEM*>( item ) );
1461 }
1462 }
1463
1464 selectAllConnectedTracks( startItems, stopCondition );
1465
1466 if( m_selection.GetItems().size() > initialCount )
1467 break;
1468 }
1469
1470 m_frame->SetStatusText( wxEmptyString );
1471
1472 // Inform other potentially interested tools
1474
1475 return 0;
1476}
1477
1478
1480 const std::vector<BOARD_CONNECTED_ITEM*>& aStartItems, STOP_CONDITION aStopCondition )
1481{
1482 const LSET allCuMask = LSET::AllCuMask();
1483
1484 PROF_TIMER refreshTimer;
1485 double refreshIntervalMs = 500; // Refresh display with this interval to indicate progress
1486 int lastSelectionSize = (int) m_selection.GetSize();
1487
1488 auto connectivity = board()->GetConnectivity();
1489
1490 std::map<VECTOR2I, std::vector<PCB_TRACK*>> trackMap;
1491 std::map<VECTOR2I, PCB_VIA*> viaMap;
1492 std::map<VECTOR2I, PAD*> padMap;
1493 std::map<VECTOR2I, std::vector<PCB_SHAPE*>> shapeMap;
1494 std::set<PAD*> startPadSet;
1495 std::vector<BOARD_CONNECTED_ITEM*> cleanupItems;
1496 std::vector<std::pair<VECTOR2I, LSET>> activePts;
1497
1498 for( BOARD_CONNECTED_ITEM* startItem : aStartItems )
1499 {
1500 // Register starting pads
1501 if( startItem->Type() == PCB_PAD_T )
1502 startPadSet.insert( static_cast<PAD*>( startItem ) );
1503
1504 // Select any starting track items
1505 if( startItem->IsType( { PCB_TRACE_T, PCB_ARC_T, PCB_VIA_T } ) )
1506 select( startItem );
1507 }
1508
1509 for( BOARD_CONNECTED_ITEM* startItem : aStartItems )
1510 {
1511 if( startItem->HasFlag( SKIP_STRUCT ) ) // Skip already visited items
1512 continue;
1513
1514 auto connectedItems = connectivity->GetConnectedItems( startItem,
1516
1517 // Build maps of connected items
1518 for( BOARD_CONNECTED_ITEM* item : connectedItems )
1519 {
1520 switch( item->Type() )
1521 {
1522 case PCB_ARC_T:
1523 case PCB_TRACE_T:
1524 {
1525 PCB_TRACK* track = static_cast<PCB_TRACK*>( item );
1526 trackMap[track->GetStart()].push_back( track );
1527 trackMap[track->GetEnd()].push_back( track );
1528 break;
1529 }
1530
1531 case PCB_VIA_T:
1532 {
1533 PCB_VIA* via = static_cast<PCB_VIA*>( item );
1534 viaMap[via->GetStart()] = via;
1535 break;
1536 }
1537
1538 case PCB_PAD_T:
1539 {
1540 PAD* pad = static_cast<PAD*>( item );
1541 padMap[pad->GetPosition()] = pad;
1542 break;
1543 }
1544
1545 case PCB_SHAPE_T:
1546 {
1547 PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( item );
1548
1549 for( const auto& point : shape->GetConnectionPoints() )
1550 shapeMap[point].push_back( shape );
1551
1552 break;
1553 }
1554
1555 default:
1556 break;
1557 }
1558 }
1559
1560 // Set up the initial active points
1561 switch( startItem->Type() )
1562 {
1563 case PCB_ARC_T:
1564 case PCB_TRACE_T:
1565 {
1566 PCB_TRACK* track = static_cast<PCB_TRACK*>( startItem );
1567
1568 activePts.push_back( { track->GetStart(), track->GetLayerSet() } );
1569 activePts.push_back( { track->GetEnd(), track->GetLayerSet() } );
1570 break;
1571 }
1572
1573 case PCB_VIA_T:
1574 activePts.push_back( { startItem->GetPosition(), startItem->GetLayerSet() } );
1575 break;
1576
1577 case PCB_PAD_T:
1578 activePts.push_back( { startItem->GetPosition(), startItem->GetLayerSet() } );
1579 break;
1580
1581 case PCB_SHAPE_T:
1582 {
1583 PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( startItem );
1584
1585 for( const auto& point : shape->GetConnectionPoints() )
1586 activePts.push_back( { point, startItem->GetLayerSet() } );
1587
1588 break;
1589 }
1590
1591 default:
1592 break;
1593 }
1594
1595 bool expand = true;
1596 int failSafe = 0;
1597
1598 // Iterative push from all active points
1599 while( expand && failSafe++ < 100000 )
1600 {
1601 expand = false;
1602
1603 for( int i = (int) activePts.size() - 1; i >= 0; --i )
1604 {
1605 VECTOR2I pt = activePts[i].first;
1606 LSET layerSetCu = activePts[i].second & allCuMask;
1607
1608 auto viaIt = viaMap.find( pt );
1609 auto padIt = padMap.find( pt );
1610
1611 bool gotVia = ( viaIt != viaMap.end() )
1612 && ( layerSetCu & ( viaIt->second->GetLayerSet() ) ).any();
1613
1614 bool gotPad = ( padIt != padMap.end() )
1615 && ( layerSetCu & ( padIt->second->GetLayerSet() ) ).any();
1616
1617 bool gotNonStartPad =
1618 gotPad && ( startPadSet.find( padIt->second ) == startPadSet.end() );
1619
1620 if( aStopCondition == STOP_AT_JUNCTION )
1621 {
1622 size_t pt_count = 0;
1623
1624 for( PCB_TRACK* track : trackMap[pt] )
1625 {
1626 if( track->GetStart() != track->GetEnd()
1627 && layerSetCu.Contains( track->GetLayer() ) )
1628 {
1629 pt_count++;
1630 }
1631 }
1632
1633 if( pt_count > 2 || gotVia || gotNonStartPad )
1634 {
1635 activePts.erase( activePts.begin() + i );
1636 continue;
1637 }
1638 }
1639 else if( aStopCondition == STOP_AT_PAD )
1640 {
1641 if( gotNonStartPad )
1642 {
1643 activePts.erase( activePts.begin() + i );
1644 continue;
1645 }
1646 }
1647
1648 if( gotPad )
1649 {
1650 PAD* pad = padIt->second;
1651
1652 if( !pad->HasFlag( SKIP_STRUCT ) )
1653 {
1654 pad->SetFlags( SKIP_STRUCT );
1655 cleanupItems.push_back( pad );
1656
1657 activePts.push_back( { pad->GetPosition(), pad->GetLayerSet() } );
1658 expand = true;
1659 }
1660 }
1661
1662 for( PCB_TRACK* track : trackMap[pt] )
1663 {
1664 if( !layerSetCu.Contains( track->GetLayer() ) )
1665 continue;
1666
1667 if( !track->IsSelected() )
1668 select( track );
1669
1670 if( !track->HasFlag( SKIP_STRUCT ) )
1671 {
1672 track->SetFlags( SKIP_STRUCT );
1673 cleanupItems.push_back( track );
1674
1675 if( track->GetStart() == pt )
1676 activePts.push_back( { track->GetEnd(), track->GetLayerSet() } );
1677 else
1678 activePts.push_back( { track->GetStart(), track->GetLayerSet() } );
1679
1680 expand = true;
1681 }
1682 }
1683
1684 for( PCB_SHAPE* shape : shapeMap[pt] )
1685 {
1686 if( !layerSetCu.Contains( shape->GetLayer() ) )
1687 continue;
1688
1689 if( !shape->IsSelected() )
1690 select( shape );
1691
1692 if( !shape->HasFlag( SKIP_STRUCT ) )
1693 {
1694 shape->SetFlags( SKIP_STRUCT );
1695 cleanupItems.push_back( shape );
1696
1697 for( const VECTOR2I& newPoint : shape->GetConnectionPoints() )
1698 {
1699 if( newPoint == pt )
1700 continue;
1701
1702 activePts.push_back( { newPoint, shape->GetLayerSet() } );
1703 }
1704
1705 expand = true;
1706 }
1707 }
1708
1709 if( viaMap.count( pt ) )
1710 {
1711 PCB_VIA* via = viaMap[pt];
1712
1713 if( !via->IsSelected() )
1714 select( via );
1715
1716 if( !via->HasFlag( SKIP_STRUCT ) )
1717 {
1718 via->SetFlags( SKIP_STRUCT );
1719 cleanupItems.push_back( via );
1720
1721 activePts.push_back( { via->GetPosition(), via->GetLayerSet() } );
1722 expand = true;
1723 }
1724 }
1725
1726 activePts.erase( activePts.begin() + i );
1727 }
1728
1729 // Refresh display for the feel of progress
1730 if( refreshTimer.msecs() >= refreshIntervalMs )
1731 {
1732 if( m_selection.Size() != lastSelectionSize )
1733 {
1735 lastSelectionSize = m_selection.Size();
1736 }
1737
1738 refreshTimer.Start();
1739 }
1740 }
1741 }
1742
1743 // Promote generated members to their PCB_GENERATOR parents
1744 for( EDA_ITEM* item : m_selection )
1745 {
1746 if( !item->IsBOARD_ITEM() )
1747 continue;
1748
1749 BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( item );
1750 PCB_GROUP* parent = boardItem->GetParentGroup();
1751
1752 if( parent && parent->Type() == PCB_GENERATOR_T )
1753 {
1754 unselect( item );
1755
1756 if( !parent->IsSelected() )
1757 select( parent );
1758 }
1759 }
1760
1761 for( BOARD_CONNECTED_ITEM* item : cleanupItems )
1762 item->ClearFlags( SKIP_STRUCT );
1763}
1764
1765
1767{
1768 if( aItem->Type() == PCB_SHAPE_T )
1769 {
1770 const PCB_SHAPE* shape = static_cast<const PCB_SHAPE*>( aItem );
1771
1772 switch( shape->GetShape() )
1773 {
1774 case SHAPE_T::SEGMENT:
1775 case SHAPE_T::ARC:
1776 case SHAPE_T::BEZIER:
1777 return !shape->IsOnCopperLayer();
1778
1779 case SHAPE_T::POLY:
1780 return !shape->IsOnCopperLayer() && !shape->IsClosed();
1781
1782 default:
1783 return false;
1784 }
1785 }
1786
1787 return false;
1788}
1789
1790
1791void PCB_SELECTION_TOOL::selectAllConnectedShapes( const std::vector<PCB_SHAPE*>& aStartItems )
1792{
1793 std::stack<PCB_SHAPE*> toSearch;
1794 std::set<PCB_SHAPE*> toCleanup;
1795
1796 for( PCB_SHAPE* startItem : aStartItems )
1797 toSearch.push( startItem );
1798
1799 GENERAL_COLLECTOR collector;
1801
1802 auto searchPoint = [&]( const VECTOR2I& aWhere )
1803 {
1804 collector.Collect( board(), { PCB_SHAPE_T }, aWhere, guide );
1805
1806 for( EDA_ITEM* item : collector )
1807 {
1808 if( isExpandableGraphicShape( item ) )
1809 toSearch.push( static_cast<PCB_SHAPE*>( item ) );
1810 }
1811 };
1812
1813 while( !toSearch.empty() )
1814 {
1815 PCB_SHAPE* shape = toSearch.top();
1816 toSearch.pop();
1817
1818 if( shape->HasFlag( SKIP_STRUCT ) )
1819 continue;
1820
1821 select( shape );
1822 shape->SetFlags( SKIP_STRUCT );
1823 toCleanup.insert( shape );
1824
1825 guide.SetLayerVisibleBits( shape->GetLayerSet() );
1826
1827 searchPoint( shape->GetStart() );
1828 searchPoint( shape->GetEnd() );
1829 }
1830
1831 for( PCB_SHAPE* shape : toCleanup )
1832 shape->ClearFlags( SKIP_STRUCT );
1833}
1834
1835
1837{
1838 // Get all pads
1839 std::vector<PAD*> pads;
1840
1841 for( EDA_ITEM* item : m_selection.GetItems() )
1842 {
1843 if( item->Type() == PCB_FOOTPRINT_T )
1844 {
1845 for( PAD* pad : static_cast<FOOTPRINT*>( item )->Pads() )
1846 pads.push_back( pad );
1847 }
1848 else if( item->Type() == PCB_PAD_T )
1849 {
1850 pads.push_back( static_cast<PAD*>( item ) );
1851 }
1852 }
1853
1854 // Select every footprint on the end of the ratsnest for each pad in our selection
1855 std::shared_ptr<CONNECTIVITY_DATA> conn = board()->GetConnectivity();
1856
1857 for( PAD* pad : pads )
1858 {
1859 for( const CN_EDGE& edge : conn->GetRatsnestForPad( pad ) )
1860 {
1861 wxCHECK2( edge.GetSourceNode() && !edge.GetSourceNode()->Dirty(), continue );
1862 wxCHECK2( edge.GetTargetNode() && !edge.GetTargetNode()->Dirty(), continue );
1863
1864 BOARD_CONNECTED_ITEM* sourceParent = edge.GetSourceNode()->Parent();
1865 BOARD_CONNECTED_ITEM* targetParent = edge.GetTargetNode()->Parent();
1866
1867 if( sourceParent == pad )
1868 {
1869 if( targetParent->Type() == PCB_PAD_T )
1870 select( static_cast<PAD*>( targetParent )->GetParent() );
1871 }
1872 else if( targetParent == pad )
1873 {
1874 if( sourceParent->Type() == PCB_PAD_T )
1875 select( static_cast<PAD*>( sourceParent )->GetParent() );
1876 }
1877 }
1878 }
1879
1880 return 0;
1881}
1882
1883
1885{
1886 PCB_SELECTION originalSelection = m_selection;
1887
1888 // Get all pads
1889 std::vector<PAD*> pads;
1890
1891 for( EDA_ITEM* item : m_selection.GetItems() )
1892 {
1893 if( item->Type() == PCB_FOOTPRINT_T )
1894 {
1895 for( PAD* pad : static_cast<FOOTPRINT*>( item )->Pads() )
1896 pads.push_back( pad );
1897 }
1898 else if( item->Type() == PCB_PAD_T )
1899 {
1900 pads.push_back( static_cast<PAD*>( item ) );
1901 }
1902 }
1903
1905
1906 // Select every footprint on the end of the ratsnest for each pad in our selection
1907 std::shared_ptr<CONNECTIVITY_DATA> conn = board()->GetConnectivity();
1908
1909 for( PAD* pad : pads )
1910 {
1911 const std::vector<CN_EDGE> edges = conn->GetRatsnestForPad( pad );
1912
1913 // Need to have something unconnected to grab
1914 if( edges.size() == 0 )
1915 continue;
1916
1917 double currentDistance = DBL_MAX;
1918 FOOTPRINT* nearest = nullptr;
1919
1920 // Check every ratsnest line for the nearest one
1921 for( const CN_EDGE& edge : edges )
1922 {
1923 if( edge.GetSourceNode()->Parent()->GetParentFootprint()
1924 == edge.GetTargetNode()->Parent()->GetParentFootprint() )
1925 {
1926 continue; // This edge is a loop on the same footprint
1927 }
1928
1929 // Figure out if we are the source or the target node on the ratnest
1930 const CN_ANCHOR* other = edge.GetSourceNode()->Parent() == pad ? edge.GetTargetNode().get()
1931 : edge.GetSourceNode().get();
1932
1933 wxCHECK2( other && !other->Dirty(), continue );
1934
1935 // We only want to grab footprints, so the ratnest has to point to a pad
1936 if( other->Parent()->Type() != PCB_PAD_T )
1937 continue;
1938
1939 if( edge.GetLength() < currentDistance )
1940 {
1941 currentDistance = edge.GetLength();
1942 nearest = other->Parent()->GetParentFootprint();
1943 }
1944 }
1945
1946 if( nearest != nullptr )
1947 select( nearest );
1948 }
1949
1951
1952 return 0;
1953}
1954
1955
1956void PCB_SELECTION_TOOL::SelectAllItemsOnNet( int aNetCode, bool aSelect )
1957{
1958 std::shared_ptr<CONNECTIVITY_DATA> conn = board()->GetConnectivity();
1959
1960 for( BOARD_ITEM* item : conn->GetNetItems( aNetCode, { PCB_TRACE_T,
1961 PCB_ARC_T,
1962 PCB_VIA_T,
1963 PCB_SHAPE_T } ) )
1964 {
1965 if( itemPassesFilter( item, true ) )
1966 aSelect ? select( item ) : unselect( item );
1967 }
1968}
1969
1970
1972{
1973 bool select = aEvent.IsAction( &PCB_ACTIONS::selectNet );
1974
1975 // If we've been passed an argument, just select that netcode1
1976 int netcode = aEvent.Parameter<int>();
1977
1978 if( netcode > 0 )
1979 {
1980 SelectAllItemsOnNet( netcode, select );
1981
1982 // Inform other potentially interested tools
1983 if( m_selection.Size() > 0 )
1985 else
1987
1988 return 0;
1989 }
1990
1991 if( !selectCursor() )
1992 return 0;
1993
1994 // copy the selection, since we're going to iterate and modify
1996
1997 for( EDA_ITEM* i : selection )
1998 {
1999 BOARD_CONNECTED_ITEM* connItem = dynamic_cast<BOARD_CONNECTED_ITEM*>( i );
2000
2001 if( connItem )
2002 SelectAllItemsOnNet( connItem->GetNetCode(), select );
2003 }
2004
2005 // Inform other potentially interested tools
2006 if( m_selection.Size() > 0 )
2008 else
2010
2011 return 0;
2012}
2013
2014
2016{
2017 std::vector<BOARD_ITEM*> footprints;
2018
2019 // store all footprints that are on that sheet path
2020 for( FOOTPRINT* footprint : board()->Footprints() )
2021 {
2022 if( footprint == nullptr )
2023 continue;
2024
2025 wxString footprint_path = footprint->GetPath().AsString().BeforeLast( '/' );
2026
2027 if( footprint_path.IsEmpty() )
2028 footprint_path += '/';
2029
2030 if( footprint_path == aSheetPath )
2031 footprints.push_back( footprint );
2032 }
2033
2034 for( BOARD_ITEM* i : footprints )
2035 {
2036 if( i != nullptr )
2037 select( i );
2038 }
2039
2040 selectConnections( footprints );
2041}
2042
2043
2044void PCB_SELECTION_TOOL::selectConnections( const std::vector<BOARD_ITEM*>& aItems )
2045{
2046 // Generate a list of all pads, and of all nets they belong to.
2047 std::list<int> netcodeList;
2048 std::vector<BOARD_CONNECTED_ITEM*> padList;
2049
2050 for( BOARD_ITEM* item : aItems )
2051 {
2052 switch( item->Type() )
2053 {
2054 case PCB_FOOTPRINT_T:
2055 {
2056 for( PAD* pad : static_cast<FOOTPRINT*>( item )->Pads() )
2057 {
2058 if( pad->IsConnected() )
2059 {
2060 netcodeList.push_back( pad->GetNetCode() );
2061 padList.push_back( pad );
2062 }
2063 }
2064
2065 break;
2066 }
2067
2068 case PCB_PAD_T:
2069 {
2070 PAD* pad = static_cast<PAD*>( item );
2071
2072 if( pad->IsConnected() )
2073 {
2074 netcodeList.push_back( pad->GetNetCode() );
2075 padList.push_back( pad );
2076 }
2077
2078 break;
2079 }
2080
2081 default:
2082 break;
2083 }
2084 }
2085
2086 // Sort for binary search
2087 std::sort( padList.begin(), padList.end() );
2088
2089 // remove all duplicates
2090 netcodeList.sort();
2091 netcodeList.unique();
2092
2094
2095 // now we need to find all footprints that are connected to each of these nets then we need
2096 // to determine if these footprints are in the list of footprints
2097 std::vector<int> removeCodeList;
2098 std::shared_ptr<CONNECTIVITY_DATA> conn = board()->GetConnectivity();
2099
2100 for( int netCode : netcodeList )
2101 {
2102 for( BOARD_CONNECTED_ITEM* pad : conn->GetNetItems( netCode, { PCB_PAD_T } ) )
2103 {
2104 if( !std::binary_search( padList.begin(), padList.end(), pad ) )
2105 {
2106 // if we cannot find the pad in the padList then we can assume that that pad
2107 // should not be used, therefore invalidate this netcode.
2108 removeCodeList.push_back( netCode );
2109 break;
2110 }
2111 }
2112 }
2113
2114 for( int removeCode : removeCodeList )
2115 netcodeList.remove( removeCode );
2116
2117 std::unordered_set<BOARD_ITEM*> localConnectionList;
2118
2119 for( int netCode : netcodeList )
2120 {
2121 for( BOARD_ITEM* item : conn->GetNetItems( netCode, { PCB_TRACE_T,
2122 PCB_ARC_T,
2123 PCB_VIA_T,
2124 PCB_SHAPE_T } ) )
2125 {
2126 localConnectionList.insert( item );
2127 }
2128 }
2129
2130 for( BOARD_ITEM* item : localConnectionList )
2131 select( item );
2132}
2133
2134
2136{
2137 std::vector<BOARD_ITEM*>* items = aEvent.Parameter<std::vector<BOARD_ITEM*>*>();
2138
2139 if( items )
2140 doSyncSelection( *items, false );
2141
2142 return 0;
2143}
2144
2145
2147{
2148 std::vector<BOARD_ITEM*>* items = aEvent.Parameter<std::vector<BOARD_ITEM*>*>();
2149
2150 if( items )
2151 doSyncSelection( *items, true );
2152
2153 return 0;
2154}
2155
2156
2157void PCB_SELECTION_TOOL::doSyncSelection( const std::vector<BOARD_ITEM*>& aItems, bool aWithNets )
2158{
2159 ClearSelection( true /*quiet mode*/ );
2160
2161 // Perform individual selection of each item before processing the event.
2162 for( BOARD_ITEM* item : aItems )
2163 select( item );
2164
2165 if( aWithNets )
2166 selectConnections( aItems );
2167
2169
2170 if( bbox.GetWidth() != 0 && bbox.GetHeight() != 0 )
2171 {
2173 {
2175 ZoomFitCrossProbeBBox( bbox );
2176
2177 m_frame->FocusOnLocation( bbox.Centre() );
2178 }
2179 }
2180
2182
2184
2185 if( m_selection.Size() > 0 )
2187}
2188
2189
2191{
2192 ClearSelection( true /*quiet mode*/ );
2193 wxString sheetPath = *aEvent.Parameter<wxString*>();
2194
2195 selectAllItemsOnSheet( sheetPath );
2196
2198
2199 if( m_selection.Size() > 0 )
2201
2202 return 0;
2203}
2204
2205
2207{
2208 // this function currently only supports footprints since they are only on one sheet.
2209 EDA_ITEM* item = m_selection.Front();
2210
2211 if( !item )
2212 return 0;
2213
2214 if( item->Type() != PCB_FOOTPRINT_T )
2215 return 0;
2216
2217 FOOTPRINT* footprint = dynamic_cast<FOOTPRINT*>( item );
2218
2219 if( !footprint || footprint->GetPath().empty() )
2220 return 0;
2221
2222 ClearSelection( true /*quiet mode*/ );
2223
2224 // get the sheet path only.
2225 wxString sheetPath = footprint->GetPath().AsString().BeforeLast( '/' );
2226
2227 if( sheetPath.IsEmpty() )
2228 sheetPath += '/';
2229
2230 selectAllItemsOnSheet( sheetPath );
2231
2232 // Inform other potentially interested tools
2233 if( m_selection.Size() > 0 )
2235
2236 return 0;
2237}
2238
2239
2241{
2242 // Should recalculate the view to zoom in on the selection.
2243 BOX2I selectionBox = m_selection.GetBoundingBox();
2245
2246 VECTOR2D screenSize = view->ToWorld( ToVECTOR2D( m_frame->GetCanvas()->GetClientSize() ),
2247 false );
2248 screenSize.x = std::max( 10.0, screenSize.x );
2249 screenSize.y = std::max( 10.0, screenSize.y );
2250
2251 if( selectionBox.GetWidth() != 0 || selectionBox.GetHeight() != 0 )
2252 {
2253 VECTOR2D vsize = selectionBox.GetSize();
2254 double scale = view->GetScale() / std::max( fabs( vsize.x / screenSize.x ),
2255 fabs( vsize.y / screenSize.y ) );
2256 view->SetScale( scale );
2257 view->SetCenter( selectionBox.Centre() );
2258 view->Add( &m_selection );
2259 }
2260
2262}
2263
2264
2266{
2267 // Should recalculate the view to zoom in on the bbox.
2269
2270 if( aBBox.GetWidth() == 0 )
2271 return;
2272
2273 BOX2I bbox = aBBox;
2274 bbox.Normalize();
2275
2276 //#define DEFAULT_PCBNEW_CODE // Un-comment for normal full zoom KiCad algorithm
2277#ifdef DEFAULT_PCBNEW_CODE
2278 auto bbSize = bbox.Inflate( bbox.GetWidth() * 0.2f ).GetSize();
2279 auto screenSize = view->ToWorld( GetCanvas()->GetClientSize(), false );
2280
2281 // The "fabs" on x ensures the right answer when the view is flipped
2282 screenSize.x = std::max( 10.0, fabs( screenSize.x ) );
2283 screenSize.y = std::max( 10.0, screenSize.y );
2284 double ratio = std::max( fabs( bbSize.x / screenSize.x ), fabs( bbSize.y / screenSize.y ) );
2285
2286 // Try not to zoom on every cross-probe; it gets very noisy
2287 if( crossProbingSettings.zoom_to_fit && ( ratio < 0.5 || ratio > 1.0 ) )
2288 view->SetScale( view->GetScale() / ratio );
2289#endif // DEFAULT_PCBNEW_CODE
2290
2291#ifndef DEFAULT_PCBNEW_CODE // Do the scaled zoom
2292 auto bbSize = bbox.Inflate( KiROUND( bbox.GetWidth() * 0.2 ) ).GetSize();
2293 VECTOR2D screenSize = view->ToWorld( ToVECTOR2D( m_frame->GetCanvas()->GetClientSize() ),
2294 false );
2295
2296 // This code tries to come up with a zoom factor that doesn't simply zoom in
2297 // to the cross probed component, but instead shows a reasonable amount of the
2298 // circuit around it to provide context. This reduces or eliminates the need
2299 // to manually change the zoom because it's too close.
2300
2301 // Using the default text height as a constant to compare against, use the
2302 // height of the bounding box of visible items for a footprint to figure out
2303 // if this is a big footprint (like a processor) or a small footprint (like a resistor).
2304 // This ratio is not useful by itself as a scaling factor. It must be "bent" to
2305 // provide good scaling at varying component sizes. Bigger components need less
2306 // scaling than small ones.
2307 double currTextHeight = pcbIUScale.mmToIU( DEFAULT_TEXT_SIZE );
2308
2309 double compRatio = bbSize.y / currTextHeight; // Ratio of component to text height
2310
2311 // This will end up as the scaling factor we apply to "ratio".
2312 double compRatioBent = 1.0;
2313
2314 // This is similar to the original KiCad code that scaled the zoom to make sure
2315 // components were visible on screen. It's simply a ratio of screen size to
2316 // component size, and its job is to zoom in to make the component fullscreen.
2317 // Earlier in the code the component BBox is given a 20% margin to add some
2318 // breathing room. We compare the height of this enlarged component bbox to the
2319 // default text height. If a component will end up with the sides clipped, we
2320 // adjust later to make sure it fits on screen.
2321 //
2322 // The "fabs" on x ensures the right answer when the view is flipped
2323 screenSize.x = std::max( 10.0, fabs( screenSize.x ) );
2324 screenSize.y = std::max( 10.0, screenSize.y );
2325 double ratio = std::max( -1.0, fabs( bbSize.y / screenSize.y ) );
2326
2327 // Original KiCad code for how much to scale the zoom
2328 double kicadRatio = std::max( fabs( bbSize.x / screenSize.x ),
2329 fabs( bbSize.y / screenSize.y ) );
2330
2331 // LUT to scale zoom ratio to provide reasonable schematic context. Must work
2332 // with footprints of varying sizes (e.g. 0402 package and 200 pin BGA).
2333 // "first" is used as the input and "second" as the output
2334 //
2335 // "first" = compRatio (footprint height / default text height)
2336 // "second" = Amount to scale ratio by
2337 std::vector<std::pair<double, double>> lut {
2338 { 1, 8 },
2339 { 1.5, 5 },
2340 { 3, 3 },
2341 { 4.5, 2.5 },
2342 { 8, 2.0 },
2343 { 12, 1.7 },
2344 { 16, 1.5 },
2345 { 24, 1.3 },
2346 { 32, 1.0 },
2347 };
2348
2349
2350 std::vector<std::pair<double, double>>::iterator it;
2351
2352 compRatioBent = lut.back().second; // Large component default
2353
2354 if( compRatio >= lut.front().first )
2355 {
2356 // Use LUT to do linear interpolation of "compRatio" within "first", then
2357 // use that result to linearly interpolate "second" which gives the scaling
2358 // factor needed.
2359
2360 for( it = lut.begin(); it < lut.end() - 1; it++ )
2361 {
2362 if( it->first <= compRatio && next( it )->first >= compRatio )
2363 {
2364 double diffx = compRatio - it->first;
2365 double diffn = next( it )->first - it->first;
2366
2367 compRatioBent = it->second + ( next( it )->second - it->second ) * diffx / diffn;
2368 break; // We have our interpolated value
2369 }
2370 }
2371 }
2372 else
2373 {
2374 compRatioBent = lut.front().second; // Small component default
2375 }
2376
2377 // If the width of the part we're probing is bigger than what the screen width will be
2378 // after the zoom, then punt and use the KiCad zoom algorithm since it guarantees the
2379 // part's width will be encompassed within the screen. This will apply to parts that
2380 // are much wider than they are tall.
2381
2382 if( bbSize.x > screenSize.x * ratio * compRatioBent )
2383 {
2384 // Use standard KiCad zoom algorithm for parts too wide to fit screen/
2385 ratio = kicadRatio;
2386 compRatioBent = 1.0; // Reset so we don't modify the "KiCad" ratio
2387 wxLogTrace( "CROSS_PROBE_SCALE",
2388 "Part TOO WIDE for screen. Using normal KiCad zoom ratio: %1.5f", ratio );
2389 }
2390
2391 // Now that "compRatioBent" holds our final scaling factor we apply it to the original
2392 // fullscreen zoom ratio to arrive at the final ratio itself.
2393 ratio *= compRatioBent;
2394
2395 bool alwaysZoom = false; // DEBUG - allows us to minimize zooming or not
2396
2397 // Try not to zoom on every cross-probe; it gets very noisy
2398 if( ( ratio < 0.5 || ratio > 1.0 ) || alwaysZoom )
2399 view->SetScale( view->GetScale() / ratio );
2400#endif // ifndef DEFAULT_PCBNEW_CODE
2401}
2402
2403
2405{
2406 bool cleared = false;
2407
2408 if( m_selection.GetSize() > 0 )
2409 {
2410 // Don't fire an event now; most of the time it will be redundant as we're about to
2411 // fire a SelectedEvent.
2412 cleared = true;
2413 ClearSelection( true /*quiet mode*/ );
2414 }
2415
2416 if( aItem )
2417 {
2418 switch( aItem->Type() )
2419 {
2420 case PCB_NETINFO_T:
2421 {
2422 int netCode = static_cast<NETINFO_ITEM*>( aItem )->GetNetCode();
2423
2424 if( netCode > 0 )
2425 {
2426 SelectAllItemsOnNet( netCode, true );
2427 m_frame->FocusOnLocation( aItem->GetCenter() );
2428 }
2429 break;
2430 }
2431
2432 default:
2433 select( aItem );
2434 m_frame->FocusOnLocation( aItem->GetPosition() );
2435 }
2436
2437 // If the item has a bounding box, then zoom out if needed
2438 if( aItem->GetBoundingBox().GetHeight() > 0 && aItem->GetBoundingBox().GetWidth() > 0 )
2439 {
2440 // This adds some margin
2441 double marginFactor = 2;
2442
2443 KIGFX::PCB_VIEW* pcbView = canvas()->GetView();
2444 BOX2D screenBox = pcbView->GetViewport();
2445 VECTOR2D screenSize = screenBox.GetSize();
2446 BOX2I screenRect = BOX2ISafe( screenBox.GetOrigin(), screenSize / marginFactor );
2447
2448 if( !screenRect.Contains( aItem->GetBoundingBox() ) )
2449 {
2450 double scaleX = screenSize.x /
2451 static_cast<double>( aItem->GetBoundingBox().GetWidth() );
2452 double scaleY = screenSize.y /
2453 static_cast<double>( aItem->GetBoundingBox().GetHeight() );
2454
2455 scaleX /= marginFactor;
2456 scaleY /= marginFactor;
2457
2458 double scale = scaleX > scaleY ? scaleY : scaleX;
2459
2460 if( scale < 1 ) // Don't zoom in, only zoom out
2461 {
2462 pcbView->SetScale( pcbView->GetScale() * ( scale ) );
2463
2464 //Let's refocus because there is an algorithm to avoid dialogs in there.
2465 m_frame->FocusOnLocation( aItem->GetCenter() );
2466 }
2467 }
2468 }
2469 // Inform other potentially interested tools
2471 }
2472 else if( cleared )
2473 {
2475 }
2476
2478}
2479
2480
2486static bool itemIsIncludedByFilter( const BOARD_ITEM& aItem, const BOARD& aBoard,
2487 const DIALOG_FILTER_SELECTION::OPTIONS& aFilterOptions )
2488{
2489 switch( aItem.Type() )
2490 {
2491 case PCB_FOOTPRINT_T:
2492 {
2493 const FOOTPRINT& footprint = static_cast<const FOOTPRINT&>( aItem );
2494
2495 return aFilterOptions.includeModules
2496 && ( aFilterOptions.includeLockedModules || !footprint.IsLocked() );
2497 }
2498
2499 case PCB_TRACE_T:
2500 case PCB_ARC_T:
2501 return aFilterOptions.includeTracks;
2502
2503 case PCB_VIA_T:
2504 return aFilterOptions.includeVias;
2505
2506 case PCB_ZONE_T:
2507 return aFilterOptions.includeZones;
2508
2509 case PCB_SHAPE_T:
2510 case PCB_TARGET_T:
2511 case PCB_DIM_ALIGNED_T:
2512 case PCB_DIM_CENTER_T:
2513 case PCB_DIM_RADIAL_T:
2515 case PCB_DIM_LEADER_T:
2516 if( aItem.GetLayer() == Edge_Cuts )
2517 return aFilterOptions.includeBoardOutlineLayer;
2518 else
2519 return aFilterOptions.includeItemsOnTechLayers;
2520
2521 case PCB_FIELD_T:
2522 case PCB_TEXT_T:
2523 case PCB_TEXTBOX_T:
2524 case PCB_TABLE_T:
2525 case PCB_TABLECELL_T:
2526 return aFilterOptions.includePcbTexts;
2527
2528 default:
2529 // Filter dialog is inclusive, not exclusive. If it's not included, then it doesn't
2530 // get selected.
2531 return false;
2532 }
2533}
2534
2535
2537{
2538 const BOARD& board = *getModel<BOARD>();
2539 DIALOG_FILTER_SELECTION::OPTIONS& opts = m_priv->m_filterOpts;
2540 DIALOG_FILTER_SELECTION dlg( m_frame, opts );
2541
2542 const int cmd = dlg.ShowModal();
2543
2544 if( cmd != wxID_OK )
2545 return 0;
2546
2547 // copy current selection
2548 std::deque<EDA_ITEM*> selection = m_selection.GetItems();
2549
2550 ClearSelection( true /*quiet mode*/ );
2551
2552 // re-select items from the saved selection according to the dialog options
2553 for( EDA_ITEM* i : selection )
2554 {
2555 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( i );
2556 bool include = itemIsIncludedByFilter( *item, board, opts );
2557
2558 if( include )
2559 select( item );
2560 }
2561
2563
2564 return 0;
2565}
2566
2567
2569{
2570 if( aCollector.GetCount() == 0 )
2571 return;
2572
2573 std::set<BOARD_ITEM*> rejected;
2574
2575 for( EDA_ITEM* i : aCollector )
2576 {
2577 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( i );
2578
2579 if( !itemPassesFilter( item, aMultiSelect ) )
2580 rejected.insert( item );
2581 }
2582
2583 for( BOARD_ITEM* item : rejected )
2584 aCollector.Remove( item );
2585}
2586
2587
2588bool PCB_SELECTION_TOOL::itemPassesFilter( BOARD_ITEM* aItem, bool aMultiSelect )
2589{
2590 if( !m_filter.lockedItems )
2591 {
2592 if( aItem->IsLocked() || ( aItem->GetParent() && aItem->GetParent()->IsLocked() ) )
2593 {
2594 if( aItem->Type() == PCB_PAD_T && !aMultiSelect )
2595 {
2596 // allow a single pad to be selected -- there are a lot of operations that
2597 // require this so we allow this one inconsistency
2598 }
2599 else
2600 {
2601 return false;
2602 }
2603 }
2604 }
2605
2606 if( !aItem )
2607 return false;
2608
2609 KICAD_T itemType = aItem->Type();
2610
2611 if( itemType == PCB_GENERATOR_T )
2612 {
2613 if( static_cast<PCB_GENERATOR*>( aItem )->GetItems().empty() )
2614 {
2615 if( !m_filter.otherItems )
2616 return false;
2617 }
2618 else
2619 {
2620 itemType = ( *static_cast<PCB_GENERATOR*>( aItem )->GetItems().begin() )->Type();
2621 }
2622 }
2623
2624 switch( itemType )
2625 {
2626 case PCB_FOOTPRINT_T:
2627 if( !m_filter.footprints )
2628 return false;
2629
2630 break;
2631
2632 case PCB_PAD_T:
2633 if( !m_filter.pads )
2634 return false;
2635
2636 break;
2637
2638 case PCB_TRACE_T:
2639 case PCB_ARC_T:
2640 if( !m_filter.tracks )
2641 return false;
2642
2643 break;
2644
2645 case PCB_VIA_T:
2646 if( !m_filter.vias )
2647 return false;
2648
2649 break;
2650
2651 case PCB_ZONE_T:
2652 {
2653 ZONE* zone = static_cast<ZONE*>( aItem );
2654
2655 if( ( !m_filter.zones && !zone->GetIsRuleArea() )
2656 || ( !m_filter.keepouts && zone->GetIsRuleArea() ) )
2657 {
2658 return false;
2659 }
2660
2661 // m_SolderMaskBridges zone is a special zone, only used to showsolder mask briges
2662 // after running DRC. it is not really a board item.
2663 // Never select it or delete by a Commit.
2664 if( zone == m_frame->GetBoard()->m_SolderMaskBridges )
2665 return false;
2666
2667 break;
2668 }
2669
2670 case PCB_SHAPE_T:
2671 case PCB_TARGET_T:
2672 if( !m_filter.graphics )
2673 return false;
2674
2675 break;
2676
2678 if( !m_filter.graphics )
2679 return false;
2680
2681 // a reference image living in a footprint must not be selected inside the board editor
2682 if( !m_isFootprintEditor && aItem->GetParentFootprint() )
2683 return false;
2684
2685 break;
2686
2687 case PCB_FIELD_T:
2688 case PCB_TEXT_T:
2689 case PCB_TEXTBOX_T:
2690 case PCB_TABLE_T:
2691 case PCB_TABLECELL_T:
2692 if( !m_filter.text )
2693 return false;
2694
2695 break;
2696
2697 case PCB_DIM_ALIGNED_T:
2698 case PCB_DIM_CENTER_T:
2699 case PCB_DIM_RADIAL_T:
2701 case PCB_DIM_LEADER_T:
2702 if( !m_filter.dimensions )
2703 return false;
2704
2705 break;
2706
2707 default:
2708 if( !m_filter.otherItems )
2709 return false;
2710 }
2711
2712 return true;
2713}
2714
2715
2717{
2718 if( m_selection.Empty() )
2719 return;
2720
2721 while( m_selection.GetSize() )
2723
2724 view()->Update( &m_selection );
2725
2726 m_selection.SetIsHover( false );
2728
2729 // Inform other potentially interested tools
2730 if( !aQuietMode )
2731 {
2734 }
2735}
2736
2737
2739{
2741
2742 bool enteredGroupFound = false;
2743
2744 INSPECTOR_FUNC inspector =
2745 [&]( EDA_ITEM* item, void* testData )
2746 {
2747 if( item->IsSelected() )
2748 {
2749 EDA_ITEM* parent = item->GetParent();
2750
2751 // Let selected parents handle their children.
2752 if( parent && parent->IsSelected() )
2753 return INSPECT_RESULT::CONTINUE;
2754
2755 highlight( item, SELECTED, &m_selection );
2756 }
2757
2758 if( item->Type() == PCB_GROUP_T )
2759 {
2760 if( item == m_enteredGroup )
2761 {
2762 item->SetFlags( ENTERED );
2763 enteredGroupFound = true;
2764 }
2765 else
2766 {
2767 item->ClearFlags( ENTERED );
2768 }
2769 }
2770
2771 return INSPECT_RESULT::CONTINUE;
2772 };
2773
2776
2777 if( !enteredGroupFound )
2778 {
2780 m_enteredGroup = nullptr;
2781 }
2782}
2783
2784
2785bool PCB_SELECTION_TOOL::Selectable( const BOARD_ITEM* aItem, bool checkVisibilityOnly ) const
2786{
2787 const RENDER_SETTINGS* settings = getView()->GetPainter()->GetSettings();
2788 const PCB_DISPLAY_OPTIONS& options = frame()->GetDisplayOptions();
2789
2790 auto visibleLayers =
2791 [&]()
2792 {
2794 {
2795 LSET set;
2796
2797 for( PCB_LAYER_ID layer : LSET::AllLayersMask().Seq() )
2798 set.set( layer, view()->IsLayerVisible( layer ) );
2799
2800 return set;
2801 }
2802 else
2803 {
2804 return board()->GetVisibleLayers();
2805 }
2806 };
2807
2808 auto layerVisible =
2809 [&]( PCB_LAYER_ID aLayer )
2810 {
2812 return view()->IsLayerVisible( aLayer );
2813 else
2814 return board()->IsLayerVisible( aLayer );
2815 };
2816
2817 if( settings->GetHighContrast() )
2818 {
2819 const std::set<int> activeLayers = settings->GetHighContrastLayers();
2820 bool onActiveLayer = false;
2821
2822 for( int layer : activeLayers )
2823 {
2824 // NOTE: Only checking the regular layers (not GAL meta-layers)
2825 if( layer < PCB_LAYER_ID_COUNT && aItem->IsOnLayer( ToLAYER_ID( layer ) ) )
2826 {
2827 onActiveLayer = true;
2828 break;
2829 }
2830 }
2831
2832 if( !onActiveLayer ) // We do not want to select items that are in the background
2833 return false;
2834 }
2835
2836 if( aItem->Type() == PCB_FOOTPRINT_T )
2837 {
2838 const FOOTPRINT* footprint = static_cast<const FOOTPRINT*>( aItem );
2839
2840 // In footprint editor, we do not want to select the footprint itself.
2842 return false;
2843
2844 // Allow selection of footprints if some part of the footprint is visible.
2845 if( footprint->GetSide() != UNDEFINED_LAYER && !m_skip_heuristics )
2846 {
2847 LSET boardSide = footprint->IsFlipped() ? LSET::BackMask() : LSET::FrontMask();
2848
2849 if( !( visibleLayers() & boardSide ).any() )
2850 return false;
2851 }
2852
2853 // If the footprint has no items except the reference and value fields, include the
2854 // footprint in the selections.
2855 if( footprint->GraphicalItems().empty()
2856 && footprint->Pads().empty()
2857 && footprint->Zones().empty() )
2858 {
2859 return true;
2860 }
2861
2862 for( const BOARD_ITEM* item : footprint->GraphicalItems() )
2863 {
2864 if( Selectable( item, true ) )
2865 return true;
2866 }
2867
2868 for( const PAD* pad : footprint->Pads() )
2869 {
2870 if( Selectable( pad, true ) )
2871 return true;
2872 }
2873
2874 for( const ZONE* zone : footprint->Zones() )
2875 {
2876 if( Selectable( zone, true ) )
2877 return true;
2878 }
2879
2880 return false;
2881 }
2882 else if( aItem->Type() == PCB_GROUP_T )
2883 {
2884 PCB_GROUP* group = const_cast<PCB_GROUP*>( static_cast<const PCB_GROUP*>( aItem ) );
2885
2886 // Similar to logic for footprint, a group is selectable if any of its members are.
2887 // (This recurses.)
2888 for( BOARD_ITEM* item : group->GetItems() )
2889 {
2890 if( Selectable( item, true ) )
2891 return true;
2892 }
2893
2894 return false;
2895 }
2896
2897 if( aItem->GetParentGroup() && aItem->GetParentGroup()->Type() == PCB_GENERATOR_T )
2898 return false;
2899
2900 const ZONE* zone = nullptr;
2901 const PCB_VIA* via = nullptr;
2902 const PAD* pad = nullptr;
2903 const PCB_TEXT* text = nullptr;
2904 const PCB_FIELD* field = nullptr;
2905
2906 // Most footprint children can only be selected in the footprint editor.
2907 if( aItem->GetParentFootprint() && !m_isFootprintEditor && !checkVisibilityOnly )
2908 {
2909 if( aItem->Type() != PCB_FIELD_T && aItem->Type() != PCB_PAD_T
2910 && aItem->Type() != PCB_TEXT_T )
2911 {
2912 return false;
2913 }
2914 }
2915
2916 switch( aItem->Type() )
2917 {
2918 case PCB_ZONE_T:
2919 if( !board()->IsElementVisible( LAYER_ZONES ) || ( options.m_ZoneOpacity == 0.00 ) )
2920 return false;
2921
2922 zone = static_cast<const ZONE*>( aItem );
2923
2924 // A teardrop is modelled as a property of a via, pad or the board (for track-to-track
2925 // teardrops). The underlying zone is only an implementation detail.
2926 if( zone->IsTeardropArea() && !board()->LegacyTeardrops() )
2927 return false;
2928
2929 // zones can exist on multiple layers!
2930 if( !( zone->GetLayerSet() & visibleLayers() ).any() )
2931 return false;
2932
2933 break;
2934
2935 case PCB_TRACE_T:
2936 case PCB_ARC_T:
2937 if( !board()->IsElementVisible( LAYER_TRACKS ) || ( options.m_TrackOpacity == 0.00 ) )
2938 return false;
2939
2940 if( !layerVisible( aItem->GetLayer() ) )
2941 return false;
2942
2943 break;
2944
2945 case PCB_VIA_T:
2946 if( !board()->IsElementVisible( LAYER_VIAS ) || ( options.m_ViaOpacity == 0.00 ) )
2947 return false;
2948
2949 via = static_cast<const PCB_VIA*>( aItem );
2950
2951 // For vias it is enough if only one of its layers is visible
2952 if( !( visibleLayers() & via->GetLayerSet() ).any() )
2953 return false;
2954
2955 break;
2956
2957 case PCB_FIELD_T:
2958 field = static_cast<const PCB_FIELD*>( aItem );
2959
2960 if( field->IsReference() && !view()->IsLayerVisible( LAYER_FP_REFERENCES ) )
2961 return false;
2962
2963 if( field->IsValue() && !view()->IsLayerVisible( LAYER_FP_VALUES ) )
2964 return false;
2965
2966 // Handle all other fields with normal text visibility controls
2968 case PCB_TEXT_T:
2969 text = static_cast<const PCB_TEXT*>( aItem );
2970
2971 if( !text->IsVisible() )
2972 {
2973 if( !m_isFootprintEditor )
2974 return false;
2975 }
2976
2977 if( !layerVisible( text->GetLayer() ) )
2978 return false;
2979
2980 // Apply the LOD visibility test as well
2981 if( !view()->IsVisible( text ) )
2982 return false;
2983
2984 if( aItem->GetParentFootprint() )
2985 {
2986 int controlLayer = LAYER_FP_TEXT;
2987
2988 if( text->GetText() == wxT( "${REFERENCE}" ) )
2989 controlLayer = LAYER_FP_REFERENCES;
2990 else if( text->GetText() == wxT( "${VALUE}" ) )
2991 controlLayer = LAYER_FP_VALUES;
2992
2993 if( !view()->IsLayerVisible( controlLayer ) )
2994 return false;
2995 }
2996
2997 break;
2998
3000 if( options.m_ImageOpacity == 0.00 )
3001 return false;
3002
3003 // Bitmap images on board are hidden if LAYER_DRAW_BITMAPS is not visible
3005 return false;
3006
3008
3009 case PCB_SHAPE_T:
3010 // Note: LAYER_SHAPES does not control the visibility of a PCB_SHAPE_T, only
3011 // the opacity of filled areas
3012 // The visibility is managed by the item layer
3013 if( options.m_FilledShapeOpacity == 0.0 )
3014 return false;
3015
3017
3018 case PCB_TEXTBOX_T:
3019 case PCB_TABLE_T:
3020 case PCB_TABLECELL_T:
3021 if( !layerVisible( aItem->GetLayer() ) )
3022 return false;
3023
3024 if( aItem->Type() == PCB_TABLECELL_T )
3025 {
3026 const PCB_TABLECELL* cell = static_cast<const PCB_TABLECELL*>( aItem );
3027
3028 if( cell->GetRowSpan() == 0 || cell->GetColSpan() == 0 )
3029 return false;
3030 }
3031
3032 break;
3033
3034 case PCB_DIM_ALIGNED_T:
3035 case PCB_DIM_LEADER_T:
3036 case PCB_DIM_CENTER_T:
3037 case PCB_DIM_RADIAL_T:
3039 if( !layerVisible( aItem->GetLayer() ) )
3040 return false;
3041
3042 break;
3043
3044 case PCB_PAD_T:
3045 if( options.m_PadOpacity == 0.00 )
3046 return false;
3047
3048 pad = static_cast<const PAD*>( aItem );
3049
3050 if( pad->GetAttribute() == PAD_ATTRIB::PTH || pad->GetAttribute() == PAD_ATTRIB::NPTH )
3051 {
3052 // A pad's hole is visible on every layer the pad is visible on plus many layers the
3053 // pad is not visible on -- so we only need to check for any visible hole layers.
3054 if( !( visibleLayers() & LSET::PhysicalLayersMask() ).any() )
3055 return false;
3056 }
3057 else
3058 {
3059 if( !( pad->GetLayerSet() & visibleLayers() ).any() )
3060 return false;
3061 }
3062
3063 break;
3064
3065 // These are not selectable
3066 case PCB_NETINFO_T:
3067 case NOT_USED:
3068 case TYPE_NOT_INIT:
3069 return false;
3070
3071 default: // Suppress warnings
3072 break;
3073 }
3074
3075 return true;
3076}
3077
3078
3080{
3081 if( !aItem || aItem->IsSelected() )
3082 return;
3083
3084 if( aItem->Type() == PCB_PAD_T )
3085 {
3086 FOOTPRINT* footprint = static_cast<FOOTPRINT*>( aItem->GetParent() );
3087
3088 if( m_selection.Contains( footprint ) )
3089 return;
3090 }
3091
3092 if( m_enteredGroup &&
3093 !PCB_GROUP::WithinScope( static_cast<BOARD_ITEM*>( aItem ), m_enteredGroup,
3095 {
3096 ExitGroup();
3097 }
3098
3099 highlight( aItem, SELECTED, &m_selection );
3100}
3101
3102
3104{
3105 unhighlight( aItem, SELECTED, &m_selection );
3106}
3107
3108
3109void PCB_SELECTION_TOOL::highlight( EDA_ITEM* aItem, int aMode, SELECTION* aGroup )
3110{
3111 if( aGroup )
3112 aGroup->Add( aItem );
3113
3114 highlightInternal( aItem, aMode, aGroup != nullptr );
3115 view()->Update( aItem, KIGFX::REPAINT );
3116
3117 // Many selections are very temporal and updating the display each time just
3118 // creates noise.
3119 if( aMode == BRIGHTENED )
3121}
3122
3123
3124void PCB_SELECTION_TOOL::highlightInternal( EDA_ITEM* aItem, int aMode, bool aUsingOverlay )
3125{
3126 if( aMode == SELECTED )
3127 aItem->SetSelected();
3128 else if( aMode == BRIGHTENED )
3129 aItem->SetBrightened();
3130
3131 if( aUsingOverlay && aMode != BRIGHTENED )
3132 view()->Hide( aItem, true ); // Hide the original item, so it is shown only on overlay
3133
3134 if( aItem->IsBOARD_ITEM() )
3135 {
3136 BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( aItem );
3137 boardItem->RunOnDescendants( std::bind( &PCB_SELECTION_TOOL::highlightInternal, this, _1,
3138 aMode, aUsingOverlay ) );
3139 }
3140}
3141
3142
3143void PCB_SELECTION_TOOL::unhighlight( EDA_ITEM* aItem, int aMode, SELECTION* aGroup )
3144{
3145 if( aGroup )
3146 aGroup->Remove( aItem );
3147
3148 unhighlightInternal( aItem, aMode, aGroup != nullptr );
3149 view()->Update( aItem, KIGFX::REPAINT );
3150
3151 // Many selections are very temporal and updating the display each time just creates noise.
3152 if( aMode == BRIGHTENED )
3154}
3155
3156
3157void PCB_SELECTION_TOOL::unhighlightInternal( EDA_ITEM* aItem, int aMode, bool aUsingOverlay )
3158{
3159 if( aMode == SELECTED )
3160 aItem->ClearSelected();
3161 else if( aMode == BRIGHTENED )
3162 aItem->ClearBrightened();
3163
3164 if( aUsingOverlay && aMode != BRIGHTENED )
3165 {
3166 view()->Hide( aItem, false ); // Restore original item visibility...
3167 view()->Update( aItem ); // ... and make sure it's redrawn un-selected
3168 }
3169
3170 if( aItem->IsBOARD_ITEM() )
3171 {
3172 BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( aItem );
3173 boardItem->RunOnDescendants( std::bind( &PCB_SELECTION_TOOL::unhighlightInternal, this, _1,
3174 aMode, aUsingOverlay ) );
3175 }
3176}
3177
3178
3180{
3181 const unsigned GRIP_MARGIN = 20;
3182 int margin = KiROUND( getView()->ToWorld( GRIP_MARGIN ) );
3183
3184 // Check if the point is located close to any of the currently selected items
3185 for( EDA_ITEM* item : m_selection )
3186 {
3187 BOX2I itemBox = item->ViewBBox();
3188 itemBox.Inflate( margin ); // Give some margin for gripping an item
3189
3190 if( itemBox.Contains( aPoint ) )
3191 {
3192 if( item->HitTest( aPoint, margin ) )
3193 return true;
3194
3195 bool found = false;
3196
3197 if( PCB_GROUP* group = dynamic_cast<PCB_GROUP*>( item ) )
3198 {
3199 group->RunOnDescendants(
3200 [&]( BOARD_ITEM* aItem )
3201 {
3202 if( aItem->HitTest( aPoint, margin ) )
3203 found = true;
3204 } );
3205 }
3206
3207 if( found )
3208 return true;
3209 }
3210 }
3211
3212 return false;
3213}
3214
3215
3217 int aMaxDistance ) const
3218{
3219 BOX2D viewportD = getView()->GetViewport();
3220 BOX2I viewport = BOX2ISafe( viewportD );
3221 int distance = INT_MAX;
3222 SEG loc( aWhere, aWhere );
3223
3224 switch( aItem->Type() )
3225 {
3226 case PCB_FIELD_T:
3227 case PCB_TEXT_T:
3228 {
3229 PCB_TEXT* text = static_cast<PCB_TEXT*>( aItem );
3230
3231 // Add a bit of slop to text-shapes
3232 if( text->GetEffectiveTextShape()->Collide( loc, aMaxDistance, &distance ) )
3233 distance = std::clamp( distance - ( aMaxDistance / 2 ), 0, distance );
3234
3235 break;
3236 }
3237
3238 case PCB_TEXTBOX_T:
3239 case PCB_TABLECELL_T:
3240 {
3241 PCB_TEXTBOX* textbox = static_cast<PCB_TEXTBOX*>( aItem );
3242
3243 // Add a bit of slop to text-shapes
3244 if( textbox->GetEffectiveTextShape()->Collide( loc, aMaxDistance, &distance ) )
3245 distance = std::clamp( distance - ( aMaxDistance / 2 ), 0, distance );
3246
3247 break;
3248 }
3249
3250 case PCB_TABLE_T:
3251 {
3252 PCB_TABLE* table = static_cast<PCB_TABLE*>( aItem );
3253
3254 for( PCB_TABLECELL* cell : table->GetCells() )
3255 {
3256 // Add a bit of slop to text-shapes
3257 if( cell->GetEffectiveTextShape()->Collide( loc, aMaxDistance, &distance ) )
3258 distance = std::clamp( distance - ( aMaxDistance / 2 ), 0, distance );
3259 }
3260
3261 break;
3262 }
3263
3264 case PCB_ZONE_T:
3265 {
3266 ZONE* zone = static_cast<ZONE*>( aItem );
3267
3268 // Zone borders are very specific
3269 if( zone->HitTestForEdge( aWhere, aMaxDistance / 2 ) )
3270 distance = 0;
3271 else if( zone->HitTestForEdge( aWhere, aMaxDistance ) )
3272 distance = aMaxDistance / 2;
3273 else
3274 aItem->GetEffectiveShape()->Collide( loc, aMaxDistance, &distance );
3275
3276 break;
3277 }
3278
3279 case PCB_FOOTPRINT_T:
3280 {
3281 FOOTPRINT* footprint = static_cast<FOOTPRINT*>( aItem );
3282 BOX2I bbox = footprint->GetBoundingBox( false );
3283
3284 try
3285 {
3286 footprint->GetBoundingHull().Collide( loc, aMaxDistance, &distance );
3287 }
3288 catch( const std::exception& e )
3289 {
3290 wxFAIL_MSG( wxString::Format( wxT( "Clipper exception occurred: %s" ), e.what() ) );
3291 }
3292
3293 // Consider footprints larger than the viewport only as a last resort
3294 if( bbox.GetHeight() > viewport.GetHeight() || bbox.GetWidth() > viewport.GetWidth() )
3295 distance = INT_MAX / 2;
3296
3297 break;
3298 }
3299
3300 case PCB_MARKER_T:
3301 {
3302 PCB_MARKER* marker = static_cast<PCB_MARKER*>( aItem );
3303 SHAPE_LINE_CHAIN polygon;
3304
3305 marker->ShapeToPolygon( polygon );
3306 polygon.Move( marker->GetPos() );
3307 polygon.Collide( loc, aMaxDistance, &distance );
3308 break;
3309 }
3310
3311 case PCB_GROUP_T:
3312 case PCB_GENERATOR_T:
3313 {
3314 PCB_GROUP* group = static_cast<PCB_GROUP*>( aItem );
3315
3316 for( BOARD_ITEM* member : group->GetItems() )
3317 distance = std::min( distance, hitTestDistance( aWhere, member, aMaxDistance ) );
3318
3319 break;
3320 }
3321
3322 case PCB_PAD_T:
3323 {
3324 static_cast<PAD*>( aItem )->Padstack().ForEachUniqueLayer(
3325 [&]( PCB_LAYER_ID aLayer )
3326 {
3327 int layerDistance = INT_MAX;
3328 aItem->GetEffectiveShape( aLayer )->Collide( loc, aMaxDistance, &layerDistance );
3329 distance = std::min( distance, layerDistance );
3330 } );
3331
3332 break;
3333 }
3334
3335 default:
3336 aItem->GetEffectiveShape()->Collide( loc, aMaxDistance, &distance );
3337 break;
3338 }
3339
3340 return distance;
3341}
3342
3343
3345{
3346 wxCHECK( m_frame, /* void */ );
3347
3348 if( aCollector.GetCount() < 2 )
3349 return;
3350
3351 const RENDER_SETTINGS* settings = getView()->GetPainter()->GetSettings();
3352
3353 wxCHECK( settings, /* void */ );
3354
3355 PCB_LAYER_ID activeLayer = m_frame->GetActiveLayer();
3356 LSET visibleLayers = m_frame->GetBoard()->GetVisibleLayers();
3357 LSET enabledLayers = m_frame->GetBoard()->GetEnabledLayers();
3358 LSEQ enabledLayerStack = enabledLayers.SeqStackupTop2Bottom( activeLayer );
3359
3360 wxCHECK( !enabledLayerStack.empty(), /* void */ );
3361
3362 auto isCopperPourKeepoutZone = []( const BOARD_ITEM* aItem ) -> bool
3363 {
3364 if( aItem->Type() == PCB_ZONE_T )
3365 {
3366 const ZONE* zone = static_cast<const ZONE*>( aItem );
3367
3368 wxCHECK( zone, false );
3369
3370 if( zone->GetIsRuleArea()
3371 && zone->GetDoNotAllowCopperPour() )
3372 return true;
3373 }
3374
3375 return false;
3376 };
3377
3378 std::vector<LAYER_OPACITY_ITEM> opacityStackup;
3379
3380 for( int i = 0; i < aCollector.GetCount(); i++ )
3381 {
3382 const BOARD_ITEM* item = aCollector[i];
3383
3384 LSET itemLayers = item->GetLayerSet() & enabledLayers & visibleLayers;
3385 LSEQ itemLayerSeq = itemLayers.Seq( enabledLayerStack );
3386
3387 for( PCB_LAYER_ID layer : itemLayerSeq )
3388 {
3389 COLOR4D color = settings->GetColor( item, layer );
3390
3391 if( color.a == 0 )
3392 continue;
3393
3394 LAYER_OPACITY_ITEM opacityItem;
3395
3396 opacityItem.m_Layer = layer;
3397 opacityItem.m_Opacity = color.a;
3398 opacityItem.m_Item = item;
3399
3400 if( isCopperPourKeepoutZone( item ) )
3401 opacityItem.m_Opacity = 0.0;
3402
3403 opacityStackup.emplace_back( opacityItem );
3404 }
3405 }
3406
3407 std::sort( opacityStackup.begin(), opacityStackup.end(),
3408 [&]( const LAYER_OPACITY_ITEM& aLhs, const LAYER_OPACITY_ITEM& aRhs ) -> bool
3409 {
3410 int retv = enabledLayerStack.TestLayers( aLhs.m_Layer, aRhs.m_Layer );
3411
3412 if( retv )
3413 return retv > 0;
3414
3415 return aLhs.m_Opacity > aRhs.m_Opacity;
3416 } );
3417
3418 std::set<const BOARD_ITEM*> visibleItems;
3419 std::set<const BOARD_ITEM*> itemsToRemove;
3420 double minAlphaLimit = ADVANCED_CFG::GetCfg().m_PcbSelectionVisibilityRatio;
3421 double currentStackupOpacity = 0.0;
3422 PCB_LAYER_ID lastVisibleLayer = PCB_LAYER_ID::UNDEFINED_LAYER;
3423
3424 for( const LAYER_OPACITY_ITEM& opacityItem : opacityStackup )
3425 {
3426 if( lastVisibleLayer == PCB_LAYER_ID::UNDEFINED_LAYER )
3427 {
3428 currentStackupOpacity = opacityItem.m_Opacity;
3429 lastVisibleLayer = opacityItem.m_Layer;
3430 visibleItems.emplace( opacityItem.m_Item );
3431 continue;
3432 }
3433
3434 // Objects to ignore and fallback to the old selection behavior.
3435 auto ignoreItem = [&]()
3436 {
3437 const BOARD_ITEM* item = opacityItem.m_Item;
3438
3439 wxCHECK( item, false );
3440
3441 // Check items that span multiple layers for visibility.
3442 if( visibleItems.count( item ) )
3443 return true;
3444
3445 // Don't prune child items of a footprint that is already visible.
3446 if( item->GetParent()
3447 && ( item->GetParent()->Type() == PCB_FOOTPRINT_T )
3448 && visibleItems.count( item->GetParent() ) )
3449 return true;
3450
3451 // Keepout zones are transparent but for some reason,
3452 // PCB_PAINTER::GetColor() returns the color of the zone it
3453 // prevents from filling.
3454 if( isCopperPourKeepoutZone( item ) )
3455 return true;
3456
3457 return false;
3458 };
3459
3460 // Everything on the currently selected layer is visible;
3461 if( opacityItem.m_Layer == enabledLayerStack[0] )
3462 {
3463 visibleItems.emplace( opacityItem.m_Item );
3464 }
3465 else
3466 {
3467 double itemVisibility = opacityItem.m_Opacity * ( 1.0 - currentStackupOpacity );
3468
3469 if( ( itemVisibility <= minAlphaLimit ) && !ignoreItem() )
3470 itemsToRemove.emplace( opacityItem.m_Item );
3471 else
3472 visibleItems.emplace( opacityItem.m_Item );
3473 }
3474
3475 if( opacityItem.m_Layer != lastVisibleLayer )
3476 {
3477 currentStackupOpacity += opacityItem.m_Opacity * ( 1.0 - currentStackupOpacity );
3478 currentStackupOpacity = std::min( currentStackupOpacity, 1.0 );
3479 lastVisibleLayer = opacityItem.m_Layer;
3480 }
3481 }
3482
3483 for( const BOARD_ITEM* itemToRemove : itemsToRemove )
3484 {
3485 wxCHECK( aCollector.GetCount() > 1, /* void */ );
3486 aCollector.Remove( itemToRemove );
3487 }
3488}
3489
3490
3491// The general idea here is that if the user clicks directly on a small item inside a larger
3492// one, then they want the small item. The quintessential case of this is clicking on a pad
3493// within a footprint, but we also apply it for text within a footprint, footprints within
3494// larger footprints, and vias within either larger pads or longer tracks.
3495//
3496// These "guesses" presume there is area within the larger item to click in to select it. If
3497// an item is mostly covered by smaller items within it, then the guesses are inappropriate as
3498// there might not be any area left to click to select the larger item. In this case we must
3499// leave the items in the collector and bring up a Selection Clarification menu.
3500//
3501// We currently check for pads and text mostly covering a footprint, but we don't check for
3502// smaller footprints mostly covering a larger footprint.
3503//
3505 const VECTOR2I& aWhere ) const
3506{
3507 static const LSET silkLayers( { B_SilkS, F_SilkS } );
3508 static const LSET courtyardLayers( { B_CrtYd, F_CrtYd } );
3509 static std::vector<KICAD_T> singleLayerSilkTypes = { PCB_FIELD_T,
3512 PCB_SHAPE_T };
3513
3514 if( ADVANCED_CFG::GetCfg().m_PcbSelectionVisibilityRatio != 1.0 )
3516
3517 if( aCollector.GetCount() == 1 )
3518 return;
3519
3520 std::set<BOARD_ITEM*> preferred;
3521 std::set<BOARD_ITEM*> rejected;
3522 VECTOR2I where( aWhere.x, aWhere.y );
3523 const RENDER_SETTINGS* settings = getView()->GetPainter()->GetSettings();
3524 PCB_LAYER_ID activeLayer = m_frame->GetActiveLayer();
3525
3526 // If a silk layer is in front, we assume the user is working with silk and give preferential
3527 // treatment to single-layer items on *either* silk layer.
3528 if( silkLayers[activeLayer] )
3529 {
3530 for( int i = 0; i < aCollector.GetCount(); ++i )
3531 {
3532 BOARD_ITEM* item = aCollector[i];
3533
3534 if( item->IsType( singleLayerSilkTypes ) && silkLayers[ item->GetLayer() ] )
3535 preferred.insert( item );
3536 }
3537 }
3538 // Similarly, if a courtyard layer is in front, we assume the user is positioning footprints
3539 // and give preferential treatment to footprints on *both* top and bottom.
3540 else if( courtyardLayers[activeLayer] && settings->GetHighContrast() )
3541 {
3542 for( int i = 0; i < aCollector.GetCount(); ++i )
3543 {
3544 BOARD_ITEM* item = aCollector[i];
3545
3546 if( item->Type() == PCB_FOOTPRINT_T )
3547 preferred.insert( item );
3548 }
3549 }
3550
3551 if( preferred.size() > 0 )
3552 {
3553 aCollector.Empty();
3554
3555 for( BOARD_ITEM* item : preferred )
3556 aCollector.Append( item );
3557
3558 if( preferred.size() == 1 )
3559 return;
3560 }
3561
3562 // Prefer exact hits to sloppy ones
3563 constexpr int MAX_SLOP = 5;
3564
3565 int singlePixel = KiROUND( aCollector.GetGuide()->OnePixelInIU() );
3566 int maxSlop = KiROUND( MAX_SLOP * aCollector.GetGuide()->OnePixelInIU() );
3567 int minSlop = INT_MAX;
3568
3569 std::map<BOARD_ITEM*, int> itemsBySloppiness;
3570
3571 for( int i = 0; i < aCollector.GetCount(); ++i )
3572 {
3573 BOARD_ITEM* item = aCollector[i];
3574 int itemSlop = hitTestDistance( where, item, maxSlop );
3575
3576 itemsBySloppiness[ item ] = itemSlop;
3577
3578 if( itemSlop < minSlop )
3579 minSlop = itemSlop;
3580 }
3581
3582 // Prune sloppier items
3583 if( minSlop < INT_MAX )
3584 {
3585 for( std::pair<BOARD_ITEM*, int> pair : itemsBySloppiness )
3586 {
3587 if( pair.second > minSlop + singlePixel )
3588 aCollector.Transfer( pair.first );
3589 }
3590 }
3591
3592 // If the user clicked on a small item within a much larger one then it's pretty clear
3593 // they're trying to select the smaller one.
3594 constexpr double sizeRatio = 1.5;
3595
3596 std::vector<std::pair<BOARD_ITEM*, double>> itemsByArea;
3597
3598 for( int i = 0; i < aCollector.GetCount(); ++i )
3599 {
3600 BOARD_ITEM* item = aCollector[i];
3601 double area = 0.0;
3602
3603 if( item->Type() == PCB_ZONE_T
3604 && static_cast<ZONE*>( item )->HitTestForEdge( where, maxSlop / 2 ) )
3605 {
3606 // Zone borders are very specific, so make them "small"
3607 area = (double) SEG::Square( singlePixel ) * MAX_SLOP;
3608 }
3609 else if( item->Type() == PCB_VIA_T )
3610 {
3611 // Vias rarely hide other things, and we don't want them deferring to short track
3612 // segments underneath them -- so artificially reduce their size from πr² to r².
3613 area = (double) SEG::Square( static_cast<PCB_VIA*>( item )->GetDrill() / 2 );
3614 }
3615 else if( item->Type() == PCB_REFERENCE_IMAGE_T )
3616 {
3617 BOX2I box = item->GetBoundingBox();
3618 area = (double) box.GetWidth() * box.GetHeight();
3619 }
3620 else
3621 {
3622 try
3623 {
3624 area = FOOTPRINT::GetCoverageArea( item, aCollector );
3625 }
3626 catch( const std::exception& e )
3627 {
3628 wxFAIL_MSG( wxString::Format( wxT( "Clipper exception occurred: %s" ), e.what() ) );
3629 }
3630 }
3631
3632 itemsByArea.emplace_back( item, area );
3633 }
3634
3635 std::sort( itemsByArea.begin(), itemsByArea.end(),
3636 []( const std::pair<BOARD_ITEM*, double>& lhs,
3637 const std::pair<BOARD_ITEM*, double>& rhs ) -> bool
3638 {
3639 return lhs.second < rhs.second;
3640 } );
3641
3642 bool rejecting = false;
3643
3644 for( int i = 1; i < (int) itemsByArea.size(); ++i )
3645 {
3646 if( itemsByArea[i].second > itemsByArea[i-1].second * sizeRatio )
3647 rejecting = true;
3648
3649 if( rejecting )
3650 rejected.insert( itemsByArea[i].first );
3651 }
3652
3653 // Special case: if a footprint is completely covered with other features then there's no
3654 // way to select it -- so we need to leave it in the list for user disambiguation.
3655 constexpr double maxCoverRatio = 0.70;
3656
3657 for( int i = 0; i < aCollector.GetCount(); ++i )
3658 {
3659 if( FOOTPRINT* footprint = dynamic_cast<FOOTPRINT*>( aCollector[i] ) )
3660 {
3661 if( footprint->CoverageRatio( aCollector ) > maxCoverRatio )
3662 rejected.erase( footprint );
3663 }
3664 }
3665
3666 // Hopefully we've now got what the user wanted.
3667 if( (unsigned) aCollector.GetCount() > rejected.size() ) // do not remove everything
3668 {
3669 for( BOARD_ITEM* item : rejected )
3670 aCollector.Transfer( item );
3671 }
3672
3673 // Finally, what we are left with is a set of items of similar coverage area. We now reject
3674 // any that are not on the active layer, to reduce the number of disambiguation menus shown.
3675 // If the user wants to force-disambiguate, they can either switch layers or use the modifier
3676 // key to force the menu.
3677 if( aCollector.GetCount() > 1 )
3678 {
3679 bool haveItemOnActive = false;
3680 rejected.clear();
3681
3682 for( int i = 0; i < aCollector.GetCount(); ++i )
3683 {
3684 if( !aCollector[i]->IsOnLayer( activeLayer ) )
3685 rejected.insert( aCollector[i] );
3686 else
3687 haveItemOnActive = true;
3688 }
3689
3690 if( haveItemOnActive )
3691 {
3692 for( BOARD_ITEM* item : rejected )
3693 aCollector.Transfer( item );
3694 }
3695 }
3696}
3697
3698
3700 bool aMultiselect ) const
3701{
3702 std::unordered_set<BOARD_ITEM*> toAdd;
3703
3704 // Set CANDIDATE on all parents which are included in the GENERAL_COLLECTOR. This
3705 // algorithm is O(3n), whereas checking for the parent inclusion could potentially be O(n^2).
3706 for( int j = 0; j < aCollector.GetCount(); j++ )
3707 {
3708 if( aCollector[j]->GetParent() )
3709 aCollector[j]->GetParent()->ClearFlags( CANDIDATE );
3710 }
3711
3712 if( aMultiselect )
3713 {
3714 for( int j = 0; j < aCollector.GetCount(); j++ )
3715 aCollector[j]->SetFlags( CANDIDATE );
3716 }
3717
3718 for( int j = 0; j < aCollector.GetCount(); )
3719 {
3720 BOARD_ITEM* item = aCollector[j];
3721 BOARD_ITEM* parent = item->GetParent();
3722 BOARD_ITEM* start = item;
3723
3724 if( !m_isFootprintEditor && parent && parent->Type() == PCB_FOOTPRINT_T )
3725 start = parent;
3726
3727 // If a group is entered, disallow selections of objects outside the group.
3729 {
3730 aCollector.Remove( item );
3731 continue;
3732 }
3733
3734 // If any element is a member of a group, replace those elements with the top containing
3735 // group.
3738 {
3739 if( top != item )
3740 {
3741 toAdd.insert( top );
3742 top->SetFlags(CANDIDATE );
3743
3744 aCollector.Remove( item );
3745 continue;
3746 }
3747 }
3748
3749 // Footprints are a bit easier as they can't be nested.
3750 if( parent && ( parent->GetFlags() & CANDIDATE ) )
3751 {
3752 // Remove children of selected items
3753 aCollector.Remove( item );
3754 continue;
3755 }
3756
3757 ++j;
3758 }
3759
3760 for( BOARD_ITEM* item : toAdd )
3761 {
3762 if( !aCollector.HasItem( item ) )
3763 aCollector.Append( item );
3764 }
3765}
3766
3767
3769{
3770 std::set<BOARD_ITEM*> to_add;
3771
3772 // Iterate from the back so we don't have to worry about removals.
3773 for( int i = (int) aCollector.GetCount() - 1; i >= 0; --i )
3774 {
3775 BOARD_ITEM* item = aCollector[i];
3776
3777 if( item->Type() == PCB_TABLECELL_T )
3778 {
3779 if( !aCollector.HasItem( item->GetParent() ) )
3780 to_add.insert( item->GetParent() );
3781
3782 aCollector.Remove( item );
3783 }
3784 }
3785
3786 for( BOARD_ITEM* item : to_add )
3787 aCollector.Append( item );
3788}
3789
3790
3792 bool aForcePromotion ) const
3793{
3794 std::set<BOARD_ITEM*> to_add;
3795
3796 // Iterate from the back so we don't have to worry about removals.
3797 for( int i = aCollector.GetCount() - 1; i >= 0; --i )
3798 {
3799 BOARD_ITEM* item = aCollector[i];
3800
3801 if( !m_isFootprintEditor && item->Type() == PCB_PAD_T
3802 && ( !frame()->GetPcbNewSettings()->m_AllowFreePads || aForcePromotion ) )
3803 {
3804 if( !aCollector.HasItem( item->GetParent() ) )
3805 to_add.insert( item->GetParent() );
3806
3807 aCollector.Remove( item );
3808 }
3809 }
3810
3811 for( BOARD_ITEM* item : to_add )
3812 aCollector.Append( item );
3813}
3814
3815
3817{
3818 // Iterate from the back so we don't have to worry about removals.
3819 for( int i = aCollector.GetCount() - 1; i >= 0; --i )
3820 {
3821 BOARD_ITEM* item = aCollector[i];
3822
3823 if( item->Type() == PCB_MARKER_T )
3824 aCollector.Remove( item );
3825 }
3826}
3827
3828
3830 const VECTOR2I& aWhere ) const
3831{
3832 const RENDER_SETTINGS* settings = getView()->GetPainter()->GetSettings();
3833 BOX2D viewport = getView()->GetViewport();
3834 BOX2I extents = BOX2ISafe( viewport );
3835
3836 bool need_direct_hit = false;
3837 FOOTPRINT* single_fp = nullptr;
3838
3839 // If the designer is not modifying the existing selection AND we already have
3840 // a selection, then we only want to select items that are directly under the cursor.
3841 // This prevents us from being unable to clear the selection when zoomed into a footprint
3843 {
3844 need_direct_hit = true;
3845
3846 for( EDA_ITEM* item : m_selection )
3847 {
3848 FOOTPRINT* fp = nullptr;
3849
3850 if( item->Type() != PCB_FOOTPRINT_T )
3851 fp = static_cast<BOARD_ITEM*>( item )->GetParentFootprint();
3852 else
3853 fp = static_cast<FOOTPRINT*>( item );
3854
3855 // If the selection contains items that are not footprints, then don't restrict
3856 // whether we deselect the item or not.
3857 if( !fp )
3858 {
3859 single_fp = nullptr;
3860 break;
3861 }
3862 else if( !single_fp )
3863 {
3864 single_fp = fp;
3865 }
3866 // If the selection contains items from multiple footprints, then don't restrict
3867 // whether we deselect the item or not.
3868 else if( single_fp != fp )
3869 {
3870 single_fp = nullptr;
3871 break;
3872 }
3873 }
3874 }
3875
3876 auto visibleLayers =
3877 [&]()
3878 {
3880 {
3881 LSET set;
3882
3883 for( PCB_LAYER_ID layer : LSET::AllLayersMask().Seq() )
3884 set.set( layer, view()->IsLayerVisible( layer ) );
3885
3886 return set;
3887 }
3888 else
3889 {
3890 return board()->GetVisibleLayers();
3891 }
3892 };
3893
3894 LSET layers = visibleLayers();
3895
3896 if( settings->GetHighContrast() )
3897 {
3898 layers.reset();
3899
3900 const std::set<int> activeLayers = settings->GetHighContrastLayers();
3901
3902 for( int layer : activeLayers )
3903 {
3904 if( layer >= 0 && layer < PCB_LAYER_ID_COUNT )
3905 layers.set( layer );
3906 }
3907 }
3908
3909 // Iterate from the back so we don't have to worry about removals.
3910 for( int i = aCollector.GetCount() - 1; i >= 0; --i )
3911 {
3912 BOARD_ITEM* item = aCollector[i];
3913 FOOTPRINT* fp = dyn_cast<FOOTPRINT*>( item );
3914
3915 if( !fp )
3916 continue;
3917
3918 // Make footprints not difficult to select in high-contrast modes.
3919 if( layers[fp->GetLayer()] )
3920 continue;
3921
3922 BOX2I bbox = fp->GetLayerBoundingBox( layers );
3923
3924 // If the point clicked is not inside the visible bounding box, we can also remove it.
3925 if( !bbox.Contains( aWhere) )
3926 aCollector.Remove( item );
3927
3928 bool has_hit = false;
3929
3930 for( PCB_LAYER_ID layer : layers.Seq() )
3931 {
3932 if( fp->HitTestOnLayer( extents, false, layer ) )
3933 {
3934 has_hit = true;
3935 break;
3936 }
3937 }
3938
3939 // If the point is outside of the visible bounding box, we can remove it.
3940 if( !has_hit )
3941 {
3942 aCollector.Remove( item );
3943 }
3944 // Do not require a direct hit on this fp if the existing selection only contains
3945 // this fp's items. This allows you to have a selection of pads from a single
3946 // footprint and still click in the center of the footprint to select it.
3947 else if( single_fp )
3948 {
3949 if( fp == single_fp )
3950 continue;
3951 }
3952 else if( need_direct_hit )
3953 {
3954 has_hit = false;
3955
3956 for( PCB_LAYER_ID layer : layers.Seq() )
3957 {
3958 if( fp->HitTestOnLayer( aWhere, layer ) )
3959 {
3960 has_hit = true;
3961 break;
3962 }
3963 }
3964
3965 if( !has_hit )
3966 aCollector.Remove( item );
3967 }
3968 }
3969}
3970
3971
3973{
3974 getView()->Update( &m_selection );
3976
3977 return 0;
3978}
3979
3980
3982{
3983 std::set<std::pair<PCB_TABLE*, int>> columns;
3984 bool added = false;
3985
3986 for( EDA_ITEM* item : m_selection )
3987 {
3988 if( PCB_TABLECELL* cell = dynamic_cast<PCB_TABLECELL*>( item ) )
3989 {
3990 PCB_TABLE* table = static_cast<PCB_TABLE*>( cell->GetParent() );
3991 columns.insert( std::make_pair( table, cell->GetColumn() ) );
3992 }
3993 }
3994
3995 for( auto& [ table, col ] : columns )
3996 {
3997 for( int row = 0; row < table->GetRowCount(); ++row )
3998 {
3999 PCB_TABLECELL* cell = table->GetCell( row, col );
4000
4001 if( !cell->IsSelected() )
4002 {
4003 select( table->GetCell( row, col ) );
4004 added = true;
4005 }
4006 }
4007 }
4008
4009 if( added )
4011
4012 return 0;
4013}
4014
4015
4017{
4018 std::set<std::pair<PCB_TABLE*, int>> rows;
4019 bool added = false;
4020
4021 for( EDA_ITEM* item : m_selection )
4022 {
4023 if( PCB_TABLECELL* cell = dynamic_cast<PCB_TABLECELL*>( item ) )
4024 {
4025 PCB_TABLE* table = static_cast<PCB_TABLE*>( cell->GetParent() );
4026 rows.insert( std::make_pair( table, cell->GetRow() ) );
4027 }
4028 }
4029
4030 for( auto& [ table, row ] : rows )
4031 {
4032 for( int col = 0; col < table->GetColCount(); ++col )
4033 {
4034 PCB_TABLECELL* cell = table->GetCell( row, col );
4035
4036 if( !cell->IsSelected() )
4037 {
4038 select( table->GetCell( row, col ) );
4039 added = true;
4040 }
4041 }
4042 }
4043
4044 if( added )
4046
4047 return 0;
4048}
4049
4050
4052{
4053 std::set<PCB_TABLE*> tables;
4054 bool added = false;
4055
4056 for( EDA_ITEM* item : m_selection )
4057 {
4058 if( PCB_TABLECELL* cell = dynamic_cast<PCB_TABLECELL*>( item ) )
4059 tables.insert( static_cast<PCB_TABLE*>( cell->GetParent() ) );
4060 }
4061
4063
4064 for( PCB_TABLE* table : tables )
4065 {
4066 if( !table->IsSelected() )
4067 {
4068 select( table );
4069 added = true;
4070 }
4071 }
4072
4073 if( added )
4075
4076 return 0;
4077}
4078
4079
4081{
4083
4087
4094
4113
4116
4118}
int color
Definition: DXF_plotter.cpp:58
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:108
constexpr BOX2I BOX2ISafe(const BOX2D &aInput)
Definition: box2.h:929
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition: box2.h:990
static TOOL_ACTION cancelInteractive
Definition: actions.h:65
static TOOL_ACTION unselectAll
Definition: actions.h:76
static TOOL_ACTION cursorLeft
Definition: actions.h:161
static TOOL_ACTION zoomOutCenter
Definition: actions.h:128
static TOOL_ACTION zoomIn
Definition: actions.h:125
static TOOL_ACTION cursorLeftFast
Definition: actions.h:166
static TOOL_ACTION selectColumns
Definition: actions.h:95
static TOOL_ACTION cursorDown
Definition: actions.h:160
static TOOL_ACTION zoomOut
Definition: actions.h:126
static TOOL_ACTION cursorRightFast
Definition: actions.h:167
static TOOL_ACTION zoomCenter
Definition: actions.h:133
static TOOL_ACTION panDown
Definition: actions.h:174
static TOOL_ACTION cursorDownFast
Definition: actions.h:165
static TOOL_ACTION selectRows
Definition: actions.h:94
static TOOL_ACTION cursorUpFast
Definition: actions.h:164
static TOOL_ACTION panLeft
Definition: actions.h:175
static TOOL_ACTION updateMenu
Definition: actions.h:220
static TOOL_ACTION doDelete
Definition: actions.h:78
static TOOL_ACTION zoomFitScreen
Definition: actions.h:134
static TOOL_ACTION increment
Definition: actions.h:87
static TOOL_ACTION panUp
Definition: actions.h:173
static TOOL_ACTION zoomFitObjects
Definition: actions.h:135
static TOOL_ACTION zoomInCenter
Definition: actions.h:127
static TOOL_ACTION panRight
Definition: actions.h:176
static TOOL_ACTION selectTable
Definition: actions.h:96
static TOOL_ACTION cursorUp
Cursor control with keyboard.
Definition: actions.h:159
static TOOL_ACTION cursorRight
Definition: actions.h:162
static TOOL_ACTION selectAll
Definition: actions.h:75
Defines the structure of a menu based on ACTIONs.
Definition: action_menu.h:49
void SetTitle(const wxString &aTitle) override
Set title for the menu.
Definition: action_menu.cpp:92
wxMenuItem * Add(const wxString &aLabel, int aId, BITMAPS aIcon)
Add a wxWidgets-style entry to the menu.
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
CROSS_PROBING_SETTINGS m_CrossProbing
Definition: app_settings.h:170
BASE_SET & reset(size_t pos)
Definition: base_set.h:142
BASE_SET & set(size_t pos)
Definition: base_set.h:115
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
static bool ClassOf(const EDA_ITEM *aItem)
Returns information if the object is derived from BOARD_CONNECTED_ITEM.
Tool for pcb inspection.
int ClearHighlight(const TOOL_EVENT &aEvent)
Perform the appropriate action in response to an Eeschema cross-probe.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:79
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:237
virtual bool IsConnected() const
Returns information if the object is derived from BOARD_CONNECTED_ITEM.
Definition: board_item.h:133
PCB_GROUP * GetParentGroup() const
Definition: board_item.h:90
virtual VECTOR2I GetCenter() const
This defaults to the center of the bounding box if not overridden.
Definition: board_item.h:111
virtual std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING aFlash=FLASHING::DEFAULT) const
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
Definition: board_item.cpp:279
FOOTPRINT * GetParentFootprint() const
Definition: board_item.cpp:299
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition: board_item.h:257
virtual bool IsLocked() const
Definition: board_item.cpp:75
BOARD_ITEM_CONTAINER * GetParent() const
Definition: board_item.h:215
virtual bool IsOnCopperLayer() const
Definition: board_item.h:150
virtual void RunOnDescendants(const std::function< void(BOARD_ITEM *)> &aFunction, int aDepth=0) const
Invoke a function on all descendants.
Definition: board_item.h:212
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:290
INSPECT_RESULT Visit(INSPECTOR inspector, void *testData, const std::vector< KICAD_T > &scanTypes) override
May be re-implemented for each derived class in order to handle all the types given by its member dat...
Definition: board.cpp:1769
ZONE * m_SolderMaskBridges
Definition: board.h:1308
LSET GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition: board.cpp:775
LSET GetVisibleLayers() const
A proxy function that calls the correspondent function in m_BoardSettings.
Definition: board.cpp:789
bool IsElementVisible(GAL_LAYER_ID aLayer) const
Test whether a given element category is visible.
Definition: board.cpp:841
bool IsLayerVisible(PCB_LAYER_ID aLayer) const
A proxy function that calls the correspondent function in m_BoardSettings tests whether a given layer...
Definition: board.cpp:781
bool LegacyTeardrops() const
Definition: board.h:1261
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Return a list of missing connections between components/tracks.
Definition: board.h:475
constexpr void SetMaximum()
Definition: box2.h:80
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:558
constexpr BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition: box2.h:146
constexpr size_type GetWidth() const
Definition: box2.h:214
constexpr Vec Centre() const
Definition: box2.h:97
constexpr size_type GetHeight() const
Definition: box2.h:215
constexpr bool Contains(const Vec &aPoint) const
Definition: box2.h:168
constexpr const Vec & GetOrigin() const
Definition: box2.h:210
constexpr const SizeVec & GetSize() const
Definition: box2.h:206
CN_ANCHOR represents a physical location that can be connected: a pad or a track/arc/via endpoint.
bool Dirty() const
BOARD_CONNECTED_ITEM * Parent() const
CN_EDGE represents a point-to-point connection, whether realized or unrealized (ie: tracks etc.
virtual double OnePixelInIU() const =0
void Transfer(int aIndex)
Move the item at aIndex (first position is 0) to the backup list.
Definition: collector.h:151
void Empty()
Clear the list.
Definition: collector.h:89
int GetCount() const
Return the number of objects in the list.
Definition: collector.h:81
bool HasItem(const EDA_ITEM *aItem) const
Tests if aItem has already been collected.
Definition: collector.h:195
void Remove(int aIndex)
Remove the item at aIndex (first position is 0).
Definition: collector.h:109
void Append(EDA_ITEM *item)
Add an item to the end of the list.
Definition: collector.h:99
int ShowModal() override
bool IsType(FRAME_T aType) const
void AddStandardSubMenus(TOOL_MENU &aMenu)
Construct a "basic" menu for a tool, containing only items that apply to all tools (e....
void FocusOnLocation(const VECTOR2I &aPos)
Useful to focus on a particular location, in find functions.
void ForceRefresh()
Force a redraw.
void SetCurrentCursor(KICURSOR aCursor)
Set the current cursor shape for this panel.
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:89
virtual VECTOR2I GetPosition() const
Definition: eda_item.h:243
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
Definition: eda_item.cpp:77
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:127
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:101
void ClearSelected()
Definition: eda_item.h:122
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: eda_item.h:129
bool IsSelected() const
Definition: eda_item.h:110
void SetSelected()
Definition: eda_item.h:119
virtual bool IsType(const std::vector< KICAD_T > &aScanTypes) const
Check whether the item is one of the listed types.
Definition: eda_item.h:176
void ClearBrightened()
Definition: eda_item.h:123
void SetBrightened()
Definition: eda_item.h:120
virtual bool HitTest(const VECTOR2I &aPosition, int aAccuracy=0) const
Test if aPosition is inside or on the boundary of this item.
Definition: eda_item.h:216
EDA_ITEM * GetParent() const
Definition: eda_item.h:103
bool HasFlag(EDA_ITEM_FLAGS aFlag) const
Definition: eda_item.h:131
EDA_ITEM_FLAGS GetFlags() const
Definition: eda_item.h:130
SHAPE_T GetShape() const
Definition: eda_shape.h:125
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition: eda_shape.h:167
bool IsClosed() const
Definition: eda_shape.cpp:247
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition: eda_shape.h:130
std::shared_ptr< SHAPE_COMPOUND > GetEffectiveTextShape(bool aTriangulate=true, const BOX2I &aBBox=BOX2I(), const EDA_ANGLE &aAngle=ANGLE_0) const
build a list of segments (SHAPE_SEGMENT) to describe a text shape.
Definition: eda_text.cpp:1023
static const TOOL_EVENT DisambiguatePoint
Used for hotkey feedback.
Definition: actions.h:309
static const TOOL_EVENT ClearedEvent
Definition: actions.h:294
static const TOOL_EVENT InhibitSelectionEditing
Definition: actions.h:305
static const TOOL_EVENT SelectedEvent
Definition: actions.h:292
static const TOOL_EVENT SelectedItemsModified
Selected items were moved, this can be very high frequency on the canvas, use with care.
Definition: actions.h:299
static const TOOL_EVENT UninhibitSelectionEditing
Used to inform tool that it should display the disambiguation menu.
Definition: actions.h:306
static const TOOL_EVENT PointSelectedEvent
Definition: actions.h:291
static const TOOL_EVENT SelectedItemsMoved
Used to inform tools that the selection should temporarily be non-editable.
Definition: actions.h:302
static const TOOL_EVENT UnselectedEvent
Definition: actions.h:293
ZONES & Zones()
Definition: footprint.h:212
static double GetCoverageArea(const BOARD_ITEM *aItem, const GENERAL_COLLECTOR &aCollector)
Definition: footprint.cpp:2654
const BOX2I GetLayerBoundingBox(LSET aLayers) const
Return the bounding box of the footprint on a given set of layers.
Definition: footprint.cpp:1398
PCB_LAYER_ID GetSide() const
Use instead of IsFlipped() when you also need to account for unsided footprints (those purely on user...
Definition: footprint.cpp:1615
std::deque< PAD * > & Pads()
Definition: footprint.h:206
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition: footprint.h:236
bool IsFlipped() const
Definition: footprint.h:391
SHAPE_POLY_SET GetBoundingHull() const
Return a bounding polygon for the shapes and pads in the footprint.
Definition: footprint.cpp:1443
bool IsLocked() const override
Definition: footprint.h:411
bool HitTestOnLayer(const VECTOR2I &aPosition, PCB_LAYER_ID aLayer, int aAccuracy=0) const
Test if the point hits one or more of the footprint elements on a given layer.
Definition: footprint.cpp:1677
const KIID_PATH & GetPath() const
Definition: footprint.h:263
DRAWINGS & GraphicalItems()
Definition: footprint.h:209
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: footprint.cpp:1252
A general implementation of a COLLECTORS_GUIDE.
Definition: collectors.h:319
void SetIgnoreBlindBuriedVias(bool ignore)
Definition: collectors.h:458
void SetIgnoreTracks(bool ignore)
Definition: collectors.h:464
void SetIgnoreFootprintsOnFront(bool ignore)
Definition: collectors.h:422
void SetIgnoreFPTextOnFront(bool ignore)
Definition: collectors.h:410
void SetIgnoreMicroVias(bool ignore)
Definition: collectors.h:461
void SetIgnoreZoneFills(bool ignore)
Definition: collectors.h:467
void SetIgnorePadsOnBack(bool ignore)
Definition: collectors.h:428
void SetIgnoreFPTextOnBack(bool ignore)
Definition: collectors.h:404
void SetIgnoreThroughVias(bool ignore)
Definition: collectors.h:455
void SetIgnoreThroughHolePads(bool ignore)
Definition: collectors.h:440
void SetLayerVisibleBits(LSET aLayerBits)
Definition: collectors.h:378
void SetIgnoreFPReferences(bool ignore)
Definition: collectors.h:452
void SetIgnoreFPValues(bool ignore)
Definition: collectors.h:446
void SetIgnorePadsOnFront(bool ignore)
Definition: collectors.h:434
void SetIgnoreFootprintsOnBack(bool ignore)
Definition: collectors.h:416
Used when the right click button is pressed, or when the select tool is in effect.
Definition: collectors.h:202
void SetGuide(const COLLECTORS_GUIDE *aGuide)
Record which COLLECTORS_GUIDE to use.
Definition: collectors.h:286
const COLLECTORS_GUIDE * GetGuide() const
Definition: collectors.h:288
static const std::vector< KICAD_T > AllBoardItems
A scan list for all editable board items.
Definition: collectors.h:222
void Collect(BOARD_ITEM *aItem, const std::vector< KICAD_T > &aScanList, const VECTOR2I &aRefPos, const COLLECTORS_GUIDE &aGuide)
Scan a BOARD_ITEM using this class's Inspector method, which does the collection.
Definition: collectors.cpp:482
static const std::vector< KICAD_T > FootprintItems
A scan list for primary footprint items.
Definition: collectors.h:248
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:104
virtual RENDER_SETTINGS * GetSettings()=0
Return a pointer to current settings that are going to be used when drawing items.
virtual void Update(const VIEW_ITEM *aItem, int aUpdateFlags) const override
For dynamic VIEWs, inform the associated VIEW that the graphical representation of this item has chan...
Definition: pcb_view.cpp:91
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1) override
Add a VIEW_ITEM to the view.
Definition: pcb_view.cpp:57
virtual void Remove(VIEW_ITEM *aItem) override
Remove a VIEW_ITEM from the view.
Definition: pcb_view.cpp:74
Represent a selection area (currently a rectangle) in a VIEW, drawn corner-to-corner between two poin...
void SetSubtractive(bool aSubtractive)
void SetAdditive(bool aAdditive)
void SetOrigin(const VECTOR2I &aOrigin)
const BOX2I ViewBBox() const override
Set the origin of the rectangle (the fixed corner)
void SetExclusiveOr(bool aExclusiveOr)
void SetEnd(const VECTOR2I &aEnd)
Set the current end of the rectangle (the corner that moves with the cursor.
Container for all the knowledge about how graphical objects are drawn on any output surface/device.
const std::set< int > & GetHighlightNetCodes() const
Return the netcode of currently highlighted net.
const std::set< int > GetHighContrastLayers() const
Returns the set of currently high-contrast layers.
virtual COLOR4D GetColor(const VIEW_ITEM *aItem, int aLayer) const =0
Returns the color that should be used to draw the specific VIEW_ITEM on the specific layer using curr...
bool GetHighContrast() const
void SetHighlight(bool aEnabled, int aNetcode=-1, bool aMulti=false)
Turns on/off highlighting.
virtual void SetAutoPan(bool aEnabled)
Turn on/off auto panning (this feature is used when there is a tool active (eg.
virtual void Clear()
Remove all the stored items from the group.
Definition: view_group.cpp:70
virtual void Add(VIEW_ITEM *aItem)
Add an item to the group.
Definition: view_group.cpp:58
An abstract base class for deriving all objects that can be added to a VIEW.
Definition: view_item.h:84
bool IsBOARD_ITEM() const
Definition: view_item.h:100
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition: view.h:68
double GetScale() const
Definition: view.h:277
BOX2D GetViewport() const
Return the current viewport visible area rectangle.
Definition: view.cpp:547
virtual void SetScale(double aScale, VECTOR2D aAnchor={ 0, 0 })
Set the scaling factor, zooming around a given anchor point.
Definition: view.cpp:587
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition: view.cpp:357
void UpdateAllLayersColor()
Apply the new coloring scheme to all layers.
Definition: view.cpp:804
int Query(const BOX2I &aRect, std::vector< LAYER_ITEM_PAIR > &aResult) const
Find all visible items that touch or are within the rectangle aRect.
Definition: view.cpp:437
virtual void Update(const VIEW_ITEM *aItem, int aUpdateFlags) const
For dynamic VIEWs, inform the associated VIEW that the graphical representation of this item has chan...
Definition: view.cpp:1687
VECTOR2D ToWorld(const VECTOR2D &aCoord, bool aAbsolute=true) const
Converts a screen space point/vector to a point/vector in world space coordinates.
Definition: view.cpp:484
bool IsMirroredX() const
Return true if view is flipped across the X axis.
Definition: view.h:251
std::pair< VIEW_ITEM *, int > LAYER_ITEM_PAIR
Definition: view.h:72
void Hide(VIEW_ITEM *aItem, bool aHide=true, bool aHideOverlay=false)
Temporarily hide the item in the view (e.g.
Definition: view.cpp:1635
bool IsLayerVisible(int aLayer) const
Return information about visibility of a particular layer.
Definition: view.h:418
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition: view.h:221
void SetCenter(const VECTOR2D &aCenter)
Set the center point of the VIEW (i.e.
Definition: view.cpp:613
void MarkTargetDirty(int aTarget)
Set or clear target 'dirty' flag.
Definition: view.h:625
bool IsVisible(const VIEW_ITEM *aItem) const
Return information if the item is visible (or not).
Definition: view.cpp:1657
void SetVisible(VIEW_ITEM *aItem, bool aIsVisible=true)
Set the item visibility.
Definition: view.cpp:1614
wxString AsString() const
Definition: kiid.cpp:348
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
Definition: lseq.h:47
LSET is a set of PCB_LAYER_IDs.
Definition: lset.h:36
static LSET AllLayersMask()
Definition: lset.cpp:701
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:676
static LSET PhysicalLayersMask()
Return a mask holding all layers which are physically realized.
Definition: lset.cpp:756
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:410
LSEQ SeqStackupTop2Bottom(PCB_LAYER_ID aSelectedLayer=UNDEFINED_LAYER) const
Generate a sequence of layers that represent a top to bottom stack of this set of layers.
Definition: lset.cpp:440
static LSET FrontMask()
Return a mask holding all technical layers and the external CU layer on front side.
Definition: lset.cpp:772
static LSET BackMask()
Return a mask holding all technical layers and the external CU layer on back side.
Definition: lset.cpp:779
bool Contains(PCB_LAYER_ID aLayer) const
See if the layer set contains a PCB layer.
Definition: lset.h:60
const VECTOR2I & GetPos() const
Definition: marker_base.h:88
void ShapeToPolygon(SHAPE_LINE_CHAIN &aPolygon, int aScale=-1) const
Return the shape polygon in internal units in a SHAPE_LINE_CHAIN the coordinates are relatives to the...
Handle the data for a net.
Definition: netinfo.h:56
Definition: pad.h:54
TRACK_DRAG_ACTION m_TrackDragAction
LOCKING_OPTIONS m_LockingOptions
static TOOL_ACTION drag45Degree
Definition: pcb_actions.h:197
static TOOL_ACTION unrouteSelected
Removes all tracks from the selected items to the first pad.
Definition: pcb_actions.h:93
static TOOL_ACTION selectionCursor
Select a single item under the cursor position.
Definition: pcb_actions.h:65
static TOOL_ACTION groupLeave
Definition: pcb_actions.h:536
static TOOL_ACTION grabUnconnected
Select and move nearest unconnected footprint from ratsnest of selection.
Definition: pcb_actions.h:105
static TOOL_ACTION filterSelection
Filter the items in the current selection (invokes dialog)
Definition: pcb_actions.h:117
static TOOL_ACTION highlightNet
Definition: pcb_actions.h:558
static TOOL_ACTION unselectItem
Definition: pcb_actions.h:72
static TOOL_ACTION hideLocalRatsnest
Definition: pcb_actions.h:568
static TOOL_ACTION properties
Activation of the edit tool.
Definition: pcb_actions.h:180
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: pcb_actions.h:68
static TOOL_ACTION selectOnSheetFromEeschema
Select all components on sheet from Eeschema crossprobing.
Definition: pcb_actions.h:108
static TOOL_ACTION selectConnection
Select tracks between junctions or expands an existing selection to pads or the entire connection.
Definition: pcb_actions.h:90
static TOOL_ACTION dragFreeAngle
Definition: pcb_actions.h:198
static TOOL_ACTION clearHighlight
Definition: pcb_actions.h:557
static TOOL_ACTION unselectItems
Definition: pcb_actions.h:77
static TOOL_ACTION selectUnconnected
Select unconnected footprints from ratsnest of selection.
Definition: pcb_actions.h:102
static TOOL_ACTION moveIndividually
move items one-by-one
Definition: pcb_actions.h:123
static TOOL_ACTION syncSelection
Sets selection to specified items, zooms to fit, if enabled.
Definition: pcb_actions.h:80
static TOOL_ACTION groupEnter
Definition: pcb_actions.h:535
static TOOL_ACTION selectItem
Select an item (specified as the event parameter).
Definition: pcb_actions.h:71
static TOOL_ACTION selectSameSheet
Select all components on the same sheet as the selected footprint.
Definition: pcb_actions.h:111
static TOOL_ACTION selectNet
Select all connections belonging to a single net.
Definition: pcb_actions.h:96
static TOOL_ACTION selectionActivate
Activation of the selection tool.
Definition: pcb_actions.h:62
static TOOL_ACTION move
move or drag an item
Definition: pcb_actions.h:120
static TOOL_ACTION syncSelectionWithNets
Sets selection to specified items with connected nets, zooms to fit, if enabled.
Definition: pcb_actions.h:83
static TOOL_ACTION selectItems
Select a list of items (specified as the event parameter)
Definition: pcb_actions.h:76
static TOOL_ACTION deselectNet
Remove all connections belonging to a single net from the active selection.
Definition: pcb_actions.h:99
static TOOL_ACTION selectionMenu
Run a selection menu to select from a list of items.
Definition: pcb_actions.h:86
static TOOL_ACTION reselectItem
Definition: pcb_actions.h:73
static TOOL_ACTION selectOnSchematic
Select symbols/pins on schematic corresponding to selected footprints/pads.
Definition: pcb_actions.h:114
Base PCB main window class for Pcbnew, Gerbview, and CvPcb footprint viewer.
const PCB_DISPLAY_OPTIONS & GetDisplayOptions() const
Display options control the way tracks, vias, outlines and other things are shown (for instance solid...
PCBNEW_SETTINGS * GetPcbNewSettings() const
virtual PCB_LAYER_ID GetActiveLayer() const
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
BOARD * GetBoard() const
void FocusOnItem(BOARD_ITEM *aItem, PCB_LAYER_ID aLayer=UNDEFINED_LAYER)
double m_TrackOpacity
Opacity override for all tracks.
double m_FilledShapeOpacity
Opacity override for graphic shapes.
double m_ZoneOpacity
Opacity override for filled zone areas.
double m_ImageOpacity
Opacity override for user images.
double m_PadOpacity
Opacity override for SMD pads and PTHs.
double m_ViaOpacity
Opacity override for all types of via.
ZONE_DISPLAY_MODE m_ZoneDisplayMode
virtual KIGFX::PCB_VIEW * GetView() const override
Return a pointer to the #VIEW instance used in the panel.
bool IsReference() const
Definition: pcb_field.h:70
bool IsValue() const
Definition: pcb_field.h:71
A set of BOARD_ITEMs (i.e., without duplicates).
Definition: pcb_group.h:52
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: pcb_group.cpp:263
static bool WithinScope(BOARD_ITEM *aItem, PCB_GROUP *aScope, bool isFootprintEditor)
Definition: pcb_group.cpp:157
static PCB_GROUP * TopLevelGroup(BOARD_ITEM *aItem, PCB_GROUP *aScope, bool isFootprintEditor)
Definition: pcb_group.cpp:151
std::unordered_set< BOARD_ITEM * > & GetItems()
Definition: pcb_group.h:69
void RunOnChildren(const std::function< void(BOARD_ITEM *)> &aFunction) const override
Invoke a function on all descendants.
Definition: pcb_group.cpp:401
Tool that displays edit points allowing to modify items by dragging the points.
bool HasPoint()
Indicate the cursor is over an edit point.
Private implementation of firewalled private data.
DIALOG_FILTER_SELECTION::OPTIONS m_filterOpts
The selection tool: currently supports:
void highlight(EDA_ITEM *aItem, int aHighlightMode, SELECTION *aGroup=nullptr) override
Highlight the item visually.
int syncSelectionWithNets(const TOOL_EVENT &aEvent)
int SelectTable(const TOOL_EVENT &aEvent)
Clear current selection event handler.
PCB_BASE_FRAME * frame() const
int syncSelection(const TOOL_EVENT &aEvent)
int selectNet(const TOOL_EVENT &aEvent)
Select all copper connections belonging to the same net(s) as the items in the selection.
int filterSelection(const TOOL_EVENT &aEvent)
Return true if the given item passes the current SELECTION_FILTER_OPTIONS.
void Reset(RESET_REASON aReason) override
Bring the tool to a known, initial state.
void ZoomFitCrossProbeBBox(const BOX2I &bbox)
void doSyncSelection(const std::vector< BOARD_ITEM * > &aItems, bool aWithNets)
Invoke filter dialog and modify current selection.
void GuessSelectionCandidates(GENERAL_COLLECTOR &aCollector, const VECTOR2I &aWhere) const
Try to guess best selection candidates in case multiple items are clicked, by doing some brain-dead h...
bool itemPassesFilter(BOARD_ITEM *aItem, bool aMultiSelect)
bool isExpandableGraphicShape(const EDA_ITEM *aItem) const
int disambiguateCursor(const TOOL_EVENT &aEvent)
Handle disambiguation actions including displaying the menu.
void FilterCollectorForMarkers(GENERAL_COLLECTOR &aCollector) const
Drop any PCB_MARKERs from the collector.
int UnselectAll(const TOOL_EVENT &aEvent)
void unhighlightInternal(EDA_ITEM *aItem, int aHighlightMode, bool aUsingOverlay)
bool selectionContains(const VECTOR2I &aPoint) const
void select(EDA_ITEM *aItem) override
Take necessary action mark an item as selected.
bool selectCursor(bool aForceSelect=false, CLIENT_SELECTION_FILTER aClientFilter=nullptr)
Select an item under the cursor unless there is something already selected.
int SelectColumns(const TOOL_EVENT &aEvent)
std::unique_ptr< PRIV > m_priv
PCB_SELECTION & RequestSelection(CLIENT_SELECTION_FILTER aClientFilter, bool aConfirmLockedItems=false)
Return the current selection, filtered according to aClientFilter.
int unrouteSelected(const TOOL_EVENT &aEvent)
Unroute the selected board connected items.
SELECTION & selection() override
Return a reference to the selection.
int grabUnconnected(const TOOL_EVENT &aEvent)
Select and move other nearest footprint unconnected on same net as selected items.
void FilterCollectorForFreePads(GENERAL_COLLECTOR &aCollector, bool aForcePromotion=false) const
Check the "allow free pads" setting and if disabled, replace any pads in the collector with their par...
const GENERAL_COLLECTORS_GUIDE getCollectorsGuide() const
bool Selectable(const BOARD_ITEM *aItem, bool checkVisibilityOnly=false) const
void FilterCollectedItems(GENERAL_COLLECTOR &aCollector, bool aMultiSelect)
Apply the SELECTION_FITLER_OPTIONS to the collector.
bool selectPoint(const VECTOR2I &aWhere, bool aOnDrag=false, bool *aSelectionCancelledFlag=nullptr, CLIENT_SELECTION_FILTER aClientFilter=nullptr)
Select an item pointed by the parameter aWhere.
KIGFX::PCB_VIEW * view() const
void selectAllItemsOnSheet(wxString &aSheetPath)
Select all items with the given sheet timestamp/UUID name (the sheet path).
void FilterCollectorForHierarchy(GENERAL_COLLECTOR &aCollector, bool aMultiselect) const
In general we don't want to select both a parent and any of it's children.
void setTransitions() override
Zoom the screen to center and fit the current selection.
int expandConnection(const TOOL_EVENT &aEvent)
Expand the current connected-item selection to the next boundary (junctions, pads,...
int selectUnconnected(const TOOL_EVENT &aEvent)
Select nearest unconnected footprints on same net as selected items.
virtual bool ctrlClickHighlights() override
Determines if ctrl-click is highlight net or XOR selection.
int selectSheetContents(const TOOL_EVENT &aEvent)
Select all footprints belonging to same hierarchical sheet as the selected footprint (same sheet path...
int SelectRows(const TOOL_EVENT &aEvent)
int selectSameSheet(const TOOL_EVENT &aEvent)
Set selection to items passed by parameter and connected nets (optionally).
void EnterGroup()
Enter the group at the head of the current selection.
void zoomFitSelection()
Zoom the screen to fit the bounding box for cross probing/selection sync.
void selectAllConnectedTracks(const std::vector< BOARD_CONNECTED_ITEM * > &aStartItems, STOP_CONDITION aStopCondition)
Select connected tracks and vias.
int CursorSelection(const TOOL_EVENT &aEvent)
int ClearSelection(const TOOL_EVENT &aEvent)
void highlightInternal(EDA_ITEM *aItem, int aHighlightMode, bool aUsingOverlay)
PCB_BASE_FRAME * m_frame
PCB_SELECTION_FILTER_OPTIONS m_filter
PCB_SELECTION & GetSelection()
@ STOP_AT_PAD
Stop when reaching a pad.
@ STOP_NEVER
Select the entire net.
@ STOP_AT_JUNCTION
Stop at any place where more than two traces meet.
int Main(const TOOL_EVENT &aEvent)
The main loop.
void RebuildSelection()
Rebuild the selection from the EDA_ITEMs' selection flags.
void pruneObscuredSelectionCandidates(GENERAL_COLLECTOR &aCollector) const
void OnIdle(wxIdleEvent &aEvent)
PCB_DRAW_PANEL_GAL * canvas() const
void FilterCollectorForFootprints(GENERAL_COLLECTOR &aCollector, const VECTOR2I &aWhere) const
Drop footprints that are not directly selected.
void FindItem(BOARD_ITEM *aItem)
Take necessary actions to mark an item as found.
int updateSelection(const TOOL_EVENT &aEvent)
Event handler to update the selection VIEW_ITEM.
bool Init() override
Init() is called once upon a registration of the tool.
BOARD * board() const
KIGFX::VIEW_GROUP m_enteredGroupOverlay
void selectConnections(const std::vector< BOARD_ITEM * > &aItems)
int hitTestDistance(const VECTOR2I &aWhere, BOARD_ITEM *aItem, int aMaxDistance) const
void selectAllConnectedShapes(const std::vector< PCB_SHAPE * > &aStartItems)
Select all non-closed shapes that are graphically connected to the given start items.
void SelectAllItemsOnNet(int aNetCode, bool aSelect=true)
Select all items with the given net code.
void FilterCollectorForTableCells(GENERAL_COLLECTOR &aCollector) const
Promote any table cell selections to the whole table.
bool selectMultiple()
Handle drawing a selection box that allows one to select many items at the same time.
void ExitGroup(bool aSelectGroup=false)
Leave the currently-entered group.
void unselect(EDA_ITEM *aItem) override
Take necessary action mark an item as unselected.
int SelectAll(const TOOL_EVENT &aEvent)
Unselect all items on the board.
PCB_SELECTION m_selection
bool selectTableCells(PCB_TABLE *aTable)
void unhighlight(EDA_ITEM *aItem, int aHighlightMode, SELECTION *aGroup=nullptr) override
Unhighlight the item visually.
BOX2I GetBoundingBox() const override
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: pcb_shape.cpp:374
std::vector< VECTOR2I > GetConnectionPoints() const
Definition: pcb_shape.cpp:404
int GetRowSpan() const
Definition: pcb_tablecell.h:65
int GetColSpan() const
Definition: pcb_tablecell.h:62
std::vector< PCB_TABLECELL * > GetCells() const
Definition: pcb_table.h:141
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: pcb_track.cpp:1041
const VECTOR2I & GetStart() const
Definition: pcb_track.h:122
const VECTOR2I & GetEnd() const
Definition: pcb_track.h:119
int GetDrill() const
Return the local drill setting for this PCB_VIA.
Definition: pcb_track.h:612
A small class to help profiling.
Definition: profile.h:49
void Start()
Start or restart the counter.
Definition: profile.h:77
double msecs(bool aSinceLast=false)
Definition: profile.h:149
bool RoutingInProgress()
Returns whether routing is currently active.
Definition: seg.h:42
static SEG::ecoord Square(int a)
Definition: seg.h:123
static SELECTION_CONDITION HasType(KICAD_T aType)
Create a functor that tests if among the selected items there is at least one of a given type.
static bool NotEmpty(const SELECTION &aSelection)
Test if there are any items selected.
static SELECTION_CONDITION MoreThan(int aNumber)
Create a functor that tests if the number of selected items is greater than the value given as parame...
static SELECTION_CONDITION Count(int aNumber)
Create a functor that tests if the number of selected items is equal to the value given as parameter.
static SELECTION_CONDITION OnlyTypes(std::vector< KICAD_T > aTypes)
Create a functor that tests if the selected items are only of given types.
int RemoveItemFromSel(const TOOL_EVENT &aEvent)
bool doSelectionMenu(COLLECTOR *aCollector)
wxTimer m_disambiguateTimer
int AddItemsToSel(const TOOL_EVENT &aEvent)
int AddItemToSel(const TOOL_EVENT &aEvent)
int UpdateMenu(const TOOL_EVENT &aEvent)
Update a menu's state based on the current selection.
void setModifiersState(bool aShiftState, bool aCtrlState, bool aAltState)
Set the configuration of m_additive, m_subtractive, m_exclusive_or, m_skip_heuristics from the state ...
VECTOR2I m_originalCursor
int SelectionMenu(const TOOL_EVENT &aEvent)
Show a popup menu to trim the COLLECTOR passed as aEvent's parameter down to a single item.
int RemoveItemsFromSel(const TOOL_EVENT &aEvent)
int ReselectItem(const TOOL_EVENT &aEvent)
bool hasModifier()
True if a selection modifier is enabled, false otherwise.
void onDisambiguationExpire(wxTimerEvent &aEvent)
Start the process to show our disambiguation menu once the user has kept the mouse down for the minim...
virtual void Add(EDA_ITEM *aItem)
Definition: selection.cpp:42
virtual KIGFX::VIEW_ITEM * GetItem(unsigned int aIdx) const override
Definition: selection.cpp:75
const std::deque< EDA_ITEM * > GetItems() const
Definition: selection.h:121
void SetIsHover(bool aIsHover)
Definition: selection.h:79
virtual void Remove(EDA_ITEM *aItem)
Definition: selection.cpp:60
virtual unsigned int GetSize() const override
Return the number of stored items.
Definition: selection.h:100
EDA_ITEM * Front() const
Definition: selection.h:172
virtual void Clear() override
Remove all the stored items from the group.
Definition: selection.h:93
int Size() const
Returns the number of selected parts.
Definition: selection.h:116
void ClearReferencePoint()
Definition: selection.cpp:186
bool Empty() const
Checks if there is anything selected.
Definition: selection.h:110
size_t CountType(KICAD_T aType) const
Definition: selection.cpp:157
bool Contains(EDA_ITEM *aItem) const
Definition: selection.cpp:84
ACTION_MENU * create() const override
< Return an instance of this class. It has to be overridden in inheriting classes.
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
void Move(const VECTOR2I &aVector) override
virtual bool Collide(const VECTOR2I &aP, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const override
Check if point aP lies closer to us than aClearance.
bool Collide(const SHAPE *aShape, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const override
Check if the boundary of shape (this) lies closer to the shape aShape than aClearance,...
MOUSE_DRAG_ACTION GetDragAction() const
Indicates whether a drag should draw a selection rectangle or drag selected (or unselected) objects.
Definition: tools_holder.h:144
bool ToolStackIsEmpty()
Definition: tools_holder.h:125
Represent a single user action.
Definition: tool_action.h:269
KIGFX::VIEW_CONTROLS * getViewControls() const
Return the instance of VIEW_CONTROLS object used in the application.
Definition: tool_base.cpp:42
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:218
KIGFX::VIEW * getView() const
Returns the instance of #VIEW object used in the application.
Definition: tool_base.cpp:36
bool IsToolActive() const
Definition: tool_base.cpp:31
RESET_REASON
Determine the reason of reset for a tool.
Definition: tool_base.h:78
@ REDRAW
Full drawing refresh.
Definition: tool_base.h:83
@ MODEL_RELOAD
Model changes (the sheet for a schematic)
Definition: tool_base.h:80
Generic, UI-independent tool event.
Definition: tool_event.h:167
bool IsAction(const TOOL_ACTION *aAction) const
Test if the event contains an action issued upon activation of the given TOOL_ACTION.
Definition: tool_event.cpp:82
T Parameter() const
Return a parameter assigned to the event.
Definition: tool_event.h:460
void Go(int(T::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
Define which state (aStateFunc) to go when a certain event arrives (aConditions).
std::unique_ptr< TOOL_MENU > m_menu
The functions below are not yet implemented - their interface may change.
TOOL_EVENT * Wait(const TOOL_EVENT_LIST &aEventList=TOOL_EVENT(TC_ANY, TA_ANY))
Suspend execution of the tool until an event specified in aEventList arrives.
bool ProcessEvent(const TOOL_EVENT &aEvent)
Propagate an event to tools that requested events of matching type(s).
bool RunAction(const std::string &aActionName, T aParam)
Run the specified action immediately, pausing the current action to run the new one.
Definition: tool_manager.h:150
VECTOR2D GetMousePosition() const
void VetoContextMenuMouseWarp()
Disable mouse warping after the current context menu is closed.
Definition: tool_manager.h:511
KIGFX::VIEW * GetView() const
Definition: tool_manager.h:391
Handle a list of polygons defining a copper zone.
Definition: zone.h:73
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
Definition: zone.h:721
bool HitTestForCorner(const VECTOR2I &refPos, int aAccuracy, SHAPE_POLY_SET::VERTEX_INDEX *aCornerHit=nullptr) const
Test if the given VECTOR2I is near a corner.
Definition: zone.cpp:473
bool HitTestForEdge(const VECTOR2I &refPos, int aAccuracy, SHAPE_POLY_SET::VERTEX_INDEX *aCornerHit=nullptr) const
Test if the given VECTOR2I is near a segment defined by 2 corners.
Definition: zone.cpp:480
bool IsTeardropArea() const
Definition: zone.h:696
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: zone.h:130
bool GetDoNotAllowCopperPour() const
Definition: zone.h:728
MOUSE_DRAG_ACTION
KICURSOR
Definition: cursors.h:34
#define DEFAULT_TEXT_SIZE
Ratio of the font height to the baseline of the text above the wire.
static bool empty(const wxTextEntryBase *aCtrl)
#define _(s)
std::function< INSPECT_RESULT(EDA_ITEM *aItem, void *aTestData) > INSPECTOR_FUNC
Used to inspect and possibly collect the (search) results of iterating over a list or tree of KICAD_T...
Definition: eda_item.h:79
#define BRIGHTENED
item is drawn with a bright contour
#define IS_NEW
New item, just created.
#define SELECTED
Item was manually selected by the user.
#define ENTERED
indicates a group has been entered
#define SKIP_STRUCT
flag indicating that the structure should be ignored
#define CANDIDATE
flag indicating that the structure is connected
#define IS_MOVING
Item being moved.
static std::vector< KICAD_T > tableCellTypes
const TOOL_ACTION * allowedActions[]
@ FRAME_PCB_EDITOR
Definition: frame_type.h:42
@ FRAME_FOOTPRINT_VIEWER
Definition: frame_type.h:45
@ FRAME_FOOTPRINT_EDITOR
Definition: frame_type.h:43
int m_DisambiguationMenuDelay
The number of milliseconds to wait in a click before showing a disambiguation menu.
double m_PcbSelectionVisibilityRatio
Board object selection visibility limit.
@ LAYER_FOOTPRINTS_FR
show footprints on front
Definition: layer_ids.h:209
@ LAYER_DRAW_BITMAPS
to handle and draw images bitmaps
Definition: layer_ids.h:224
@ LAYER_FP_REFERENCES
show footprints references (when texts are visible)
Definition: layer_ids.h:212
@ LAYER_ZONES
Control for copper zone opacity/visibility (color ignored)
Definition: layer_ids.h:232
@ LAYER_PADS
Meta control for all pads opacity/visibility (color ignored)
Definition: layer_ids.h:231
@ LAYER_TRACKS
Definition: layer_ids.h:213
@ LAYER_FP_TEXT
Definition: layer_ids.h:199
@ LAYER_FOOTPRINTS_BK
show footprints on back
Definition: layer_ids.h:210
@ LAYER_FP_VALUES
show footprints values (when texts are visible)
Definition: layer_ids.h:211
@ LAYER_VIAS
Meta control for all vias opacity/visibility.
Definition: layer_ids.h:194
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
@ F_CrtYd
Definition: layer_ids.h:116
@ Edge_Cuts
Definition: layer_ids.h:112
@ F_SilkS
Definition: layer_ids.h:100
@ B_CrtYd
Definition: layer_ids.h:115
@ UNDEFINED_LAYER
Definition: layer_ids.h:61
@ B_SilkS
Definition: layer_ids.h:101
@ PCB_LAYER_ID_COUNT
Definition: layer_ids.h:135
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition: lset.cpp:810
This file contains miscellaneous commonly used macros and functions.
#define KI_FALLTHROUGH
The KI_FALLTHROUGH macro is to be used when switch statement cases should purposely fallthrough from ...
Definition: macros.h:83
@ REPAINT
Item needs to be redrawn.
Definition: view_item.h:57
@ TARGET_OVERLAY
Items that may change while the view stays the same (noncached)
Definition: definitions.h:50
STL namespace.
Class to handle a set of BOARD_ITEMs.
void connectedItemFilter(const VECTOR2I &, GENERAL_COLLECTOR &aCollector, PCB_SELECTION_TOOL *sTool)
const TOOL_ACTION * allowedActions[]
static bool itemIsIncludedByFilter(const BOARD_ITEM &aItem, const BOARD &aBoard, const DIALOG_FILTER_SELECTION::OPTIONS &aFilterOptions)
Determine if an item is included by the filter specified.
std::function< void(const VECTOR2I &, GENERAL_COLLECTOR &, PCB_SELECTION_TOOL *)> CLIENT_SELECTION_FILTER
TRACK_DRAG_ACTION
CITER next(CITER it)
Definition: ptree.cpp:126
Class that computes missing connections on a PCB.
static float distance(const SFVEC2UI &a, const SFVEC2UI &b)
const int scale
bool zoom_to_fit
Zoom to fit items (ignored if center_on_items is off)
Definition: app_settings.h:35
bool center_on_items
Automatically pan to cross-probed items.
Definition: app_settings.h:34
Struct that will be set with the result of the user choices in the dialog.
constexpr int mmToIU(double mm) const
Definition: base_units.h:88
const BOARD_ITEM * m_Item
bool otherItems
Anything not fitting one of the above categories.
bool graphics
Graphic lines, shapes, polygons.
bool footprints
Allow selecting entire footprints.
bool text
Text (free or attached to a footprint)
bool lockedItems
Allow selecting locked items.
constexpr int delta
@ TA_MOUSE_UP
Definition: tool_event.h:68
@ TA_MOUSE_WHEEL
Definition: tool_event.h:72
@ TC_ANY
Definition: tool_event.h:59
@ MD_ALT
Definition: tool_event.h:144
@ MD_CTRL
Definition: tool_event.h:143
@ MD_SHIFT
Definition: tool_event.h:142
@ BUT_MIDDLE
Definition: tool_event.h:133
@ BUT_LEFT
Definition: tool_event.h:131
@ BUT_RIGHT
Definition: tool_event.h:132
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition: typeinfo.h:78
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition: typeinfo.h:88
@ PCB_DIM_ORTHOGONAL_T
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
Definition: typeinfo.h:105
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition: typeinfo.h:102
@ PCB_GENERATOR_T
class PCB_GENERATOR, generator on a layer
Definition: typeinfo.h:91
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:97
@ TYPE_NOT_INIT
Definition: typeinfo.h:81
@ PCB_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
Definition: typeinfo.h:103
@ PCB_GROUP_T
class PCB_GROUP, a set of BOARD_ITEMs
Definition: typeinfo.h:110
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
Definition: typeinfo.h:93
@ PCB_ZONE_T
class ZONE, a copper pour area
Definition: typeinfo.h:107
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition: typeinfo.h:92
@ PCB_REFERENCE_IMAGE_T
class PCB_REFERENCE_IMAGE, bitmap on a layer
Definition: typeinfo.h:89
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
Definition: typeinfo.h:90
@ NOT_USED
the 3d code uses this value
Definition: typeinfo.h:79
@ PCB_MARKER_T
class PCB_MARKER, a marker used to show something
Definition: typeinfo.h:99
@ PCB_TARGET_T
class PCB_TARGET, a target (graphic item)
Definition: typeinfo.h:106
@ PCB_TABLECELL_T
class PCB_TABLECELL, PCB_TEXTBOX for use in tables
Definition: typeinfo.h:95
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
Definition: typeinfo.h:86
@ PCB_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
Definition: typeinfo.h:101
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition: typeinfo.h:87
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition: typeinfo.h:98
@ PCB_TABLE_T
class PCB_TABLE, table of PCB_TABLECELLs
Definition: typeinfo.h:94
@ PCB_NETINFO_T
class NETINFO_ITEM, a description of a net
Definition: typeinfo.h:109
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:96
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
Definition: typeinfo.h:104
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:691
VECTOR2D ToVECTOR2D(const wxPoint &aPoint)
Definition: vector2wx.h:40