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