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