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