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