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