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 isTracks = m_selection.GetSize() > 0
521
522 if( isTracks && trackDragAction == TRACK_DRAG_ACTION::DRAG )
524 else if( isTracks && trackDragAction == TRACK_DRAG_ACTION::DRAG_FREE_ANGLE )
526 else
528 }
529 else
530 {
531 // Otherwise drag a selection box
533 }
534 }
535 }
536 else if( evt->IsCancel() )
537 {
538 m_disambiguateTimer.Stop();
539 m_frame->FocusOnItem( nullptr );
540
541 if( !GetSelection().Empty() )
542 {
544 }
545 else if( evt->FirstResponder() == this && evt->GetCommandId() == (int) WXK_ESCAPE )
546 {
547 if( m_enteredGroup )
548 {
549 ExitGroup();
550 }
551 else
552 {
554
555 try
556 {
558 controller->ClearHighlight( *evt );
559 }
560 catch( const std::runtime_error& e )
561 {
562 wxCHECK_MSG( false, 0, e.what() );
563 }
564 }
565 }
566 }
567 else
568 {
569 evt->SetPassEvent();
570 }
571
572
574 {
575 // move cursor prediction
576 if( !hasModifier()
577 && dragAction == MOUSE_DRAG_ACTION::DRAG_SELECTED
578 && !m_selection.Empty()
579 && evt->HasPosition()
580 && selectionContains( evt->Position() ) )
581 {
582 m_nonModifiedCursor = KICURSOR::MOVING;
583 }
584 else
585 {
586 m_nonModifiedCursor = KICURSOR::ARROW;
587 }
588 }
589 }
590
591 // Shutting down; clear the selection
593 m_disambiguateTimer.Stop();
594
595 return 0;
596}
597
598
600{
601 wxCHECK_RET( m_selection.GetSize() == 1 && m_selection[0]->Type() == PCB_GROUP_T,
602 wxT( "EnterGroup called when selection is not a single group" ) );
603 PCB_GROUP* aGroup = static_cast<PCB_GROUP*>( m_selection[0] );
604
605 if( m_enteredGroup != nullptr )
606 ExitGroup();
607
609 m_enteredGroup = aGroup;
612 {
613 select( titem );
614 } );
615
617
618 view()->Hide( m_enteredGroup, true );
621}
622
623
624void PCB_SELECTION_TOOL::ExitGroup( bool aSelectGroup )
625{
626 // Only continue if there is a group entered
627 if( m_enteredGroup == nullptr )
628 return;
629
631 view()->Hide( m_enteredGroup, false );
633
634 if( aSelectGroup )
635 {
638 }
639
641 m_enteredGroup = nullptr;
643}
644
645
647{
648 return m_selection;
649}
650
651
653 bool aConfirmLockedItems )
654{
655 bool selectionEmpty = m_selection.Empty();
656 m_selection.SetIsHover( selectionEmpty );
657
658 if( selectionEmpty )
659 {
662 }
663
664 if( aClientFilter )
665 {
666 enum DISPOSITION { BEFORE = 1, AFTER, BOTH };
667
668 std::map<EDA_ITEM*, DISPOSITION> itemDispositions;
670 GENERAL_COLLECTOR collector;
671
672 collector.SetGuide( &guide );
673
674 for( EDA_ITEM* item : m_selection )
675 {
676 collector.Append( item );
677 itemDispositions[ item ] = BEFORE;
678 }
679
680 aClientFilter( VECTOR2I(), collector, this );
681
682 for( EDA_ITEM* item : collector )
683 {
684 if( itemDispositions.count( item ) )
685 itemDispositions[ item ] = BOTH;
686 else
687 itemDispositions[ item ] = AFTER;
688 }
689
690 // Unhighlight the BEFORE items before highlighting the AFTER items.
691 // This is so that in the case of groups, if aClientFilter replaces a selection
692 // with the enclosing group, the unhighlight of the element doesn't undo the
693 // recursive highlighting of that element by the group.
694
695 for( std::pair<EDA_ITEM* const, DISPOSITION> itemDisposition : itemDispositions )
696 {
697 EDA_ITEM* item = itemDisposition.first;
698 DISPOSITION disposition = itemDisposition.second;
699
700 if( disposition == BEFORE )
702 }
703
704 for( std::pair<EDA_ITEM* const, DISPOSITION> itemDisposition : itemDispositions )
705 {
706 EDA_ITEM* item = itemDisposition.first;
707 DISPOSITION disposition = itemDisposition.second;
708
709 // Note that we must re-highlight even previously-highlighted items
710 // (ie: disposition BOTH) in case we removed any of their children.
711 if( disposition == AFTER || disposition == BOTH )
712 highlight( item, SELECTED, &m_selection );
713 }
714
716 }
717
718 if( aConfirmLockedItems )
719 {
720 std::vector<BOARD_ITEM*> lockedItems;
721
722 for( EDA_ITEM* item : m_selection )
723 {
724 BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( item );
725 bool lockedDescendant = false;
726
727 boardItem->RunOnDescendants(
728 [&]( BOARD_ITEM* curr_item )
729 {
730 if( curr_item->IsLocked() )
731 lockedDescendant = true;
732 } );
733
734 if( boardItem->IsLocked() || lockedDescendant )
735 lockedItems.push_back( boardItem );
736 }
737
739 if( !lockedItems.empty() && !settings->m_LockingOptions.m_sessionSkipPrompts )
740 {
741 DIALOG_LOCKED_ITEMS_QUERY dlg( frame(), lockedItems.size(),
742 settings->m_LockingOptions );
743
744 switch( dlg.ShowModal() )
745 {
746 case wxID_OK:
747 // remove locked items from selection
748 for( BOARD_ITEM* item : lockedItems )
749 unselect( item );
750
751 break;
752
753 case wxID_CANCEL:
754 // cancel operation
756 break;
757
758 case wxID_APPLY:
759 // continue with operation with current selection
760 break;
761 }
762 }
763 }
764
765 return m_selection;
766}
767
768
770{
771 GENERAL_COLLECTORS_GUIDE guide( board()->GetVisibleLayers(),
772 (PCB_LAYER_ID) view()->GetTopLayer(), view() );
773
774 bool padsDisabled = !board()->IsElementVisible( LAYER_PADS );
775
776 // account for the globals
777 guide.SetIgnoreFPTextOnBack( !board()->IsElementVisible( LAYER_FP_TEXT ) );
778 guide.SetIgnoreFPTextOnFront( !board()->IsElementVisible( LAYER_FP_TEXT ) );
779 guide.SetIgnoreFootprintsOnBack( !board()->IsElementVisible( LAYER_FOOTPRINTS_BK ) );
780 guide.SetIgnoreFootprintsOnFront( !board()->IsElementVisible( LAYER_FOOTPRINTS_FR ) );
781 guide.SetIgnorePadsOnBack( padsDisabled );
782 guide.SetIgnorePadsOnFront( padsDisabled );
783 guide.SetIgnoreThroughHolePads( padsDisabled );
784 guide.SetIgnoreFPValues( !board()->IsElementVisible( LAYER_FP_VALUES ) );
785 guide.SetIgnoreFPReferences( !board()->IsElementVisible( LAYER_FP_REFERENCES ) );
786 guide.SetIgnoreThroughVias( ! board()->IsElementVisible( LAYER_VIAS ) );
787 guide.SetIgnoreBlindBuriedVias( ! board()->IsElementVisible( LAYER_VIAS ) );
788 guide.SetIgnoreMicroVias( ! board()->IsElementVisible( LAYER_VIAS ) );
789 guide.SetIgnoreTracks( ! board()->IsElementVisible( LAYER_TRACKS ) );
790
791 return guide;
792}
793
794
796{
798}
799
800
801bool PCB_SELECTION_TOOL::selectPoint( const VECTOR2I& aWhere, bool aOnDrag,
802 bool* aSelectionCancelledFlag,
803 CLIENT_SELECTION_FILTER aClientFilter )
804{
806 GENERAL_COLLECTOR collector;
807 const PCB_DISPLAY_OPTIONS& displayOpts = m_frame->GetDisplayOptions();
808
809 guide.SetIgnoreZoneFills( displayOpts.m_ZoneDisplayMode != ZONE_DISPLAY_MODE::SHOW_FILLED );
810
812 ExitGroup();
813
816 aWhere, guide );
817
818 // Remove unselectable items
819 for( int i = collector.GetCount() - 1; i >= 0; --i )
820 {
821 if( !Selectable( collector[ i ] ) || ( aOnDrag && collector[i]->IsLocked() ) )
822 collector.Remove( i );
823 }
824
826
827 // Apply the stateful filter (remove items disabled by the Selection Filter)
828 FilterCollectedItems( collector, false );
829
830 // Allow the client to do tool- or action-specific filtering to see if we can get down
831 // to a single item
832 if( aClientFilter )
833 aClientFilter( aWhere, collector, this );
834
835 FilterCollectorForHierarchy( collector, false );
836
837 FilterCollectorForFootprints( collector, aWhere );
838
839 // For subtracting, we only want items that are selected
840 if( m_subtractive )
841 {
842 for( int i = collector.GetCount() - 1; i >= 0; --i )
843 {
844 if( !collector[i]->IsSelected() )
845 collector.Remove( i );
846 }
847 }
848
849 // Apply some ugly heuristics to avoid disambiguation menus whenever possible
850 if( collector.GetCount() > 1 && !m_skip_heuristics )
851 {
852 try
853 {
854 GuessSelectionCandidates( collector, aWhere );
855 }
856 catch( const std::exception& exc )
857 {
858 wxLogWarning( wxS( "Exception \"%s\" occurred attempting to guess selection "
859 "candidates." ), exc.what() );
860 return false;
861 }
862 }
863
864 // If still more than one item we're going to have to ask the user.
865 if( collector.GetCount() > 1 )
866 {
867 if( aOnDrag )
869
870 if( !doSelectionMenu( &collector ) )
871 {
872 if( aSelectionCancelledFlag )
873 *aSelectionCancelledFlag = true;
874
875 return false;
876 }
877 }
878
879 int addedCount = 0;
880 bool anySubtracted = false;
881
883 {
884 if( m_selection.GetSize() > 0 )
885 {
886 ClearSelection( true /*quiet mode*/ );
887 anySubtracted = true;
888 }
889 }
890
891 if( collector.GetCount() > 0 )
892 {
893 for( int i = 0; i < collector.GetCount(); ++i )
894 {
895 if( m_subtractive || ( m_exclusive_or && collector[i]->IsSelected() ) )
896 {
897 unselect( collector[i] );
898 anySubtracted = true;
899 }
900 else
901 {
902 select( collector[i] );
903 addedCount++;
904 }
905 }
906 }
907
908 if( addedCount == 1 )
909 {
911 return true;
912 }
913 else if( addedCount > 1 )
914 {
916 return true;
917 }
918 else if( anySubtracted )
919 {
921 return true;
922 }
923
924 return false;
925}
926
927
928bool PCB_SELECTION_TOOL::selectCursor( bool aForceSelect, CLIENT_SELECTION_FILTER aClientFilter )
929{
930 if( aForceSelect || m_selection.Empty() )
931 {
932 ClearSelection( true /*quiet mode*/ );
933 selectPoint( getViewControls()->GetCursorPosition( false ), false, nullptr, aClientFilter );
934 }
935
936 return !m_selection.Empty();
937}
938
939
940// Some navigation actions are allowed in selectMultiple
950 &ACTIONS::zoomFitObjects, nullptr };
951
952
954{
955 bool cancelled = false; // Was the tool canceled while it was running?
956 m_multiple = true; // Multiple selection mode is active
957
958 for( PCB_TABLECELL* cell : aTable->GetCells() )
959 {
960 if( cell->IsSelected() )
961 cell->SetFlags( CANDIDATE );
962 else
963 cell->ClearFlags( CANDIDATE );
964 }
965
966 auto wasSelected =
967 []( EDA_ITEM* aItem )
968 {
969 return ( aItem->GetFlags() & CANDIDATE ) > 0;
970 };
971
972 while( TOOL_EVENT* evt = Wait() )
973 {
974 if( evt->IsCancelInteractive() || evt->IsActivate() )
975 {
976 cancelled = true;
977 break;
978 }
979 else if( evt->IsDrag( BUT_LEFT ) )
980 {
981 getViewControls()->SetAutoPan( true );
982
983 BOX2I selectionRect( evt->DragOrigin(), evt->Position() - evt->DragOrigin() );
984 selectionRect.Normalize();
985
986 for( PCB_TABLECELL* cell : aTable->GetCells() )
987 {
988 bool doSelect = false;
989
990 if( cell->HitTest( selectionRect, false ) )
991 {
992 if( m_subtractive )
993 doSelect = false;
994 else if( m_exclusive_or )
995 doSelect = !wasSelected( cell );
996 else
997 doSelect = true;
998 }
999 else if( wasSelected( cell ) )
1000 {
1001 doSelect = m_additive || m_subtractive || m_exclusive_or;
1002 }
1003
1004 if( doSelect && !cell->IsSelected() )
1005 select( cell );
1006 else if( !doSelect && cell->IsSelected() )
1007 unselect( cell );
1008 }
1009 }
1010 else if( evt->IsMouseUp( BUT_LEFT ) )
1011 {
1012 m_selection.SetIsHover( false );
1013
1014 bool anyAdded = false;
1015 bool anySubtracted = false;
1016
1017 for( PCB_TABLECELL* cell : aTable->GetCells() )
1018 {
1019 if( cell->IsSelected() && !wasSelected( cell ) )
1020 anyAdded = true;
1021 else if( wasSelected( cell ) && !cell->IsSelected() )
1022 anySubtracted = true;
1023 }
1024
1025 // Inform other potentially interested tools
1026 if( anyAdded )
1028
1029 if( anySubtracted )
1031
1032 break; // Stop waiting for events
1033 }
1034 else
1035 {
1036 // Allow some actions for navigation
1037 for( int i = 0; allowedActions[i]; ++i )
1038 {
1039 if( evt->IsAction( allowedActions[i] ) )
1040 {
1041 evt->SetPassEvent();
1042 break;
1043 }
1044 }
1045 }
1046 }
1047
1048 getViewControls()->SetAutoPan( false );
1049
1050 m_multiple = false; // Multiple selection mode is inactive
1051
1052 if( !cancelled )
1054
1055 return cancelled;
1056}
1057
1058
1060{
1061 bool cancelled = false; // Was the tool canceled while it was running?
1062 m_multiple = true; // Multiple selection mode is active
1064
1066 view->Add( &area );
1067
1068 bool anyAdded = false;
1069 bool anySubtracted = false;
1070
1071 while( TOOL_EVENT* evt = Wait() )
1072 {
1073 int width = area.GetEnd().x - area.GetOrigin().x;
1074
1075 /* Selection mode depends on direction of drag-selection:
1076 * Left > Right : Select objects that are fully enclosed by selection
1077 * Right > Left : Select objects that are crossed by selection
1078 */
1079 bool greedySelection = width >= 0 ? false : true;
1080
1081 if( view->IsMirroredX() )
1082 greedySelection = !greedySelection;
1083
1084 m_frame->GetCanvas()->SetCurrentCursor( !greedySelection ? KICURSOR::SELECT_WINDOW
1085 : KICURSOR::SELECT_LASSO );
1086
1087 if( evt->IsCancelInteractive() || evt->IsActivate() )
1088 {
1089 cancelled = true;
1090 break;
1091 }
1092
1093 if( evt->IsDrag( BUT_LEFT ) )
1094 {
1096 {
1097 if( m_selection.GetSize() > 0 )
1098 {
1099 anySubtracted = true;
1100 ClearSelection( true /*quiet mode*/ );
1101 }
1102 }
1103
1104 // Start drawing a selection box
1105 area.SetOrigin( evt->DragOrigin() );
1106 area.SetEnd( evt->Position() );
1109 area.SetExclusiveOr( false );
1110
1111 view->SetVisible( &area, true );
1112 view->Update( &area );
1113 getViewControls()->SetAutoPan( true );
1114 }
1115
1116 if( evt->IsMouseUp( BUT_LEFT ) )
1117 {
1118 getViewControls()->SetAutoPan( false );
1119
1120 // End drawing the selection box
1121 view->SetVisible( &area, false );
1122
1123 std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> candidates;
1124 BOX2I selectionBox = area.ViewBBox();
1125 view->Query( selectionBox, candidates ); // Get the list of nearby items
1126
1127 int height = area.GetEnd().y - area.GetOrigin().y;
1128
1129 // Construct a BOX2I to determine BOARD_ITEM selection
1130 BOX2I selectionRect( area.GetOrigin(), VECTOR2I( width, height ) );
1131
1132 selectionRect.Normalize();
1133
1134 GENERAL_COLLECTOR collector;
1135 GENERAL_COLLECTOR padsCollector;
1136 std::set<BOARD_ITEM*> group_items;
1137
1138 for( PCB_GROUP* group : board()->Groups() )
1139 {
1140 // The currently entered group does not get limited
1141 if( m_enteredGroup == group )
1142 continue;
1143
1144 std::unordered_set<BOARD_ITEM*>& newset = group->GetItems();
1145
1146 // If we are not greedy and have selected the whole group, add just one item
1147 // to allow it to be promoted to the group later
1148 if( !greedySelection && selectionRect.Contains( group->GetBoundingBox() )
1149 && newset.size() )
1150 {
1151 for( BOARD_ITEM* group_item : newset )
1152 {
1153 if( Selectable( group_item ) )
1154 collector.Append( *newset.begin() );
1155 }
1156 }
1157
1158 for( BOARD_ITEM* group_item : newset )
1159 group_items.emplace( group_item );
1160 }
1161
1162 for( const KIGFX::VIEW::LAYER_ITEM_PAIR& candidate : candidates )
1163 {
1164 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( candidate.first );
1165
1166 if( item && Selectable( item ) && item->HitTest( selectionRect, !greedySelection )
1167 && ( greedySelection || !group_items.count( item ) ) )
1168 {
1169 if( item->Type() == PCB_PAD_T && !m_isFootprintEditor )
1170 padsCollector.Append( item );
1171 else
1172 collector.Append( item );
1173 }
1174 }
1175
1176 // Apply the stateful filter
1177 FilterCollectedItems( collector, true );
1178
1179 FilterCollectorForHierarchy( collector, true );
1180
1181 // If we selected nothing but pads, allow them to be selected
1182 if( collector.GetCount() == 0 )
1183 {
1184 collector = padsCollector;
1185 FilterCollectedItems( collector, true );
1186 FilterCollectorForHierarchy( collector, true );
1187 }
1188
1189 for( EDA_ITEM* i : collector )
1190 {
1191 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( i );
1192
1193 if( m_subtractive || ( m_exclusive_or && item->IsSelected() ) )
1194 {
1195 unselect( item );
1196 anySubtracted = true;
1197 }
1198 else
1199 {
1200 select( item );
1201 anyAdded = true;
1202 }
1203 }
1204
1205 m_selection.SetIsHover( false );
1206
1207 // Inform other potentially interested tools
1208 if( anyAdded )
1210 else if( anySubtracted )
1212
1213 break; // Stop waiting for events
1214 }
1215
1216 // Allow some actions for navigation
1217 for( int i = 0; allowedActions[i]; ++i )
1218 {
1219 if( evt->IsAction( allowedActions[i] ) )
1220 {
1221 evt->SetPassEvent();
1222 break;
1223 }
1224 }
1225 }
1226
1227 getViewControls()->SetAutoPan( false );
1228
1229 // Stop drawing the selection box
1230 view->Remove( &area );
1231 m_multiple = false; // Multiple selection mode is inactive
1232
1233 if( !cancelled )
1235
1237
1238 return cancelled;
1239}
1240
1241
1243{
1244 wxMouseState keyboardState = wxGetMouseState();
1245
1246 setModifiersState( keyboardState.ShiftDown(), keyboardState.ControlDown(),
1247 keyboardState.AltDown() );
1248
1249 m_skip_heuristics = true;
1251 m_skip_heuristics = false;
1252
1253 return 0;
1254}
1255
1256
1257
1259{
1261
1262 selectCursor( false, aClientFilter );
1263
1264 return 0;
1265}
1266
1267
1269{
1271
1272 return 0;
1273}
1274
1275
1277{
1278 GENERAL_COLLECTOR collection;
1279 BOX2I selectionBox;
1280
1281 selectionBox.SetMaximum();
1282
1283 getView()->Query( selectionBox,
1284 [&]( KIGFX::VIEW_ITEM* viewItem ) -> bool
1285 {
1286 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( viewItem );
1287
1288 if( !item || !Selectable( item ) || !itemPassesFilter( item, true ) )
1289 return true;
1290
1291 collection.Append( item );
1292 return true;
1293 } );
1294
1295 FilterCollectorForHierarchy( collection, true );
1296
1297 for( EDA_ITEM* item : collection )
1298 select( item );
1299
1301
1303
1304 return 0;
1305}
1306
1307
1309{
1310 BOX2I selectionBox;
1311
1312 selectionBox.SetMaximum();
1313
1314 getView()->Query( selectionBox,
1315 [&]( KIGFX::VIEW_ITEM* viewItem ) -> bool
1316 {
1317 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( viewItem );
1318
1319 if( !item || !Selectable( item ) )
1320 return true;
1321
1322 unselect( item );
1323 return true;
1324 } );
1325
1327
1329
1330 return 0;
1331}
1332
1333
1335 PCB_SELECTION_TOOL* sTool )
1336{
1337 // Narrow the collection down to a single BOARD_CONNECTED_ITEM for each represented net.
1338 // All other items types are removed.
1339 std::set<int> representedNets;
1340
1341 for( int i = aCollector.GetCount() - 1; i >= 0; i-- )
1342 {
1343 BOARD_CONNECTED_ITEM* item = dynamic_cast<BOARD_CONNECTED_ITEM*>( aCollector[i] );
1344
1345 if( !item )
1346 aCollector.Remove( i );
1347 else if ( representedNets.count( item->GetNetCode() ) )
1348 aCollector.Remove( i );
1349 else
1350 representedNets.insert( item->GetNetCode() );
1351 }
1352}
1353
1354
1356{
1357 std::deque<EDA_ITEM*> selectedItems = m_selection.GetItems();
1358
1359 // Get all footprints and pads
1360 std::vector<BOARD_CONNECTED_ITEM*> toUnroute;
1361
1362 for( EDA_ITEM* item : selectedItems )
1363 {
1364 if( item->Type() == PCB_FOOTPRINT_T )
1365 {
1366 for( PAD* pad : static_cast<FOOTPRINT*>( item )->Pads() )
1367 toUnroute.push_back( pad );
1368 }
1369 else if( BOARD_CONNECTED_ITEM::ClassOf( item ) )
1370 {
1371 toUnroute.push_back( static_cast<BOARD_CONNECTED_ITEM*>( item ) );
1372 }
1373 }
1374
1375 // Clear selection so we don't delete our footprints/pads
1376 ClearSelection( true );
1377
1378 // Get the tracks on our list of pads, then delete them
1381
1382 // Reselect our footprint/pads as they were in our original selection
1383 for( EDA_ITEM* item : selectedItems )
1384 {
1385 if( item->Type() == PCB_FOOTPRINT_T || item->Type() == PCB_PAD_T )
1386 select( item );
1387 }
1388
1389 return 0;
1390}
1391
1392
1394{
1395 // expandConnection will get called no matter whether the user selected a connected item or a
1396 // non-connected shape (graphic on a non-copper layer). The algorithm for expanding to connected
1397 // items is different from graphics, so they need to be handled separately.
1398 unsigned initialCount = 0;
1399
1400 for( const EDA_ITEM* item : m_selection.GetItems() )
1401 {
1402 if( item->Type() == PCB_FOOTPRINT_T
1403 || item->Type() == PCB_GENERATOR_T
1404 || ( static_cast<const BOARD_ITEM*>( item )->IsConnected() ) )
1405 {
1406 initialCount++;
1407 }
1408 }
1409
1410 if( initialCount == 0 )
1411 {
1412 // First, process any graphic shapes we have
1413 std::vector<PCB_SHAPE*> startShapes;
1414
1415 for( EDA_ITEM* item : m_selection.GetItems() )
1416 {
1417 if( isExpandableGraphicShape( item ) )
1418 startShapes.push_back( static_cast<PCB_SHAPE*>( item ) );
1419 }
1420
1421 // If no non-copper shapes; fall back to looking for connected items
1422 if( !startShapes.empty() )
1423 selectAllConnectedShapes( startShapes );
1424 else
1426 }
1427
1428 m_frame->SetStatusText( _( "Select/Expand Connection..." ) );
1429
1430 for( STOP_CONDITION stopCondition : { STOP_AT_JUNCTION, STOP_AT_PAD, STOP_NEVER } )
1431 {
1432 std::deque<EDA_ITEM*> selectedItems = m_selection.GetItems();
1433
1434 for( EDA_ITEM* item : selectedItems )
1435 item->ClearTempFlags();
1436
1437 std::vector<BOARD_CONNECTED_ITEM*> startItems;
1438
1439 for( EDA_ITEM* item : selectedItems )
1440 {
1441 if( item->Type() == PCB_FOOTPRINT_T )
1442 {
1443 FOOTPRINT* footprint = static_cast<FOOTPRINT*>( item );
1444
1445 for( PAD* pad : footprint->Pads() )
1446 startItems.push_back( pad );
1447 }
1448 else if( item->Type() == PCB_GENERATOR_T )
1449 {
1450 for( BOARD_ITEM* generatedItem : static_cast<PCB_GENERATOR*>( item )->GetItems() )
1451 {
1452 if( BOARD_CONNECTED_ITEM::ClassOf( generatedItem ) )
1453 startItems.push_back( static_cast<BOARD_CONNECTED_ITEM*>( generatedItem ) );
1454 }
1455 }
1456 else if( BOARD_CONNECTED_ITEM::ClassOf( item ) )
1457 {
1458 startItems.push_back( static_cast<BOARD_CONNECTED_ITEM*>( item ) );
1459 }
1460 }
1461
1462 selectAllConnectedTracks( startItems, stopCondition );
1463
1464 if( m_selection.GetItems().size() > initialCount )
1465 break;
1466 }
1467
1468 m_frame->SetStatusText( wxEmptyString );
1469
1470 // Inform other potentially interested tools
1472
1473 return 0;
1474}
1475
1476
1478 const std::vector<BOARD_CONNECTED_ITEM*>& aStartItems, STOP_CONDITION aStopCondition )
1479{
1480 const LSET allCuMask = LSET::AllCuMask();
1481
1482 PROF_TIMER refreshTimer;
1483 double refreshIntervalMs = 500; // Refresh display with this interval to indicate progress
1484 int lastSelectionSize = (int) m_selection.GetSize();
1485
1486 auto connectivity = board()->GetConnectivity();
1487
1488 std::map<VECTOR2I, std::vector<PCB_TRACK*>> trackMap;
1489 std::map<VECTOR2I, PCB_VIA*> viaMap;
1490 std::map<VECTOR2I, PAD*> padMap;
1491 std::map<VECTOR2I, std::vector<PCB_SHAPE*>> shapeMap;
1492 std::set<PAD*> startPadSet;
1493 std::vector<BOARD_CONNECTED_ITEM*> cleanupItems;
1494 std::vector<std::pair<VECTOR2I, LSET>> activePts;
1495
1496 for( BOARD_CONNECTED_ITEM* startItem : aStartItems )
1497 {
1498 // Register starting pads
1499 if( startItem->Type() == PCB_PAD_T )
1500 startPadSet.insert( static_cast<PAD*>( startItem ) );
1501
1502 // Select any starting track items
1503 if( startItem->IsType( { PCB_TRACE_T, PCB_ARC_T, PCB_VIA_T } ) )
1504 select( startItem );
1505 }
1506
1507 for( BOARD_CONNECTED_ITEM* startItem : aStartItems )
1508 {
1509 if( startItem->HasFlag( SKIP_STRUCT ) ) // Skip already visited items
1510 continue;
1511
1512 auto connectedItems = connectivity->GetConnectedItems( startItem,
1514
1515 // Build maps of connected items
1516 for( BOARD_CONNECTED_ITEM* item : connectedItems )
1517 {
1518 switch( item->Type() )
1519 {
1520 case PCB_ARC_T:
1521 case PCB_TRACE_T:
1522 {
1523 PCB_TRACK* track = static_cast<PCB_TRACK*>( item );
1524 trackMap[track->GetStart()].push_back( track );
1525 trackMap[track->GetEnd()].push_back( track );
1526 break;
1527 }
1528
1529 case PCB_VIA_T:
1530 {
1531 PCB_VIA* via = static_cast<PCB_VIA*>( item );
1532 viaMap[via->GetStart()] = via;
1533 break;
1534 }
1535
1536 case PCB_PAD_T:
1537 {
1538 PAD* pad = static_cast<PAD*>( item );
1539 padMap[pad->GetPosition()] = pad;
1540 break;
1541 }
1542
1543 case PCB_SHAPE_T:
1544 {
1545 PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( item );
1546
1547 for( const auto& point : shape->GetConnectionPoints() )
1548 shapeMap[point].push_back( shape );
1549
1550 break;
1551 }
1552
1553 default:
1554 break;
1555 }
1556 }
1557
1558 // Set up the initial active points
1559 switch( startItem->Type() )
1560 {
1561 case PCB_ARC_T:
1562 case PCB_TRACE_T:
1563 {
1564 PCB_TRACK* track = static_cast<PCB_TRACK*>( startItem );
1565
1566 activePts.push_back( { track->GetStart(), track->GetLayerSet() } );
1567 activePts.push_back( { track->GetEnd(), track->GetLayerSet() } );
1568 break;
1569 }
1570
1571 case PCB_VIA_T:
1572 activePts.push_back( { startItem->GetPosition(), startItem->GetLayerSet() } );
1573 break;
1574
1575 case PCB_PAD_T:
1576 activePts.push_back( { startItem->GetPosition(), startItem->GetLayerSet() } );
1577 break;
1578
1579 case PCB_SHAPE_T:
1580 {
1581 PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( startItem );
1582
1583 for( const auto& point : shape->GetConnectionPoints() )
1584 activePts.push_back( { point, startItem->GetLayerSet() } );
1585
1586 break;
1587 }
1588
1589 default:
1590 break;
1591 }
1592
1593 bool expand = true;
1594 int failSafe = 0;
1595
1596 // Iterative push from all active points
1597 while( expand && failSafe++ < 100000 )
1598 {
1599 expand = false;
1600
1601 for( int i = (int) activePts.size() - 1; i >= 0; --i )
1602 {
1603 VECTOR2I pt = activePts[i].first;
1604 LSET layerSetCu = activePts[i].second & allCuMask;
1605
1606 auto viaIt = viaMap.find( pt );
1607 auto padIt = padMap.find( pt );
1608
1609 bool gotVia = ( viaIt != viaMap.end() )
1610 && ( layerSetCu & ( viaIt->second->GetLayerSet() ) ).any();
1611
1612 bool gotPad = ( padIt != padMap.end() )
1613 && ( layerSetCu & ( padIt->second->GetLayerSet() ) ).any();
1614
1615 bool gotNonStartPad =
1616 gotPad && ( startPadSet.find( padIt->second ) == startPadSet.end() );
1617
1618 if( aStopCondition == STOP_AT_JUNCTION )
1619 {
1620 size_t pt_count = 0;
1621
1622 for( PCB_TRACK* track : trackMap[pt] )
1623 {
1624 if( track->GetStart() != track->GetEnd()
1625 && layerSetCu.Contains( track->GetLayer() ) )
1626 {
1627 pt_count++;
1628 }
1629 }
1630
1631 if( pt_count > 2 || gotVia || gotNonStartPad )
1632 {
1633 activePts.erase( activePts.begin() + i );
1634 continue;
1635 }
1636 }
1637 else if( aStopCondition == STOP_AT_PAD )
1638 {
1639 if( gotNonStartPad )
1640 {
1641 activePts.erase( activePts.begin() + i );
1642 continue;
1643 }
1644 }
1645
1646 if( gotPad )
1647 {
1648 PAD* pad = padIt->second;
1649
1650 if( !pad->HasFlag( SKIP_STRUCT ) )
1651 {
1652 pad->SetFlags( SKIP_STRUCT );
1653 cleanupItems.push_back( pad );
1654
1655 activePts.push_back( { pad->GetPosition(), pad->GetLayerSet() } );
1656 expand = true;
1657 }
1658 }
1659
1660 for( PCB_TRACK* track : trackMap[pt] )
1661 {
1662 if( !layerSetCu.Contains( track->GetLayer() ) )
1663 continue;
1664
1665 if( !track->IsSelected() )
1666 select( track );
1667
1668 if( !track->HasFlag( SKIP_STRUCT ) )
1669 {
1670 track->SetFlags( SKIP_STRUCT );
1671 cleanupItems.push_back( track );
1672
1673 if( track->GetStart() == pt )
1674 activePts.push_back( { track->GetEnd(), track->GetLayerSet() } );
1675 else
1676 activePts.push_back( { track->GetStart(), track->GetLayerSet() } );
1677
1678 expand = true;
1679 }
1680 }
1681
1682 for( PCB_SHAPE* shape : shapeMap[pt] )
1683 {
1684 if( !layerSetCu.Contains( shape->GetLayer() ) )
1685 continue;
1686
1687 if( !shape->IsSelected() )
1688 select( shape );
1689
1690 if( !shape->HasFlag( SKIP_STRUCT ) )
1691 {
1692 shape->SetFlags( SKIP_STRUCT );
1693 cleanupItems.push_back( shape );
1694
1695 for( const VECTOR2I& newPoint : shape->GetConnectionPoints() )
1696 {
1697 if( newPoint == pt )
1698 continue;
1699
1700 activePts.push_back( { newPoint, shape->GetLayerSet() } );
1701 }
1702
1703 expand = true;
1704 }
1705 }
1706
1707 if( viaMap.count( pt ) )
1708 {
1709 PCB_VIA* via = viaMap[pt];
1710
1711 if( !via->IsSelected() )
1712 select( via );
1713
1714 if( !via->HasFlag( SKIP_STRUCT ) )
1715 {
1716 via->SetFlags( SKIP_STRUCT );
1717 cleanupItems.push_back( via );
1718
1719 activePts.push_back( { via->GetPosition(), via->GetLayerSet() } );
1720 expand = true;
1721 }
1722 }
1723
1724 activePts.erase( activePts.begin() + i );
1725 }
1726
1727 // Refresh display for the feel of progress
1728 if( refreshTimer.msecs() >= refreshIntervalMs )
1729 {
1730 if( m_selection.Size() != lastSelectionSize )
1731 {
1733 lastSelectionSize = m_selection.Size();
1734 }
1735
1736 refreshTimer.Start();
1737 }
1738 }
1739 }
1740
1741 std::set<EDA_ITEM*> toDeselect;
1742 std::set<EDA_ITEM*> toSelect;
1743
1744 // Promote generated members to their PCB_GENERATOR parents
1745 for( EDA_ITEM* item : m_selection )
1746 {
1747 if( !item->IsBOARD_ITEM() )
1748 continue;
1749
1750 BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( item );
1751 PCB_GROUP* parent = boardItem->GetParentGroup();
1752
1753 if( parent && parent->Type() == PCB_GENERATOR_T )
1754 {
1755 toDeselect.insert( item );
1756
1757 if( !parent->IsSelected() )
1758 toSelect.insert( parent );
1759 }
1760 }
1761
1762 for( EDA_ITEM* item : toDeselect )
1763 unselect( item );
1764
1765 for( EDA_ITEM* item : toSelect )
1766 select( item );
1767
1768 for( BOARD_CONNECTED_ITEM* item : cleanupItems )
1769 item->ClearFlags( SKIP_STRUCT );
1770}
1771
1772
1774{
1775 if( aItem->Type() == PCB_SHAPE_T )
1776 {
1777 const PCB_SHAPE* shape = static_cast<const PCB_SHAPE*>( aItem );
1778
1779 switch( shape->GetShape() )
1780 {
1781 case SHAPE_T::SEGMENT:
1782 case SHAPE_T::ARC:
1783 case SHAPE_T::BEZIER:
1784 return !shape->IsOnCopperLayer();
1785
1786 case SHAPE_T::POLY:
1787 return !shape->IsOnCopperLayer() && !shape->IsClosed();
1788
1789 default:
1790 return false;
1791 }
1792 }
1793
1794 return false;
1795}
1796
1797
1798void PCB_SELECTION_TOOL::selectAllConnectedShapes( const std::vector<PCB_SHAPE*>& aStartItems )
1799{
1800 std::stack<PCB_SHAPE*> toSearch;
1801 std::set<PCB_SHAPE*> toCleanup;
1802
1803 for( PCB_SHAPE* startItem : aStartItems )
1804 toSearch.push( startItem );
1805
1806 GENERAL_COLLECTOR collector;
1808
1809 auto searchPoint = [&]( const VECTOR2I& aWhere )
1810 {
1811 collector.Collect( board(), { PCB_SHAPE_T }, aWhere, guide );
1812
1813 for( EDA_ITEM* item : collector )
1814 {
1815 if( isExpandableGraphicShape( item ) )
1816 toSearch.push( static_cast<PCB_SHAPE*>( item ) );
1817 }
1818 };
1819
1820 while( !toSearch.empty() )
1821 {
1822 PCB_SHAPE* shape = toSearch.top();
1823 toSearch.pop();
1824
1825 if( shape->HasFlag( SKIP_STRUCT ) )
1826 continue;
1827
1828 select( shape );
1829 shape->SetFlags( SKIP_STRUCT );
1830 toCleanup.insert( shape );
1831
1832 guide.SetLayerVisibleBits( shape->GetLayerSet() );
1833
1834 searchPoint( shape->GetStart() );
1835 searchPoint( shape->GetEnd() );
1836 }
1837
1838 for( PCB_SHAPE* shape : toCleanup )
1839 shape->ClearFlags( SKIP_STRUCT );
1840}
1841
1842
1844{
1845 // Get all pads
1846 std::vector<PAD*> pads;
1847
1848 for( EDA_ITEM* item : m_selection.GetItems() )
1849 {
1850 if( item->Type() == PCB_FOOTPRINT_T )
1851 {
1852 for( PAD* pad : static_cast<FOOTPRINT*>( item )->Pads() )
1853 pads.push_back( pad );
1854 }
1855 else if( item->Type() == PCB_PAD_T )
1856 {
1857 pads.push_back( static_cast<PAD*>( item ) );
1858 }
1859 }
1860
1861 // Select every footprint on the end of the ratsnest for each pad in our selection
1862 std::shared_ptr<CONNECTIVITY_DATA> conn = board()->GetConnectivity();
1863
1864 for( PAD* pad : pads )
1865 {
1866 for( const CN_EDGE& edge : conn->GetRatsnestForPad( pad ) )
1867 {
1868 wxCHECK2( edge.GetSourceNode() && !edge.GetSourceNode()->Dirty(), continue );
1869 wxCHECK2( edge.GetTargetNode() && !edge.GetTargetNode()->Dirty(), continue );
1870
1871 BOARD_CONNECTED_ITEM* sourceParent = edge.GetSourceNode()->Parent();
1872 BOARD_CONNECTED_ITEM* targetParent = edge.GetTargetNode()->Parent();
1873
1874 if( sourceParent == pad )
1875 {
1876 if( targetParent->Type() == PCB_PAD_T )
1877 select( static_cast<PAD*>( targetParent )->GetParent() );
1878 }
1879 else if( targetParent == pad )
1880 {
1881 if( sourceParent->Type() == PCB_PAD_T )
1882 select( static_cast<PAD*>( sourceParent )->GetParent() );
1883 }
1884 }
1885 }
1886
1887 return 0;
1888}
1889
1890
1892{
1893 PCB_SELECTION originalSelection = m_selection;
1894
1895 // Get all pads
1896 std::vector<PAD*> pads;
1897
1898 for( EDA_ITEM* item : m_selection.GetItems() )
1899 {
1900 if( item->Type() == PCB_FOOTPRINT_T )
1901 {
1902 for( PAD* pad : static_cast<FOOTPRINT*>( item )->Pads() )
1903 pads.push_back( pad );
1904 }
1905 else if( item->Type() == PCB_PAD_T )
1906 {
1907 pads.push_back( static_cast<PAD*>( item ) );
1908 }
1909 }
1910
1912
1913 // Select every footprint on the end of the ratsnest for each pad in our selection
1914 std::shared_ptr<CONNECTIVITY_DATA> conn = board()->GetConnectivity();
1915
1916 for( PAD* pad : pads )
1917 {
1918 const std::vector<CN_EDGE> edges = conn->GetRatsnestForPad( pad );
1919
1920 // Need to have something unconnected to grab
1921 if( edges.size() == 0 )
1922 continue;
1923
1924 double currentDistance = DBL_MAX;
1925 FOOTPRINT* nearest = nullptr;
1926
1927 // Check every ratsnest line for the nearest one
1928 for( const CN_EDGE& edge : edges )
1929 {
1930 if( edge.GetSourceNode()->Parent()->GetParentFootprint()
1931 == edge.GetTargetNode()->Parent()->GetParentFootprint() )
1932 {
1933 continue; // This edge is a loop on the same footprint
1934 }
1935
1936 // Figure out if we are the source or the target node on the ratnest
1937 const CN_ANCHOR* other = edge.GetSourceNode()->Parent() == pad ? edge.GetTargetNode().get()
1938 : edge.GetSourceNode().get();
1939
1940 wxCHECK2( other && !other->Dirty(), continue );
1941
1942 // We only want to grab footprints, so the ratnest has to point to a pad
1943 if( other->Parent()->Type() != PCB_PAD_T )
1944 continue;
1945
1946 if( edge.GetLength() < currentDistance )
1947 {
1948 currentDistance = edge.GetLength();
1949 nearest = other->Parent()->GetParentFootprint();
1950 }
1951 }
1952
1953 if( nearest != nullptr )
1954 select( nearest );
1955 }
1956
1958
1959 return 0;
1960}
1961
1962
1963void PCB_SELECTION_TOOL::SelectAllItemsOnNet( int aNetCode, bool aSelect )
1964{
1965 std::shared_ptr<CONNECTIVITY_DATA> conn = board()->GetConnectivity();
1966
1967 for( BOARD_ITEM* item : conn->GetNetItems( aNetCode, { PCB_TRACE_T,
1968 PCB_ARC_T,
1969 PCB_VIA_T,
1970 PCB_SHAPE_T } ) )
1971 {
1972 if( itemPassesFilter( item, true ) )
1973 aSelect ? select( item ) : unselect( item );
1974 }
1975}
1976
1977
1979{
1980 bool select = aEvent.IsAction( &PCB_ACTIONS::selectNet );
1981
1982 // If we've been passed an argument, just select that netcode1
1983 int netcode = aEvent.Parameter<int>();
1984
1985 if( netcode > 0 )
1986 {
1987 SelectAllItemsOnNet( netcode, select );
1988
1989 // Inform other potentially interested tools
1990 if( m_selection.Size() > 0 )
1992 else
1994
1995 return 0;
1996 }
1997
1998 if( !selectCursor() )
1999 return 0;
2000
2001 // copy the selection, since we're going to iterate and modify
2003
2004 for( EDA_ITEM* i : selection )
2005 {
2006 BOARD_CONNECTED_ITEM* connItem = dynamic_cast<BOARD_CONNECTED_ITEM*>( i );
2007
2008 if( connItem )
2009 SelectAllItemsOnNet( connItem->GetNetCode(), select );
2010 }
2011
2012 // Inform other potentially interested tools
2013 if( m_selection.Size() > 0 )
2015 else
2017
2018 return 0;
2019}
2020
2021
2023{
2024 std::vector<BOARD_ITEM*> footprints;
2025
2026 // store all footprints that are on that sheet path
2027 for( FOOTPRINT* footprint : board()->Footprints() )
2028 {
2029 if( footprint == nullptr )
2030 continue;
2031
2032 wxString footprint_path = footprint->GetPath().AsString().BeforeLast( '/' );
2033
2034 if( footprint_path.IsEmpty() )
2035 footprint_path += '/';
2036
2037 if( footprint_path == aSheetPath )
2038 footprints.push_back( footprint );
2039 }
2040
2041 for( BOARD_ITEM* i : footprints )
2042 {
2043 if( i != nullptr )
2044 select( i );
2045 }
2046
2047 selectConnections( footprints );
2048}
2049
2050
2051void PCB_SELECTION_TOOL::selectConnections( const std::vector<BOARD_ITEM*>& aItems )
2052{
2053 // Generate a list of all pads, and of all nets they belong to.
2054 std::list<int> netcodeList;
2055 std::vector<BOARD_CONNECTED_ITEM*> padList;
2056
2057 for( BOARD_ITEM* item : aItems )
2058 {
2059 switch( item->Type() )
2060 {
2061 case PCB_FOOTPRINT_T:
2062 {
2063 for( PAD* pad : static_cast<FOOTPRINT*>( item )->Pads() )
2064 {
2065 if( pad->IsConnected() )
2066 {
2067 netcodeList.push_back( pad->GetNetCode() );
2068 padList.push_back( pad );
2069 }
2070 }
2071
2072 break;
2073 }
2074
2075 case PCB_PAD_T:
2076 {
2077 PAD* pad = static_cast<PAD*>( item );
2078
2079 if( pad->IsConnected() )
2080 {
2081 netcodeList.push_back( pad->GetNetCode() );
2082 padList.push_back( pad );
2083 }
2084
2085 break;
2086 }
2087
2088 default:
2089 break;
2090 }
2091 }
2092
2093 // Sort for binary search
2094 std::sort( padList.begin(), padList.end() );
2095
2096 // remove all duplicates
2097 netcodeList.sort();
2098 netcodeList.unique();
2099
2101
2102 // now we need to find all footprints that are connected to each of these nets then we need
2103 // to determine if these footprints are in the list of footprints
2104 std::vector<int> removeCodeList;
2105 std::shared_ptr<CONNECTIVITY_DATA> conn = board()->GetConnectivity();
2106
2107 for( int netCode : netcodeList )
2108 {
2109 for( BOARD_CONNECTED_ITEM* pad : conn->GetNetItems( netCode, { PCB_PAD_T } ) )
2110 {
2111 if( !std::binary_search( padList.begin(), padList.end(), pad ) )
2112 {
2113 // if we cannot find the pad in the padList then we can assume that that pad
2114 // should not be used, therefore invalidate this netcode.
2115 removeCodeList.push_back( netCode );
2116 break;
2117 }
2118 }
2119 }
2120
2121 for( int removeCode : removeCodeList )
2122 netcodeList.remove( removeCode );
2123
2124 std::unordered_set<BOARD_ITEM*> localConnectionList;
2125
2126 for( int netCode : netcodeList )
2127 {
2128 for( BOARD_ITEM* item : conn->GetNetItems( netCode, { PCB_TRACE_T,
2129 PCB_ARC_T,
2130 PCB_VIA_T,
2131 PCB_SHAPE_T } ) )
2132 {
2133 localConnectionList.insert( item );
2134 }
2135 }
2136
2137 for( BOARD_ITEM* item : localConnectionList )
2138 select( item );
2139}
2140
2141
2143{
2144 std::vector<BOARD_ITEM*>* items = aEvent.Parameter<std::vector<BOARD_ITEM*>*>();
2145
2146 if( items )
2147 doSyncSelection( *items, false );
2148
2149 return 0;
2150}
2151
2152
2154{
2155 std::vector<BOARD_ITEM*>* items = aEvent.Parameter<std::vector<BOARD_ITEM*>*>();
2156
2157 if( items )
2158 doSyncSelection( *items, true );
2159
2160 return 0;
2161}
2162
2163
2164void PCB_SELECTION_TOOL::doSyncSelection( const std::vector<BOARD_ITEM*>& aItems, bool aWithNets )
2165{
2166 ClearSelection( true /*quiet mode*/ );
2167
2168 // Perform individual selection of each item before processing the event.
2169 for( BOARD_ITEM* item : aItems )
2170 select( item );
2171
2172 if( aWithNets )
2173 selectConnections( aItems );
2174
2176
2177 if( bbox.GetWidth() != 0 && bbox.GetHeight() != 0 )
2178 {
2180 {
2182 ZoomFitCrossProbeBBox( bbox );
2183
2184 m_frame->FocusOnLocation( bbox.Centre() );
2185 }
2186 }
2187
2189
2191
2192 if( m_selection.Size() > 0 )
2194}
2195
2196
2198{
2199 ClearSelection( true /*quiet mode*/ );
2200 wxString sheetPath = *aEvent.Parameter<wxString*>();
2201
2202 selectAllItemsOnSheet( sheetPath );
2203
2205
2206 if( m_selection.Size() > 0 )
2208
2209 return 0;
2210}
2211
2212
2214{
2215 // this function currently only supports footprints since they are only on one sheet.
2216 EDA_ITEM* item = m_selection.Front();
2217
2218 if( !item )
2219 return 0;
2220
2221 if( item->Type() != PCB_FOOTPRINT_T )
2222 return 0;
2223
2224 FOOTPRINT* footprint = dynamic_cast<FOOTPRINT*>( item );
2225
2226 if( !footprint || footprint->GetPath().empty() )
2227 return 0;
2228
2229 ClearSelection( true /*quiet mode*/ );
2230
2231 // get the sheet path only.
2232 wxString sheetPath = footprint->GetPath().AsString().BeforeLast( '/' );
2233
2234 if( sheetPath.IsEmpty() )
2235 sheetPath += '/';
2236
2237 selectAllItemsOnSheet( sheetPath );
2238
2239 // Inform other potentially interested tools
2240 if( m_selection.Size() > 0 )
2242
2243 return 0;
2244}
2245
2246
2248{
2249 // Should recalculate the view to zoom in on the selection.
2250 BOX2I selectionBox = m_selection.GetBoundingBox();
2252
2253 VECTOR2D screenSize = view->ToWorld( ToVECTOR2D( m_frame->GetCanvas()->GetClientSize() ),
2254 false );
2255 screenSize.x = std::max( 10.0, screenSize.x );
2256 screenSize.y = std::max( 10.0, screenSize.y );
2257
2258 if( selectionBox.GetWidth() != 0 || selectionBox.GetHeight() != 0 )
2259 {
2260 VECTOR2D vsize = selectionBox.GetSize();
2261 double scale = view->GetScale() / std::max( fabs( vsize.x / screenSize.x ),
2262 fabs( vsize.y / screenSize.y ) );
2263 view->SetScale( scale );
2264 view->SetCenter( selectionBox.Centre() );
2265 view->Add( &m_selection );
2266 }
2267
2269}
2270
2271
2273{
2274 // Should recalculate the view to zoom in on the bbox.
2276
2277 if( aBBox.GetWidth() == 0 )
2278 return;
2279
2280 BOX2I bbox = aBBox;
2281 bbox.Normalize();
2282
2283 //#define DEFAULT_PCBNEW_CODE // Un-comment for normal full zoom KiCad algorithm
2284#ifdef DEFAULT_PCBNEW_CODE
2285 auto bbSize = bbox.Inflate( bbox.GetWidth() * 0.2f ).GetSize();
2286 auto screenSize = view->ToWorld( GetCanvas()->GetClientSize(), false );
2287
2288 // The "fabs" on x ensures the right answer when the view is flipped
2289 screenSize.x = std::max( 10.0, fabs( screenSize.x ) );
2290 screenSize.y = std::max( 10.0, screenSize.y );
2291 double ratio = std::max( fabs( bbSize.x / screenSize.x ), fabs( bbSize.y / screenSize.y ) );
2292
2293 // Try not to zoom on every cross-probe; it gets very noisy
2294 if( crossProbingSettings.zoom_to_fit && ( ratio < 0.5 || ratio > 1.0 ) )
2295 view->SetScale( view->GetScale() / ratio );
2296#endif // DEFAULT_PCBNEW_CODE
2297
2298#ifndef DEFAULT_PCBNEW_CODE // Do the scaled zoom
2299 auto bbSize = bbox.Inflate( KiROUND( bbox.GetWidth() * 0.2 ) ).GetSize();
2300 VECTOR2D screenSize = view->ToWorld( ToVECTOR2D( m_frame->GetCanvas()->GetClientSize() ),
2301 false );
2302
2303 // This code tries to come up with a zoom factor that doesn't simply zoom in
2304 // to the cross probed component, but instead shows a reasonable amount of the
2305 // circuit around it to provide context. This reduces or eliminates the need
2306 // to manually change the zoom because it's too close.
2307
2308 // Using the default text height as a constant to compare against, use the
2309 // height of the bounding box of visible items for a footprint to figure out
2310 // if this is a big footprint (like a processor) or a small footprint (like a resistor).
2311 // This ratio is not useful by itself as a scaling factor. It must be "bent" to
2312 // provide good scaling at varying component sizes. Bigger components need less
2313 // scaling than small ones.
2314 double currTextHeight = pcbIUScale.mmToIU( DEFAULT_TEXT_SIZE );
2315
2316 double compRatio = bbSize.y / currTextHeight; // Ratio of component to text height
2317
2318 // This will end up as the scaling factor we apply to "ratio".
2319 double compRatioBent = 1.0;
2320
2321 // This is similar to the original KiCad code that scaled the zoom to make sure
2322 // components were visible on screen. It's simply a ratio of screen size to
2323 // component size, and its job is to zoom in to make the component fullscreen.
2324 // Earlier in the code the component BBox is given a 20% margin to add some
2325 // breathing room. We compare the height of this enlarged component bbox to the
2326 // default text height. If a component will end up with the sides clipped, we
2327 // adjust later to make sure it fits on screen.
2328 //
2329 // The "fabs" on x ensures the right answer when the view is flipped
2330 screenSize.x = std::max( 10.0, fabs( screenSize.x ) );
2331 screenSize.y = std::max( 10.0, screenSize.y );
2332 double ratio = std::max( -1.0, fabs( bbSize.y / screenSize.y ) );
2333
2334 // Original KiCad code for how much to scale the zoom
2335 double kicadRatio = std::max( fabs( bbSize.x / screenSize.x ),
2336 fabs( bbSize.y / screenSize.y ) );
2337
2338 // LUT to scale zoom ratio to provide reasonable schematic context. Must work
2339 // with footprints of varying sizes (e.g. 0402 package and 200 pin BGA).
2340 // "first" is used as the input and "second" as the output
2341 //
2342 // "first" = compRatio (footprint height / default text height)
2343 // "second" = Amount to scale ratio by
2344 std::vector<std::pair<double, double>> lut {
2345 { 1, 8 },
2346 { 1.5, 5 },
2347 { 3, 3 },
2348 { 4.5, 2.5 },
2349 { 8, 2.0 },
2350 { 12, 1.7 },
2351 { 16, 1.5 },
2352 { 24, 1.3 },
2353 { 32, 1.0 },
2354 };
2355
2356
2357 std::vector<std::pair<double, double>>::iterator it;
2358
2359 compRatioBent = lut.back().second; // Large component default
2360
2361 if( compRatio >= lut.front().first )
2362 {
2363 // Use LUT to do linear interpolation of "compRatio" within "first", then
2364 // use that result to linearly interpolate "second" which gives the scaling
2365 // factor needed.
2366
2367 for( it = lut.begin(); it < lut.end() - 1; it++ )
2368 {
2369 if( it->first <= compRatio && next( it )->first >= compRatio )
2370 {
2371 double diffx = compRatio - it->first;
2372 double diffn = next( it )->first - it->first;
2373
2374 compRatioBent = it->second + ( next( it )->second - it->second ) * diffx / diffn;
2375 break; // We have our interpolated value
2376 }
2377 }
2378 }
2379 else
2380 {
2381 compRatioBent = lut.front().second; // Small component default
2382 }
2383
2384 // If the width of the part we're probing is bigger than what the screen width will be
2385 // after the zoom, then punt and use the KiCad zoom algorithm since it guarantees the
2386 // part's width will be encompassed within the screen. This will apply to parts that
2387 // are much wider than they are tall.
2388
2389 if( bbSize.x > screenSize.x * ratio * compRatioBent )
2390 {
2391 // Use standard KiCad zoom algorithm for parts too wide to fit screen/
2392 ratio = kicadRatio;
2393 compRatioBent = 1.0; // Reset so we don't modify the "KiCad" ratio
2394 wxLogTrace( "CROSS_PROBE_SCALE",
2395 "Part TOO WIDE for screen. Using normal KiCad zoom ratio: %1.5f", ratio );
2396 }
2397
2398 // Now that "compRatioBent" holds our final scaling factor we apply it to the original
2399 // fullscreen zoom ratio to arrive at the final ratio itself.
2400 ratio *= compRatioBent;
2401
2402 bool alwaysZoom = false; // DEBUG - allows us to minimize zooming or not
2403
2404 // Try not to zoom on every cross-probe; it gets very noisy
2405 if( ( ratio < 0.5 || ratio > 1.0 ) || alwaysZoom )
2406 view->SetScale( view->GetScale() / ratio );
2407#endif // ifndef DEFAULT_PCBNEW_CODE
2408}
2409
2410
2412{
2413 bool cleared = false;
2414
2415 if( m_selection.GetSize() > 0 )
2416 {
2417 // Don't fire an event now; most of the time it will be redundant as we're about to
2418 // fire a SelectedEvent.
2419 cleared = true;
2420 ClearSelection( true /*quiet mode*/ );
2421 }
2422
2423 if( aItem )
2424 {
2425 switch( aItem->Type() )
2426 {
2427 case PCB_NETINFO_T:
2428 {
2429 int netCode = static_cast<NETINFO_ITEM*>( aItem )->GetNetCode();
2430
2431 if( netCode > 0 )
2432 {
2433 SelectAllItemsOnNet( netCode, true );
2434 m_frame->FocusOnLocation( aItem->GetCenter() );
2435 }
2436 break;
2437 }
2438
2439 default:
2440 select( aItem );
2441 m_frame->FocusOnLocation( aItem->GetPosition() );
2442 }
2443
2444 // If the item has a bounding box, then zoom out if needed
2445 if( aItem->GetBoundingBox().GetHeight() > 0 && aItem->GetBoundingBox().GetWidth() > 0 )
2446 {
2447 // This adds some margin
2448 double marginFactor = 2;
2449
2450 KIGFX::PCB_VIEW* pcbView = canvas()->GetView();
2451 BOX2D screenBox = pcbView->GetViewport();
2452 VECTOR2D screenSize = screenBox.GetSize();
2453 BOX2I screenRect = BOX2ISafe( screenBox.GetOrigin(), screenSize / marginFactor );
2454
2455 if( !screenRect.Contains( aItem->GetBoundingBox() ) )
2456 {
2457 double scaleX = screenSize.x /
2458 static_cast<double>( aItem->GetBoundingBox().GetWidth() );
2459 double scaleY = screenSize.y /
2460 static_cast<double>( aItem->GetBoundingBox().GetHeight() );
2461
2462 scaleX /= marginFactor;
2463 scaleY /= marginFactor;
2464
2465 double scale = scaleX > scaleY ? scaleY : scaleX;
2466
2467 if( scale < 1 ) // Don't zoom in, only zoom out
2468 {
2469 pcbView->SetScale( pcbView->GetScale() * ( scale ) );
2470
2471 //Let's refocus because there is an algorithm to avoid dialogs in there.
2472 m_frame->FocusOnLocation( aItem->GetCenter() );
2473 }
2474 }
2475 }
2476 // Inform other potentially interested tools
2478 }
2479 else if( cleared )
2480 {
2482 }
2483
2485}
2486
2487
2493static bool itemIsIncludedByFilter( const BOARD_ITEM& aItem, const BOARD& aBoard,
2494 const DIALOG_FILTER_SELECTION::OPTIONS& aFilterOptions )
2495{
2496 switch( aItem.Type() )
2497 {
2498 case PCB_FOOTPRINT_T:
2499 {
2500 const FOOTPRINT& footprint = static_cast<const FOOTPRINT&>( aItem );
2501
2502 return aFilterOptions.includeModules
2503 && ( aFilterOptions.includeLockedModules || !footprint.IsLocked() );
2504 }
2505
2506 case PCB_TRACE_T:
2507 case PCB_ARC_T:
2508 return aFilterOptions.includeTracks;
2509
2510 case PCB_VIA_T:
2511 return aFilterOptions.includeVias;
2512
2513 case PCB_ZONE_T:
2514 return aFilterOptions.includeZones;
2515
2516 case PCB_SHAPE_T:
2517 case PCB_TARGET_T:
2518 case PCB_DIM_ALIGNED_T:
2519 case PCB_DIM_CENTER_T:
2520 case PCB_DIM_RADIAL_T:
2522 case PCB_DIM_LEADER_T:
2523 if( aItem.GetLayer() == Edge_Cuts )
2524 return aFilterOptions.includeBoardOutlineLayer;
2525 else
2526 return aFilterOptions.includeItemsOnTechLayers;
2527
2528 case PCB_FIELD_T:
2529 case PCB_TEXT_T:
2530 case PCB_TEXTBOX_T:
2531 case PCB_TABLE_T:
2532 case PCB_TABLECELL_T:
2533 return aFilterOptions.includePcbTexts;
2534
2535 default:
2536 // Filter dialog is inclusive, not exclusive. If it's not included, then it doesn't
2537 // get selected.
2538 return false;
2539 }
2540}
2541
2542
2544{
2545 const BOARD& board = *getModel<BOARD>();
2546 DIALOG_FILTER_SELECTION::OPTIONS& opts = m_priv->m_filterOpts;
2547 DIALOG_FILTER_SELECTION dlg( m_frame, opts );
2548
2549 const int cmd = dlg.ShowModal();
2550
2551 if( cmd != wxID_OK )
2552 return 0;
2553
2554 // copy current selection
2555 std::deque<EDA_ITEM*> selection = m_selection.GetItems();
2556
2557 ClearSelection( true /*quiet mode*/ );
2558
2559 // re-select items from the saved selection according to the dialog options
2560 for( EDA_ITEM* i : selection )
2561 {
2562 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( i );
2563 bool include = itemIsIncludedByFilter( *item, board, opts );
2564
2565 if( include )
2566 select( item );
2567 }
2568
2570
2571 return 0;
2572}
2573
2574
2576{
2577 if( aCollector.GetCount() == 0 )
2578 return;
2579
2580 std::set<BOARD_ITEM*> rejected;
2581
2582 for( EDA_ITEM* i : aCollector )
2583 {
2584 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( i );
2585
2586 if( !itemPassesFilter( item, aMultiSelect ) )
2587 rejected.insert( item );
2588 }
2589
2590 for( BOARD_ITEM* item : rejected )
2591 aCollector.Remove( item );
2592}
2593
2594
2595bool PCB_SELECTION_TOOL::itemPassesFilter( BOARD_ITEM* aItem, bool aMultiSelect )
2596{
2597 if( !m_filter.lockedItems )
2598 {
2599 if( aItem->IsLocked() || ( aItem->GetParent() && aItem->GetParent()->IsLocked() ) )
2600 {
2601 if( aItem->Type() == PCB_PAD_T && !aMultiSelect )
2602 {
2603 // allow a single pad to be selected -- there are a lot of operations that
2604 // require this so we allow this one inconsistency
2605 }
2606 else
2607 {
2608 return false;
2609 }
2610 }
2611 }
2612
2613 if( !aItem )
2614 return false;
2615
2616 KICAD_T itemType = aItem->Type();
2617
2618 if( itemType == PCB_GENERATOR_T )
2619 {
2620 if( static_cast<PCB_GENERATOR*>( aItem )->GetItems().empty() )
2621 {
2622 if( !m_filter.otherItems )
2623 return false;
2624 }
2625 else
2626 {
2627 itemType = ( *static_cast<PCB_GENERATOR*>( aItem )->GetItems().begin() )->Type();
2628 }
2629 }
2630
2631 switch( itemType )
2632 {
2633 case PCB_FOOTPRINT_T:
2634 if( !m_filter.footprints )
2635 return false;
2636
2637 break;
2638
2639 case PCB_PAD_T:
2640 if( !m_filter.pads )
2641 return false;
2642
2643 break;
2644
2645 case PCB_TRACE_T:
2646 case PCB_ARC_T:
2647 if( !m_filter.tracks )
2648 return false;
2649
2650 break;
2651
2652 case PCB_VIA_T:
2653 if( !m_filter.vias )
2654 return false;
2655
2656 break;
2657
2658 case PCB_ZONE_T:
2659 {
2660 ZONE* zone = static_cast<ZONE*>( aItem );
2661
2662 if( ( !m_filter.zones && !zone->GetIsRuleArea() )
2663 || ( !m_filter.keepouts && zone->GetIsRuleArea() ) )
2664 {
2665 return false;
2666 }
2667
2668 // m_SolderMaskBridges zone is a special zone, only used to showsolder mask briges
2669 // after running DRC. it is not really a board item.
2670 // Never select it or delete by a Commit.
2671 if( zone == m_frame->GetBoard()->m_SolderMaskBridges )
2672 return false;
2673
2674 break;
2675 }
2676
2677 case PCB_SHAPE_T:
2678 case PCB_TARGET_T:
2679 if( !m_filter.graphics )
2680 return false;
2681
2682 break;
2683
2685 if( !m_filter.graphics )
2686 return false;
2687
2688 // a reference image living in a footprint must not be selected inside the board editor
2689 if( !m_isFootprintEditor && aItem->GetParentFootprint() )
2690 return false;
2691
2692 break;
2693
2694 case PCB_FIELD_T:
2695 case PCB_TEXT_T:
2696 case PCB_TEXTBOX_T:
2697 case PCB_TABLE_T:
2698 case PCB_TABLECELL_T:
2699 if( !m_filter.text )
2700 return false;
2701
2702 break;
2703
2704 case PCB_DIM_ALIGNED_T:
2705 case PCB_DIM_CENTER_T:
2706 case PCB_DIM_RADIAL_T:
2708 case PCB_DIM_LEADER_T:
2709 if( !m_filter.dimensions )
2710 return false;
2711
2712 break;
2713
2714 default:
2715 if( !m_filter.otherItems )
2716 return false;
2717 }
2718
2719 return true;
2720}
2721
2722
2724{
2725 if( m_selection.Empty() )
2726 return;
2727
2728 while( m_selection.GetSize() )
2730
2731 view()->Update( &m_selection );
2732
2733 m_selection.SetIsHover( false );
2735
2736 // Inform other potentially interested tools
2737 if( !aQuietMode )
2738 {
2741 }
2742}
2743
2744
2746{
2748
2749 bool enteredGroupFound = false;
2750
2751 INSPECTOR_FUNC inspector =
2752 [&]( EDA_ITEM* item, void* testData )
2753 {
2754 if( item->IsSelected() )
2755 {
2756 EDA_ITEM* parent = item->GetParent();
2757
2758 // Let selected parents handle their children.
2759 if( parent && parent->IsSelected() )
2760 return INSPECT_RESULT::CONTINUE;
2761
2762 highlight( item, SELECTED, &m_selection );
2763 }
2764
2765 if( item->Type() == PCB_GROUP_T )
2766 {
2767 if( item == m_enteredGroup )
2768 {
2769 item->SetFlags( ENTERED );
2770 enteredGroupFound = true;
2771 }
2772 else
2773 {
2774 item->ClearFlags( ENTERED );
2775 }
2776 }
2777
2778 return INSPECT_RESULT::CONTINUE;
2779 };
2780
2783
2784 if( !enteredGroupFound )
2785 {
2787 m_enteredGroup = nullptr;
2788 }
2789}
2790
2791
2792bool PCB_SELECTION_TOOL::Selectable( const BOARD_ITEM* aItem, bool checkVisibilityOnly ) const
2793{
2794 const RENDER_SETTINGS* settings = getView()->GetPainter()->GetSettings();
2795 const PCB_DISPLAY_OPTIONS& options = frame()->GetDisplayOptions();
2796
2797 auto visibleLayers =
2798 [&]()
2799 {
2801 {
2802 LSET set;
2803
2804 for( PCB_LAYER_ID layer : LSET::AllLayersMask().Seq() )
2805 set.set( layer, view()->IsLayerVisible( layer ) );
2806
2807 return set;
2808 }
2809 else
2810 {
2811 return board()->GetVisibleLayers();
2812 }
2813 };
2814
2815 auto layerVisible =
2816 [&]( PCB_LAYER_ID aLayer )
2817 {
2819 return view()->IsLayerVisible( aLayer );
2820 else
2821 return board()->IsLayerVisible( aLayer );
2822 };
2823
2824 if( settings->GetHighContrast() )
2825 {
2826 const std::set<int> activeLayers = settings->GetHighContrastLayers();
2827 bool onActiveLayer = false;
2828
2829 for( int layer : activeLayers )
2830 {
2831 // NOTE: Only checking the regular layers (not GAL meta-layers)
2832 if( layer < PCB_LAYER_ID_COUNT && aItem->IsOnLayer( ToLAYER_ID( layer ) ) )
2833 {
2834 onActiveLayer = true;
2835 break;
2836 }
2837 }
2838
2839 if( !onActiveLayer && aItem->Type() != PCB_MARKER_T )
2840 {
2841 // We do not want to select items that are in the background
2842 return false;
2843 }
2844 }
2845
2846 if( aItem->Type() == PCB_FOOTPRINT_T )
2847 {
2848 const FOOTPRINT* footprint = static_cast<const FOOTPRINT*>( aItem );
2849
2850 // In footprint editor, we do not want to select the footprint itself.
2852 return false;
2853
2854 // Allow selection of footprints if some part of the footprint is visible.
2855 if( footprint->GetSide() != UNDEFINED_LAYER && !m_skip_heuristics )
2856 {
2857 LSET boardSide = footprint->IsFlipped() ? LSET::BackMask() : LSET::FrontMask();
2858
2859 if( !( visibleLayers() & boardSide ).any() )
2860 return false;
2861 }
2862
2863 // If the footprint has no items except the reference and value fields, include the
2864 // footprint in the selections.
2865 if( footprint->GraphicalItems().empty()
2866 && footprint->Pads().empty()
2867 && footprint->Zones().empty() )
2868 {
2869 return true;
2870 }
2871
2872 for( const BOARD_ITEM* item : footprint->GraphicalItems() )
2873 {
2874 if( Selectable( item, true ) )
2875 return true;
2876 }
2877
2878 for( const PAD* pad : footprint->Pads() )
2879 {
2880 if( Selectable( pad, true ) )
2881 return true;
2882 }
2883
2884 for( const ZONE* zone : footprint->Zones() )
2885 {
2886 if( Selectable( zone, true ) )
2887 return true;
2888 }
2889
2890 return false;
2891 }
2892 else if( aItem->Type() == PCB_GROUP_T )
2893 {
2894 PCB_GROUP* group = const_cast<PCB_GROUP*>( static_cast<const PCB_GROUP*>( aItem ) );
2895
2896 // Similar to logic for footprint, a group is selectable if any of its members are.
2897 // (This recurses.)
2898 for( BOARD_ITEM* item : group->GetItems() )
2899 {
2900 if( Selectable( item, true ) )
2901 return true;
2902 }
2903
2904 return false;
2905 }
2906
2907 if( aItem->GetParentGroup() && aItem->GetParentGroup()->Type() == PCB_GENERATOR_T )
2908 return false;
2909
2910 const ZONE* zone = nullptr;
2911 const PCB_VIA* via = nullptr;
2912 const PAD* pad = nullptr;
2913 const PCB_TEXT* text = nullptr;
2914 const PCB_FIELD* field = nullptr;
2915
2916 // Most footprint children can only be selected in the footprint editor.
2917 if( aItem->GetParentFootprint() && !m_isFootprintEditor && !checkVisibilityOnly )
2918 {
2919 if( aItem->Type() != PCB_FIELD_T && aItem->Type() != PCB_PAD_T
2920 && aItem->Type() != PCB_TEXT_T )
2921 {
2922 return false;
2923 }
2924 }
2925
2926 switch( aItem->Type() )
2927 {
2928 case PCB_ZONE_T:
2929 if( !board()->IsElementVisible( LAYER_ZONES ) || ( options.m_ZoneOpacity == 0.00 ) )
2930 return false;
2931
2932 zone = static_cast<const ZONE*>( aItem );
2933
2934 // A teardrop is modelled as a property of a via, pad or the board (for track-to-track
2935 // teardrops). The underlying zone is only an implementation detail.
2936 if( zone->IsTeardropArea() && !board()->LegacyTeardrops() )
2937 return false;
2938
2939 // zones can exist on multiple layers!
2940 if( !( zone->GetLayerSet() & visibleLayers() ).any() )
2941 return false;
2942
2943 break;
2944
2945 case PCB_TRACE_T:
2946 case PCB_ARC_T:
2947 if( !board()->IsElementVisible( LAYER_TRACKS ) || ( options.m_TrackOpacity == 0.00 ) )
2948 return false;
2949
2950 if( !layerVisible( aItem->GetLayer() ) )
2951 return false;
2952
2953 break;
2954
2955 case PCB_VIA_T:
2956 if( !board()->IsElementVisible( LAYER_VIAS ) || ( options.m_ViaOpacity == 0.00 ) )
2957 return false;
2958
2959 via = static_cast<const PCB_VIA*>( aItem );
2960
2961 // For vias it is enough if only one of its layers is visible
2962 if( !( visibleLayers() & via->GetLayerSet() ).any() )
2963 return false;
2964
2965 break;
2966
2967 case PCB_FIELD_T:
2968 field = static_cast<const PCB_FIELD*>( aItem );
2969
2970 if( field->IsReference() && !view()->IsLayerVisible( LAYER_FP_REFERENCES ) )
2971 return false;
2972
2973 if( field->IsValue() && !view()->IsLayerVisible( LAYER_FP_VALUES ) )
2974 return false;
2975
2976 // Handle all other fields with normal text visibility controls
2978 case PCB_TEXT_T:
2979 text = static_cast<const PCB_TEXT*>( aItem );
2980
2981 if( !text->IsVisible() )
2982 {
2983 if( !m_isFootprintEditor )
2984 return false;
2985 }
2986
2987 if( !layerVisible( text->GetLayer() ) )
2988 return false;
2989
2990 // Apply the LOD visibility test as well
2991 if( !view()->IsVisible( text ) )
2992 return false;
2993
2994 if( aItem->GetParentFootprint() )
2995 {
2996 int controlLayer = LAYER_FP_TEXT;
2997
2998 if( text->GetText() == wxT( "${REFERENCE}" ) )
2999 controlLayer = LAYER_FP_REFERENCES;
3000 else if( text->GetText() == wxT( "${VALUE}" ) )
3001 controlLayer = LAYER_FP_VALUES;
3002
3003 if( !view()->IsLayerVisible( controlLayer ) )
3004 return false;
3005 }
3006
3007 break;
3008
3010 if( options.m_ImageOpacity == 0.00 )
3011 return false;
3012
3013 // Bitmap images on board are hidden if LAYER_DRAW_BITMAPS is not visible
3015 return false;
3016
3018
3019 case PCB_SHAPE_T:
3020 // Note: LAYER_SHAPES does not control the visibility of a PCB_SHAPE_T, only
3021 // the opacity of filled areas
3022 // The visibility is managed by the item layer
3023 if( options.m_FilledShapeOpacity == 0.0 )
3024 return false;
3025
3027
3028 case PCB_TEXTBOX_T:
3029 case PCB_TABLE_T:
3030 case PCB_TABLECELL_T:
3031 if( !layerVisible( aItem->GetLayer() ) )
3032 return false;
3033
3034 if( aItem->Type() == PCB_TABLECELL_T )
3035 {
3036 const PCB_TABLECELL* cell = static_cast<const PCB_TABLECELL*>( aItem );
3037
3038 if( cell->GetRowSpan() == 0 || cell->GetColSpan() == 0 )
3039 return false;
3040 }
3041
3042 break;
3043
3044 case PCB_DIM_ALIGNED_T:
3045 case PCB_DIM_LEADER_T:
3046 case PCB_DIM_CENTER_T:
3047 case PCB_DIM_RADIAL_T:
3049 if( !layerVisible( aItem->GetLayer() ) )
3050 return false;
3051
3052 break;
3053
3054 case PCB_PAD_T:
3055 if( options.m_PadOpacity == 0.00 )
3056 return false;
3057
3058 pad = static_cast<const PAD*>( aItem );
3059
3060 if( pad->GetAttribute() == PAD_ATTRIB::PTH || pad->GetAttribute() == PAD_ATTRIB::NPTH )
3061 {
3062 // A pad's hole is visible on every layer the pad is visible on plus many layers the
3063 // pad is not visible on -- so we only need to check for any visible hole layers.
3064 if( !( visibleLayers() & LSET::PhysicalLayersMask() ).any() )
3065 return false;
3066 }
3067 else
3068 {
3069 if( !( pad->GetLayerSet() & visibleLayers() ).any() )
3070 return false;
3071 }
3072
3073 break;
3074
3075 // These are not selectable
3076 case PCB_NETINFO_T:
3077 case NOT_USED:
3078 case TYPE_NOT_INIT:
3079 return false;
3080
3081 default: // Suppress warnings
3082 break;
3083 }
3084
3085 return true;
3086}
3087
3088
3090{
3091 if( !aItem || aItem->IsSelected() )
3092 return;
3093
3094 if( aItem->Type() == PCB_PAD_T )
3095 {
3096 FOOTPRINT* footprint = static_cast<FOOTPRINT*>( aItem->GetParent() );
3097
3098 if( m_selection.Contains( footprint ) )
3099 return;
3100 }
3101
3102 if( m_enteredGroup &&
3103 !PCB_GROUP::WithinScope( static_cast<BOARD_ITEM*>( aItem ), m_enteredGroup,
3105 {
3106 ExitGroup();
3107 }
3108
3109 highlight( aItem, SELECTED, &m_selection );
3110}
3111
3112
3114{
3115 unhighlight( aItem, SELECTED, &m_selection );
3116}
3117
3118
3119void PCB_SELECTION_TOOL::highlight( EDA_ITEM* aItem, int aMode, SELECTION* aGroup )
3120{
3121 if( aGroup )
3122 aGroup->Add( aItem );
3123
3124 highlightInternal( aItem, aMode, aGroup != nullptr );
3125 view()->Update( aItem, KIGFX::REPAINT );
3126
3127 // Many selections are very temporal and updating the display each time just
3128 // creates noise.
3129 if( aMode == BRIGHTENED )
3131}
3132
3133
3134void PCB_SELECTION_TOOL::highlightInternal( EDA_ITEM* aItem, int aMode, bool aUsingOverlay )
3135{
3136 if( aMode == SELECTED )
3137 aItem->SetSelected();
3138 else if( aMode == BRIGHTENED )
3139 aItem->SetBrightened();
3140
3141 if( aUsingOverlay && aMode != BRIGHTENED )
3142 view()->Hide( aItem, true ); // Hide the original item, so it is shown only on overlay
3143
3144 if( aItem->IsBOARD_ITEM() )
3145 {
3146 BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( aItem );
3147 boardItem->RunOnDescendants( std::bind( &PCB_SELECTION_TOOL::highlightInternal, this, _1,
3148 aMode, aUsingOverlay ) );
3149 }
3150}
3151
3152
3153void PCB_SELECTION_TOOL::unhighlight( EDA_ITEM* aItem, int aMode, SELECTION* aGroup )
3154{
3155 if( aGroup )
3156 aGroup->Remove( aItem );
3157
3158 unhighlightInternal( aItem, aMode, aGroup != nullptr );
3159 view()->Update( aItem, KIGFX::REPAINT );
3160
3161 // Many selections are very temporal and updating the display each time just creates noise.
3162 if( aMode == BRIGHTENED )
3164}
3165
3166
3167void PCB_SELECTION_TOOL::unhighlightInternal( EDA_ITEM* aItem, int aMode, bool aUsingOverlay )
3168{
3169 if( aMode == SELECTED )
3170 aItem->ClearSelected();
3171 else if( aMode == BRIGHTENED )
3172 aItem->ClearBrightened();
3173
3174 if( aUsingOverlay && aMode != BRIGHTENED )
3175 {
3176 view()->Hide( aItem, false ); // Restore original item visibility...
3177 view()->Update( aItem ); // ... and make sure it's redrawn un-selected
3178 }
3179
3180 if( aItem->IsBOARD_ITEM() )
3181 {
3182 BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( aItem );
3183 boardItem->RunOnDescendants( std::bind( &PCB_SELECTION_TOOL::unhighlightInternal, this, _1,
3184 aMode, aUsingOverlay ) );
3185 }
3186}
3187
3188
3190{
3191 const unsigned GRIP_MARGIN = 20;
3192 int margin = KiROUND( getView()->ToWorld( GRIP_MARGIN ) );
3193
3194 // Check if the point is located close to any of the currently selected items
3195 for( EDA_ITEM* item : m_selection )
3196 {
3197 BOX2I itemBox = item->ViewBBox();
3198 itemBox.Inflate( margin ); // Give some margin for gripping an item
3199
3200 if( itemBox.Contains( aPoint ) )
3201 {
3202 if( item->HitTest( aPoint, margin ) )
3203 return true;
3204
3205 bool found = false;
3206
3207 if( PCB_GROUP* group = dynamic_cast<PCB_GROUP*>( item ) )
3208 {
3209 group->RunOnDescendants(
3210 [&]( BOARD_ITEM* aItem )
3211 {
3212 if( aItem->HitTest( aPoint, margin ) )
3213 found = true;
3214 } );
3215 }
3216
3217 if( found )
3218 return true;
3219 }
3220 }
3221
3222 return false;
3223}
3224
3225
3227 int aMaxDistance ) const
3228{
3229 BOX2D viewportD = getView()->GetViewport();
3230 BOX2I viewport = BOX2ISafe( viewportD );
3231 int distance = INT_MAX;
3232 SEG loc( aWhere, aWhere );
3233
3234 switch( aItem->Type() )
3235 {
3236 case PCB_FIELD_T:
3237 case PCB_TEXT_T:
3238 {
3239 PCB_TEXT* text = static_cast<PCB_TEXT*>( aItem );
3240
3241 // Add a bit of slop to text-shapes
3242 if( text->GetEffectiveTextShape()->Collide( loc, aMaxDistance, &distance ) )
3243 distance = std::clamp( distance - ( aMaxDistance / 2 ), 0, distance );
3244
3245 break;
3246 }
3247
3248 case PCB_TEXTBOX_T:
3249 case PCB_TABLECELL_T:
3250 {
3251 PCB_TEXTBOX* textbox = static_cast<PCB_TEXTBOX*>( aItem );
3252
3253 // Add a bit of slop to text-shapes
3254 if( textbox->GetEffectiveTextShape()->Collide( loc, aMaxDistance, &distance ) )
3255 distance = std::clamp( distance - ( aMaxDistance / 2 ), 0, distance );
3256
3257 break;
3258 }
3259
3260 case PCB_TABLE_T:
3261 {
3262 PCB_TABLE* table = static_cast<PCB_TABLE*>( aItem );
3263
3264 for( PCB_TABLECELL* cell : table->GetCells() )
3265 {
3266 // Add a bit of slop to text-shapes
3267 if( cell->GetEffectiveTextShape()->Collide( loc, aMaxDistance, &distance ) )
3268 distance = std::clamp( distance - ( aMaxDistance / 2 ), 0, distance );
3269 }
3270
3271 break;
3272 }
3273
3274 case PCB_ZONE_T:
3275 {
3276 ZONE* zone = static_cast<ZONE*>( aItem );
3277
3278 // Zone borders are very specific
3279 if( zone->HitTestForEdge( aWhere, aMaxDistance / 2 ) )
3280 distance = 0;
3281 else if( zone->HitTestForEdge( aWhere, aMaxDistance ) )
3282 distance = aMaxDistance / 2;
3283 else
3284 aItem->GetEffectiveShape()->Collide( loc, aMaxDistance, &distance );
3285
3286 break;
3287 }
3288
3289 case PCB_FOOTPRINT_T:
3290 {
3291 FOOTPRINT* footprint = static_cast<FOOTPRINT*>( aItem );
3292 BOX2I bbox = footprint->GetBoundingBox( false );
3293
3294 try
3295 {
3296 footprint->GetBoundingHull().Collide( loc, aMaxDistance, &distance );
3297 }
3298 catch( const std::exception& e )
3299 {
3300 wxFAIL_MSG( wxString::Format( wxT( "Clipper exception occurred: %s" ), e.what() ) );
3301 }
3302
3303 // Consider footprints larger than the viewport only as a last resort
3304 if( bbox.GetHeight() > viewport.GetHeight() || bbox.GetWidth() > viewport.GetWidth() )
3305 distance = INT_MAX / 2;
3306
3307 break;
3308 }
3309
3310 case PCB_MARKER_T:
3311 {
3312 PCB_MARKER* marker = static_cast<PCB_MARKER*>( aItem );
3313 SHAPE_LINE_CHAIN polygon;
3314
3315 marker->ShapeToPolygon( polygon );
3316 polygon.Move( marker->GetPos() );
3317 polygon.Collide( loc, aMaxDistance, &distance );
3318 break;
3319 }
3320
3321 case PCB_GROUP_T:
3322 case PCB_GENERATOR_T:
3323 {
3324 PCB_GROUP* group = static_cast<PCB_GROUP*>( aItem );
3325
3326 for( BOARD_ITEM* member : group->GetItems() )
3327 distance = std::min( distance, hitTestDistance( aWhere, member, aMaxDistance ) );
3328
3329 break;
3330 }
3331
3332 case PCB_PAD_T:
3333 {
3334 static_cast<PAD*>( aItem )->Padstack().ForEachUniqueLayer(
3335 [&]( PCB_LAYER_ID aLayer )
3336 {
3337 int layerDistance = INT_MAX;
3338 aItem->GetEffectiveShape( aLayer )->Collide( loc, aMaxDistance, &layerDistance );
3339 distance = std::min( distance, layerDistance );
3340 } );
3341
3342 break;
3343 }
3344
3345 default:
3346 aItem->GetEffectiveShape()->Collide( loc, aMaxDistance, &distance );
3347 break;
3348 }
3349
3350 return distance;
3351}
3352
3353
3355{
3356 wxCHECK( m_frame, /* void */ );
3357
3358 if( aCollector.GetCount() < 2 )
3359 return;
3360
3361 const RENDER_SETTINGS* settings = getView()->GetPainter()->GetSettings();
3362
3363 wxCHECK( settings, /* void */ );
3364
3365 PCB_LAYER_ID activeLayer = m_frame->GetActiveLayer();
3366 LSET visibleLayers = m_frame->GetBoard()->GetVisibleLayers();
3367 LSET enabledLayers = m_frame->GetBoard()->GetEnabledLayers();
3368 LSEQ enabledLayerStack = enabledLayers.SeqStackupTop2Bottom( activeLayer );
3369
3370 wxCHECK( !enabledLayerStack.empty(), /* void */ );
3371
3372 auto isCopperPourKeepoutZone = []( const BOARD_ITEM* aItem ) -> bool
3373 {
3374 if( aItem->Type() == PCB_ZONE_T )
3375 {
3376 const ZONE* zone = static_cast<const ZONE*>( aItem );
3377
3378 wxCHECK( zone, false );
3379
3380 if( zone->GetIsRuleArea()
3381 && zone->GetDoNotAllowCopperPour() )
3382 return true;
3383 }
3384
3385 return false;
3386 };
3387
3388 std::vector<LAYER_OPACITY_ITEM> opacityStackup;
3389
3390 for( int i = 0; i < aCollector.GetCount(); i++ )
3391 {
3392 const BOARD_ITEM* item = aCollector[i];
3393
3394 LSET itemLayers = item->GetLayerSet() & enabledLayers & visibleLayers;
3395 LSEQ itemLayerSeq = itemLayers.Seq( enabledLayerStack );
3396
3397 for( PCB_LAYER_ID layer : itemLayerSeq )
3398 {
3399 COLOR4D color = settings->GetColor( item, layer );
3400
3401 if( color.a == 0 )
3402 continue;
3403
3404 LAYER_OPACITY_ITEM opacityItem;
3405
3406 opacityItem.m_Layer = layer;
3407 opacityItem.m_Opacity = color.a;
3408 opacityItem.m_Item = item;
3409
3410 if( isCopperPourKeepoutZone( item ) )
3411 opacityItem.m_Opacity = 0.0;
3412
3413 opacityStackup.emplace_back( opacityItem );
3414 }
3415 }
3416
3417 std::sort( opacityStackup.begin(), opacityStackup.end(),
3418 [&]( const LAYER_OPACITY_ITEM& aLhs, const LAYER_OPACITY_ITEM& aRhs ) -> bool
3419 {
3420 int retv = enabledLayerStack.TestLayers( aLhs.m_Layer, aRhs.m_Layer );
3421
3422 if( retv )
3423 return retv > 0;
3424
3425 return aLhs.m_Opacity > aRhs.m_Opacity;
3426 } );
3427
3428 std::set<const BOARD_ITEM*> visibleItems;
3429 std::set<const BOARD_ITEM*> itemsToRemove;
3430 double minAlphaLimit = ADVANCED_CFG::GetCfg().m_PcbSelectionVisibilityRatio;
3431 double currentStackupOpacity = 0.0;
3432 PCB_LAYER_ID lastVisibleLayer = PCB_LAYER_ID::UNDEFINED_LAYER;
3433
3434 for( const LAYER_OPACITY_ITEM& opacityItem : opacityStackup )
3435 {
3436 if( lastVisibleLayer == PCB_LAYER_ID::UNDEFINED_LAYER )
3437 {
3438 currentStackupOpacity = opacityItem.m_Opacity;
3439 lastVisibleLayer = opacityItem.m_Layer;
3440 visibleItems.emplace( opacityItem.m_Item );
3441 continue;
3442 }
3443
3444 // Objects to ignore and fallback to the old selection behavior.
3445 auto ignoreItem = [&]()
3446 {
3447 const BOARD_ITEM* item = opacityItem.m_Item;
3448
3449 wxCHECK( item, false );
3450
3451 // Check items that span multiple layers for visibility.
3452 if( visibleItems.count( item ) )
3453 return true;
3454
3455 // Don't prune child items of a footprint that is already visible.
3456 if( item->GetParent()
3457 && ( item->GetParent()->Type() == PCB_FOOTPRINT_T )
3458 && visibleItems.count( item->GetParent() ) )
3459 return true;
3460
3461 // Keepout zones are transparent but for some reason,
3462 // PCB_PAINTER::GetColor() returns the color of the zone it
3463 // prevents from filling.
3464 if( isCopperPourKeepoutZone( item ) )
3465 return true;
3466
3467 return false;
3468 };
3469
3470 // Everything on the currently selected layer is visible;
3471 if( opacityItem.m_Layer == enabledLayerStack[0] )
3472 {
3473 visibleItems.emplace( opacityItem.m_Item );
3474 }
3475 else
3476 {
3477 double itemVisibility = opacityItem.m_Opacity * ( 1.0 - currentStackupOpacity );
3478
3479 if( ( itemVisibility <= minAlphaLimit ) && !ignoreItem() )
3480 itemsToRemove.emplace( opacityItem.m_Item );
3481 else
3482 visibleItems.emplace( opacityItem.m_Item );
3483 }
3484
3485 if( opacityItem.m_Layer != lastVisibleLayer )
3486 {
3487 currentStackupOpacity += opacityItem.m_Opacity * ( 1.0 - currentStackupOpacity );
3488 currentStackupOpacity = std::min( currentStackupOpacity, 1.0 );
3489 lastVisibleLayer = opacityItem.m_Layer;
3490 }
3491 }
3492
3493 for( const BOARD_ITEM* itemToRemove : itemsToRemove )
3494 {
3495 wxCHECK( aCollector.GetCount() > 1, /* void */ );
3496 aCollector.Remove( itemToRemove );
3497 }
3498}
3499
3500
3501// The general idea here is that if the user clicks directly on a small item inside a larger
3502// one, then they want the small item. The quintessential case of this is clicking on a pad
3503// within a footprint, but we also apply it for text within a footprint, footprints within
3504// larger footprints, and vias within either larger pads or longer tracks.
3505//
3506// These "guesses" presume there is area within the larger item to click in to select it. If
3507// an item is mostly covered by smaller items within it, then the guesses are inappropriate as
3508// there might not be any area left to click to select the larger item. In this case we must
3509// leave the items in the collector and bring up a Selection Clarification menu.
3510//
3511// We currently check for pads and text mostly covering a footprint, but we don't check for
3512// smaller footprints mostly covering a larger footprint.
3513//
3515 const VECTOR2I& aWhere ) const
3516{
3517 static const LSET silkLayers( { B_SilkS, F_SilkS } );
3518 static const LSET courtyardLayers( { B_CrtYd, F_CrtYd } );
3519 static std::vector<KICAD_T> singleLayerSilkTypes = { PCB_FIELD_T,
3522 PCB_SHAPE_T };
3523
3524 if( ADVANCED_CFG::GetCfg().m_PcbSelectionVisibilityRatio != 1.0 )
3526
3527 if( aCollector.GetCount() == 1 )
3528 return;
3529
3530 std::set<BOARD_ITEM*> preferred;
3531 std::set<BOARD_ITEM*> rejected;
3532 VECTOR2I where( aWhere.x, aWhere.y );
3533 const RENDER_SETTINGS* settings = getView()->GetPainter()->GetSettings();
3534 PCB_LAYER_ID activeLayer = m_frame->GetActiveLayer();
3535
3536 // If a silk layer is in front, we assume the user is working with silk and give preferential
3537 // treatment to single-layer items on *either* silk layer.
3538 if( silkLayers[activeLayer] )
3539 {
3540 for( int i = 0; i < aCollector.GetCount(); ++i )
3541 {
3542 BOARD_ITEM* item = aCollector[i];
3543
3544 if( item->IsType( singleLayerSilkTypes ) && silkLayers[ item->GetLayer() ] )
3545 preferred.insert( item );
3546 }
3547 }
3548 // Similarly, if a courtyard layer is in front, we assume the user is positioning footprints
3549 // and give preferential treatment to footprints on *both* top and bottom.
3550 else if( courtyardLayers[activeLayer] && settings->GetHighContrast() )
3551 {
3552 for( int i = 0; i < aCollector.GetCount(); ++i )
3553 {
3554 BOARD_ITEM* item = aCollector[i];
3555
3556 if( item->Type() == PCB_FOOTPRINT_T )
3557 preferred.insert( item );
3558 }
3559 }
3560
3561 if( preferred.size() > 0 )
3562 {
3563 aCollector.Empty();
3564
3565 for( BOARD_ITEM* item : preferred )
3566 aCollector.Append( item );
3567
3568 if( preferred.size() == 1 )
3569 return;
3570 }
3571
3572 // Prefer exact hits to sloppy ones
3573 constexpr int MAX_SLOP = 5;
3574
3575 int singlePixel = KiROUND( aCollector.GetGuide()->OnePixelInIU() );
3576 int maxSlop = KiROUND( MAX_SLOP * aCollector.GetGuide()->OnePixelInIU() );
3577 int minSlop = INT_MAX;
3578
3579 std::map<BOARD_ITEM*, int> itemsBySloppiness;
3580
3581 for( int i = 0; i < aCollector.GetCount(); ++i )
3582 {
3583 BOARD_ITEM* item = aCollector[i];
3584 int itemSlop = hitTestDistance( where, item, maxSlop );
3585
3586 itemsBySloppiness[ item ] = itemSlop;
3587
3588 if( itemSlop < minSlop )
3589 minSlop = itemSlop;
3590 }
3591
3592 // Prune sloppier items
3593 if( minSlop < INT_MAX )
3594 {
3595 for( std::pair<BOARD_ITEM*, int> pair : itemsBySloppiness )
3596 {
3597 if( pair.second > minSlop + singlePixel )
3598 aCollector.Transfer( pair.first );
3599 }
3600 }
3601
3602 // If the user clicked on a small item within a much larger one then it's pretty clear
3603 // they're trying to select the smaller one.
3604 constexpr double sizeRatio = 1.5;
3605
3606 std::vector<std::pair<BOARD_ITEM*, double>> itemsByArea;
3607
3608 for( int i = 0; i < aCollector.GetCount(); ++i )
3609 {
3610 BOARD_ITEM* item = aCollector[i];
3611 double area = 0.0;
3612
3613 if( item->Type() == PCB_ZONE_T
3614 && static_cast<ZONE*>( item )->HitTestForEdge( where, maxSlop / 2 ) )
3615 {
3616 // Zone borders are very specific, so make them "small"
3617 area = (double) SEG::Square( singlePixel ) * MAX_SLOP;
3618 }
3619 else if( item->Type() == PCB_VIA_T )
3620 {
3621 // Vias rarely hide other things, and we don't want them deferring to short track
3622 // segments underneath them -- so artificially reduce their size from πr² to r².
3623 area = (double) SEG::Square( static_cast<PCB_VIA*>( item )->GetDrill() / 2 );
3624 }
3625 else if( item->Type() == PCB_REFERENCE_IMAGE_T )
3626 {
3627 BOX2I box = item->GetBoundingBox();
3628 area = (double) box.GetWidth() * box.GetHeight();
3629 }
3630 else
3631 {
3632 try
3633 {
3634 area = FOOTPRINT::GetCoverageArea( item, aCollector );
3635 }
3636 catch( const std::exception& e )
3637 {
3638 wxFAIL_MSG( wxString::Format( wxT( "Clipper exception occurred: %s" ), e.what() ) );
3639 }
3640 }
3641
3642 itemsByArea.emplace_back( item, area );
3643 }
3644
3645 std::sort( itemsByArea.begin(), itemsByArea.end(),
3646 []( const std::pair<BOARD_ITEM*, double>& lhs,
3647 const std::pair<BOARD_ITEM*, double>& rhs ) -> bool
3648 {
3649 return lhs.second < rhs.second;
3650 } );
3651
3652 bool rejecting = false;
3653
3654 for( int i = 1; i < (int) itemsByArea.size(); ++i )
3655 {
3656 if( itemsByArea[i].second > itemsByArea[i-1].second * sizeRatio )
3657 rejecting = true;
3658
3659 if( rejecting )
3660 rejected.insert( itemsByArea[i].first );
3661 }
3662
3663 // Special case: if a footprint is completely covered with other features then there's no
3664 // way to select it -- so we need to leave it in the list for user disambiguation.
3665 constexpr double maxCoverRatio = 0.70;
3666
3667 for( int i = 0; i < aCollector.GetCount(); ++i )
3668 {
3669 if( FOOTPRINT* footprint = dynamic_cast<FOOTPRINT*>( aCollector[i] ) )
3670 {
3671 if( footprint->CoverageRatio( aCollector ) > maxCoverRatio )
3672 rejected.erase( footprint );
3673 }
3674 }
3675
3676 // Hopefully we've now got what the user wanted.
3677 if( (unsigned) aCollector.GetCount() > rejected.size() ) // do not remove everything
3678 {
3679 for( BOARD_ITEM* item : rejected )
3680 aCollector.Transfer( item );
3681 }
3682
3683 // Finally, what we are left with is a set of items of similar coverage area. We now reject
3684 // any that are not on the active layer, to reduce the number of disambiguation menus shown.
3685 // If the user wants to force-disambiguate, they can either switch layers or use the modifier
3686 // key to force the menu.
3687 if( aCollector.GetCount() > 1 )
3688 {
3689 bool haveItemOnActive = false;
3690 rejected.clear();
3691
3692 for( int i = 0; i < aCollector.GetCount(); ++i )
3693 {
3694 if( !aCollector[i]->IsOnLayer( activeLayer ) )
3695 rejected.insert( aCollector[i] );
3696 else
3697 haveItemOnActive = true;
3698 }
3699
3700 if( haveItemOnActive )
3701 {
3702 for( BOARD_ITEM* item : rejected )
3703 aCollector.Transfer( item );
3704 }
3705 }
3706}
3707
3708
3710 bool aMultiselect ) const
3711{
3712 std::unordered_set<BOARD_ITEM*> toAdd;
3713
3714 // Set CANDIDATE on all parents which are included in the GENERAL_COLLECTOR. This
3715 // algorithm is O(3n), whereas checking for the parent inclusion could potentially be O(n^2).
3716 for( int j = 0; j < aCollector.GetCount(); j++ )
3717 {
3718 if( aCollector[j]->GetParent() )
3719 aCollector[j]->GetParent()->ClearFlags( CANDIDATE );
3720 }
3721
3722 if( aMultiselect )
3723 {
3724 for( int j = 0; j < aCollector.GetCount(); j++ )
3725 aCollector[j]->SetFlags( CANDIDATE );
3726 }
3727
3728 for( int j = 0; j < aCollector.GetCount(); )
3729 {
3730 BOARD_ITEM* item = aCollector[j];
3731 BOARD_ITEM* parent = item->GetParent();
3732 BOARD_ITEM* start = item;
3733
3734 if( !m_isFootprintEditor && parent && parent->Type() == PCB_FOOTPRINT_T )
3735 start = parent;
3736
3737 // If a group is entered, disallow selections of objects outside the group.
3739 {
3740 aCollector.Remove( item );
3741 continue;
3742 }
3743
3744 // If any element is a member of a group, replace those elements with the top containing
3745 // group.
3748 {
3749 if( top != item )
3750 {
3751 toAdd.insert( top );
3752 top->SetFlags(CANDIDATE );
3753
3754 aCollector.Remove( item );
3755 continue;
3756 }
3757 }
3758
3759 // Footprints are a bit easier as they can't be nested.
3760 if( parent && ( parent->GetFlags() & CANDIDATE ) )
3761 {
3762 // Remove children of selected items
3763 aCollector.Remove( item );
3764 continue;
3765 }
3766
3767 ++j;
3768 }
3769
3770 for( BOARD_ITEM* item : toAdd )
3771 {
3772 if( !aCollector.HasItem( item ) )
3773 aCollector.Append( item );
3774 }
3775}
3776
3777
3779{
3780 std::set<BOARD_ITEM*> to_add;
3781
3782 // Iterate from the back so we don't have to worry about removals.
3783 for( int i = (int) aCollector.GetCount() - 1; i >= 0; --i )
3784 {
3785 BOARD_ITEM* item = aCollector[i];
3786
3787 if( item->Type() == PCB_TABLECELL_T )
3788 {
3789 if( !aCollector.HasItem( item->GetParent() ) )
3790 to_add.insert( item->GetParent() );
3791
3792 aCollector.Remove( item );
3793 }
3794 }
3795
3796 for( BOARD_ITEM* item : to_add )
3797 aCollector.Append( item );
3798}
3799
3800
3802 bool aForcePromotion ) const
3803{
3804 std::set<BOARD_ITEM*> to_add;
3805
3806 // Iterate from the back so we don't have to worry about removals.
3807 for( int i = aCollector.GetCount() - 1; i >= 0; --i )
3808 {
3809 BOARD_ITEM* item = aCollector[i];
3810
3811 if( !m_isFootprintEditor && item->Type() == PCB_PAD_T
3812 && ( !frame()->GetPcbNewSettings()->m_AllowFreePads || aForcePromotion ) )
3813 {
3814 if( !aCollector.HasItem( item->GetParent() ) )
3815 to_add.insert( item->GetParent() );
3816
3817 aCollector.Remove( item );
3818 }
3819 }
3820
3821 for( BOARD_ITEM* item : to_add )
3822 aCollector.Append( item );
3823}
3824
3825
3827{
3828 // Iterate from the back so we don't have to worry about removals.
3829 for( int i = aCollector.GetCount() - 1; i >= 0; --i )
3830 {
3831 BOARD_ITEM* item = aCollector[i];
3832
3833 if( item->Type() == PCB_MARKER_T )
3834 aCollector.Remove( item );
3835 }
3836}
3837
3838
3840 const VECTOR2I& aWhere ) const
3841{
3842 const RENDER_SETTINGS* settings = getView()->GetPainter()->GetSettings();
3843 BOX2D viewport = getView()->GetViewport();
3844 BOX2I extents = BOX2ISafe( viewport );
3845
3846 bool need_direct_hit = false;
3847 FOOTPRINT* single_fp = nullptr;
3848
3849 // If the designer is not modifying the existing selection AND we already have
3850 // a selection, then we only want to select items that are directly under the cursor.
3851 // This prevents us from being unable to clear the selection when zoomed into a footprint
3853 {
3854 need_direct_hit = true;
3855
3856 for( EDA_ITEM* item : m_selection )
3857 {
3858 FOOTPRINT* fp = nullptr;
3859
3860 if( item->Type() != PCB_FOOTPRINT_T )
3861 fp = static_cast<BOARD_ITEM*>( item )->GetParentFootprint();
3862 else
3863 fp = static_cast<FOOTPRINT*>( item );
3864
3865 // If the selection contains items that are not footprints, then don't restrict
3866 // whether we deselect the item or not.
3867 if( !fp )
3868 {
3869 single_fp = nullptr;
3870 break;
3871 }
3872 else if( !single_fp )
3873 {
3874 single_fp = fp;
3875 }
3876 // If the selection contains items from multiple footprints, then don't restrict
3877 // whether we deselect the item or not.
3878 else if( single_fp != fp )
3879 {
3880 single_fp = nullptr;
3881 break;
3882 }
3883 }
3884 }
3885
3886 auto visibleLayers =
3887 [&]()
3888 {
3890 {
3891 LSET set;
3892
3893 for( PCB_LAYER_ID layer : LSET::AllLayersMask().Seq() )
3894 set.set( layer, view()->IsLayerVisible( layer ) );
3895
3896 return set;
3897 }
3898 else
3899 {
3900 return board()->GetVisibleLayers();
3901 }
3902 };
3903
3904 LSET layers = visibleLayers();
3905
3906 if( settings->GetHighContrast() )
3907 {
3908 layers.reset();
3909
3910 const std::set<int> activeLayers = settings->GetHighContrastLayers();
3911
3912 for( int layer : activeLayers )
3913 {
3914 if( layer >= 0 && layer < PCB_LAYER_ID_COUNT )
3915 layers.set( layer );
3916 }
3917 }
3918
3919 // Iterate from the back so we don't have to worry about removals.
3920 for( int i = aCollector.GetCount() - 1; i >= 0; --i )
3921 {
3922 BOARD_ITEM* item = aCollector[i];
3923 FOOTPRINT* fp = dyn_cast<FOOTPRINT*>( item );
3924
3925 if( !fp )
3926 continue;
3927
3928 // Make footprints not difficult to select in high-contrast modes.
3929 if( layers[fp->GetLayer()] )
3930 continue;
3931
3932 BOX2I bbox = fp->GetLayerBoundingBox( layers );
3933
3934 // If the point clicked is not inside the visible bounding box, we can also remove it.
3935 if( !bbox.Contains( aWhere) )
3936 aCollector.Remove( item );
3937
3938 bool has_hit = false;
3939
3940 for( PCB_LAYER_ID layer : layers.Seq() )
3941 {
3942 if( fp->HitTestOnLayer( extents, false, layer ) )
3943 {
3944 has_hit = true;
3945 break;
3946 }
3947 }
3948
3949 // If the point is outside of the visible bounding box, we can remove it.
3950 if( !has_hit )
3951 {
3952 aCollector.Remove( item );
3953 }
3954 // Do not require a direct hit on this fp if the existing selection only contains
3955 // this fp's items. This allows you to have a selection of pads from a single
3956 // footprint and still click in the center of the footprint to select it.
3957 else if( single_fp )
3958 {
3959 if( fp == single_fp )
3960 continue;
3961 }
3962 else if( need_direct_hit )
3963 {
3964 has_hit = false;
3965
3966 for( PCB_LAYER_ID layer : layers.Seq() )
3967 {
3968 if( fp->HitTestOnLayer( aWhere, layer ) )
3969 {
3970 has_hit = true;
3971 break;
3972 }
3973 }
3974
3975 if( !has_hit )
3976 aCollector.Remove( item );
3977 }
3978 }
3979}
3980
3981
3983{
3984 getView()->Update( &m_selection );
3986
3987 return 0;
3988}
3989
3990
3992{
3993 std::set<std::pair<PCB_TABLE*, int>> columns;
3994 bool added = false;
3995
3996 for( EDA_ITEM* item : m_selection )
3997 {
3998 if( PCB_TABLECELL* cell = dynamic_cast<PCB_TABLECELL*>( item ) )
3999 {
4000 PCB_TABLE* table = static_cast<PCB_TABLE*>( cell->GetParent() );
4001 columns.insert( std::make_pair( table, cell->GetColumn() ) );
4002 }
4003 }
4004
4005 for( auto& [ table, col ] : columns )
4006 {
4007 for( int row = 0; row < table->GetRowCount(); ++row )
4008 {
4009 PCB_TABLECELL* cell = table->GetCell( row, col );
4010
4011 if( !cell->IsSelected() )
4012 {
4013 select( table->GetCell( row, col ) );
4014 added = true;
4015 }
4016 }
4017 }
4018
4019 if( added )
4021
4022 return 0;
4023}
4024
4025
4027{
4028 std::set<std::pair<PCB_TABLE*, int>> rows;
4029 bool added = false;
4030
4031 for( EDA_ITEM* item : m_selection )
4032 {
4033 if( PCB_TABLECELL* cell = dynamic_cast<PCB_TABLECELL*>( item ) )
4034 {
4035 PCB_TABLE* table = static_cast<PCB_TABLE*>( cell->GetParent() );
4036 rows.insert( std::make_pair( table, cell->GetRow() ) );
4037 }
4038 }
4039
4040 for( auto& [ table, row ] : rows )
4041 {
4042 for( int col = 0; col < table->GetColCount(); ++col )
4043 {
4044 PCB_TABLECELL* cell = table->GetCell( row, col );
4045
4046 if( !cell->IsSelected() )
4047 {
4048 select( table->GetCell( row, col ) );
4049 added = true;
4050 }
4051 }
4052 }
4053
4054 if( added )
4056
4057 return 0;
4058}
4059
4060
4062{
4063 std::set<PCB_TABLE*> tables;
4064 bool added = false;
4065
4066 for( EDA_ITEM* item : m_selection )
4067 {
4068 if( PCB_TABLECELL* cell = dynamic_cast<PCB_TABLECELL*>( item ) )
4069 tables.insert( static_cast<PCB_TABLE*>( cell->GetParent() ) );
4070 }
4071
4073
4074 for( PCB_TABLE* table : tables )
4075 {
4076 if( !table->IsSelected() )
4077 {
4078 select( table );
4079 added = true;
4080 }
4081 }
4082
4083 if( added )
4085
4086 return 0;
4087}
4088
4089
4091{
4093
4097
4104
4123
4126
4128}
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:176
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:278
FOOTPRINT * GetParentFootprint() const
Definition: board_item.cpp:298
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:1773
ZONE * m_SolderMaskBridges
Definition: board.h:1308
LSET GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition: board.cpp:778
LSET GetVisibleLayers() const
A proxy function that calls the correspondent function in m_BoardSettings.
Definition: board.cpp:792
bool IsElementVisible(GAL_LAYER_ID aLayer) const
Test whether a given element category is visible.
Definition: board.cpp:844
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:784
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:132
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition: eda_shape.h:174
bool IsClosed() const
Definition: eda_shape.cpp:498
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition: eda_shape.h:137
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:1110
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:2699
const BOX2I GetLayerBoundingBox(LSET aLayers) const
Return the bounding box of the footprint on a given set of layers.
Definition: footprint.cpp:1441
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:1658
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:1486
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:1720
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:1295
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:273
BOX2D GetViewport() const
Return the current viewport visible area rectangle.
Definition: view.cpp:522
virtual void SetScale(double aScale, VECTOR2D aAnchor={ 0, 0 })
Set the scaling factor, zooming around a given anchor point.
Definition: view.cpp:562
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition: view.cpp:334
void UpdateAllLayersColor()
Apply the new coloring scheme to all layers.
Definition: view.cpp:765
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:412
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:1669
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:459
bool IsMirroredX() const
Return true if view is flipped across the X axis.
Definition: view.h:247
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:1617
bool IsLayerVisible(int aLayer) const
Return information about visibility of a particular layer.
Definition: view.h:419
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition: view.h:217
void SetCenter(const VECTOR2D &aCenter)
Set the center point of the VIEW (i.e.
Definition: view.cpp:588
void MarkTargetDirty(int aTarget)
Set or clear target 'dirty' flag.
Definition: view.h:636
bool IsVisible(const VIEW_ITEM *aItem) const
Return information if the item is visible (or not).
Definition: view.cpp:1639
void SetVisible(VIEW_ITEM *aItem, bool aIsVisible=true)
Set the item visibility.
Definition: view.cpp:1596
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:711
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:686
static LSET PhysicalLayersMask()
Return a mask holding all layers which are physically realized.
Definition: lset.cpp:766
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:420
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:450
static LSET FrontMask()
Return a mask holding all technical layers and the external CU layer on front side.
Definition: lset.cpp:782
static LSET BackMask()
Return a mask holding all technical layers and the external CU layer on back side.
Definition: lset.cpp:789
bool Contains(PCB_LAYER_ID aLayer) const
See if the layer set contains a PCB layer.
Definition: lset.h:62
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:68
bool IsValue() const
Definition: pcb_field.h:69
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:400
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:218
std::vector< VECTOR2I > GetConnectionPoints() const
Definition: pcb_shape.cpp:248
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:138
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: pcb_track.cpp:1046
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:618
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 OnlyContains(std::vector< KICAD_T > aList) const
Checks if all items in the selection have a type in aList.
Definition: selection.cpp:213
bool Empty() const
Checks if there is anything selected.
Definition: selection.h:110
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:724
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:659
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:666
bool IsTeardropArea() const
Definition: zone.h:699
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: zone.h:133
bool GetDoNotAllowCopperPour() const
Definition: zone.h:731
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:820
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:39
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