KiCad PCB EDA Suite
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>
30using namespace std::placeholders;
31#include <core/kicad_algo.h>
32#include <board.h>
34#include <board_item.h>
35#include <clipper.hpp>
36#include <pcb_bitmap.h>
37#include <pcb_track.h>
38#include <footprint.h>
39#include <pad.h>
40#include <pcb_group.h>
41#include <pcb_shape.h>
42#include <pcb_text.h>
43#include <pcb_textbox.h>
44#include <fp_textbox.h>
45#include <pcb_marker.h>
46#include <zone.h>
47#include <collectors.h>
51#include <view/view_controls.h>
53#include <painter.h>
54#include <router/router_tool.h>
55#include <pcbnew_settings.h>
56#include <tool/tool_event.h>
57#include <tool/tool_manager.h>
61#include <tools/pcb_actions.h>
66#include <wx/event.h>
67#include <wx/timer.h>
68#include <wx/log.h>
69#include <profile.h>
70
71
73{
74public:
76 ACTION_MENU( true )
77 {
78 SetTitle( _( "Select" ) );
79
81
82 AppendSeparator();
83
86
87 // This could be enabled if we have better logic for picking the target net with the mouse
88 // Add( PCB_ACTIONS::deselectNet );
91
94 }
95
96private:
97 ACTION_MENU* create() const override
98 {
99 return new SELECT_MENU();
100 }
101};
102
103
108{
109public:
111};
112
113
115 SELECTION_TOOL( "pcbnew.InteractiveSelection" ),
116 m_frame( nullptr ),
117 m_isFootprintEditor( false ),
118 m_nonModifiedCursor( KICURSOR::ARROW ),
119 m_enteredGroup( nullptr ),
120 m_priv( std::make_unique<PRIV>() )
121{
122 m_filter.lockedItems = false;
123 m_filter.footprints = true;
124 m_filter.text = true;
125 m_filter.tracks = true;
126 m_filter.vias = true;
127 m_filter.pads = true;
128 m_filter.graphics = true;
129 m_filter.zones = true;
130 m_filter.keepouts = true;
131 m_filter.dimensions = true;
132 m_filter.otherItems = true;
133}
134
135
137{
140
141 Disconnect( wxEVT_TIMER, wxTimerEventHandler( PCB_SELECTION_TOOL::onDisambiguationExpire ), nullptr, this );
142}
143
144
146{
147 PCB_BASE_FRAME* frame = getEditFrame<PCB_BASE_FRAME>();
148
151 {
153 return true;
154 }
155
156 std::shared_ptr<SELECT_MENU> selectMenu = std::make_shared<SELECT_MENU>();
157 selectMenu->SetTool( this );
158 m_menu.RegisterSubMenu( selectMenu );
159
160 auto& menu = m_menu.GetMenu();
161
162 auto activeToolCondition =
163 [ frame ] ( const SELECTION& aSel )
164 {
165 return !frame->ToolStackIsEmpty();
166 };
167
168 auto haveHighlight =
169 [&]( const SELECTION& sel )
170 {
172
173 return !cfg->GetHighlightNetCodes().empty();
174 };
175
176 auto groupEnterCondition =
178
179 auto inGroupCondition =
180 [this] ( const SELECTION& )
181 {
182 return m_enteredGroup != nullptr;
183 };
184
186 {
187 menu.AddMenu( selectMenu.get(), SELECTION_CONDITIONS::NotEmpty );
188 menu.AddSeparator( 1000 );
189 }
190
191 // "Cancel" goes at the top of the context menu when a tool is active
192 menu.AddItem( ACTIONS::cancelInteractive, activeToolCondition, 1 );
193 menu.AddItem( PCB_ACTIONS::groupEnter, groupEnterCondition, 1 );
194 menu.AddItem( PCB_ACTIONS::groupLeave, inGroupCondition, 1 );
195 menu.AddItem( PCB_ACTIONS::clearHighlight, haveHighlight, 1 );
196
197 menu.AddSeparator( 1 );
198
199 if( frame )
201
202 m_disambiguateTimer.SetOwner( this );
203 Connect( wxEVT_TIMER, wxTimerEventHandler( PCB_SELECTION_TOOL::onDisambiguationExpire ), nullptr, this );
204
205 return true;
206}
207
208
210{
211 m_frame = getEditFrame<PCB_BASE_FRAME>();
213
214 if( m_enteredGroup )
215 ExitGroup();
216
217 if( aReason == TOOL_BASE::MODEL_RELOAD )
218 {
219 // Deselect any item being currently in edit, to avoid unexpected behavior
220 // and remove pointers to the selected items from containers
221 // without changing their properties (as they are already deleted
222 // while a new board is loaded)
223 ClearSelection( true );
224
225 getView()->GetPainter()->GetSettings()->SetHighlight( false );
226 }
227 else if ( aReason != TOOL_BASE::REDRAW )
228 {
229 // Restore previous properties of selected items and remove them from containers
230 ClearSelection( true );
231 }
232
233 // Reinsert the VIEW_GROUP, in case it was removed from the VIEW
234 view()->Remove( &m_selection );
235 view()->Add( &m_selection );
236
239}
240
241
242void PCB_SELECTION_TOOL::OnIdle( wxIdleEvent& aEvent )
243{
245 {
246 wxMouseState keyboardState = wxGetMouseState();
247
248 setModifiersState( keyboardState.ShiftDown(), keyboardState.ControlDown(),
249 keyboardState.AltDown() );
250
251 if( m_additive )
253 else if( m_subtractive )
255 else if( m_exclusive_or )
257 else
259 }
260}
261
262
264{
265 // Main loop: keep receiving events
266 while( TOOL_EVENT* evt = Wait() )
267 {
270
271 // on left click, a selection is made, depending on modifiers ALT, SHIFT, CTRL:
272 setModifiersState( evt->Modifier( MD_SHIFT ), evt->Modifier( MD_CTRL ),
273 evt->Modifier( MD_ALT ) );
274
275 PCB_BASE_FRAME* frame = getEditFrame<PCB_BASE_FRAME>();
276 bool brd_editor = frame && frame->IsType( FRAME_PCB_EDITOR );
278
279 // If the router tool is active, don't override
280 if( router && router->IsToolActive() && router->RoutingInProgress() )
281 {
282 evt->SetPassEvent();
283 }
284 else if( evt->IsMouseDown( BUT_LEFT ) )
285 {
286 // Avoid triggering when running under other tools
288
289 if( m_frame->ToolStackIsEmpty() && pt_tool && !pt_tool->HasPoint() )
290 {
292 m_disambiguateTimer.StartOnce( 500 );
293 }
294 }
295 else if( evt->IsClick( BUT_LEFT ) )
296 {
297 // If there is no disambiguation, this routine is still running and will
298 // register a `click` event when released
299 if( m_disambiguateTimer.IsRunning() )
300 {
301 m_disambiguateTimer.Stop();
302
303 // Single click? Select single object
304 if( m_highlight_modifier && brd_editor )
305 {
307 }
308 else
309 {
310 m_frame->FocusOnItem( nullptr );
311 selectPoint( evt->Position() );
312 }
313 }
314
315 m_canceledMenu = false;
316 }
317 else if( evt->IsClick( BUT_RIGHT ) )
318 {
319 m_disambiguateTimer.Stop();
320
321 // Right click? if there is any object - show the context menu
322 bool selectionCancelled = false;
323
324 if( m_selection.Empty() )
325 {
326 selectPoint( evt->Position(), false, &selectionCancelled );
327 m_selection.SetIsHover( true );
328 }
329
330 if( !selectionCancelled )
332 }
333 else if( evt->IsDblClick( BUT_LEFT ) )
334 {
335 m_disambiguateTimer.Stop();
336
337 // Double click? Display the properties window
338 m_frame->FocusOnItem( nullptr );
339
340 if( m_selection.Empty() )
341 selectPoint( evt->Position() );
342
343 if( m_selection.GetSize() == 1 && m_selection[0]->Type() == PCB_GROUP_T )
344 EnterGroup();
345 else
347 }
348 else if( evt->IsDblClick( BUT_MIDDLE ) )
349 {
350 // Middle double click? Do zoom to fit or zoom to objects
351 if( evt->Modifier( MD_CTRL ) ) // Is CTRL key down?
353 else
355 }
356 else if( evt->IsDrag( BUT_LEFT ) )
357 {
358 m_disambiguateTimer.Stop();
359
360 // Is another tool already moving a new object? Don't allow a drag start
361 if( !m_selection.Empty() && m_selection[0]->HasFlag( IS_NEW | IS_MOVING ) )
362 {
363 evt->SetPassEvent();
364 continue;
365 }
366
367 // Drag with LMB? Select multiple objects (or at least draw a selection box)
368 // or drag them
369 m_frame->FocusOnItem( nullptr );
371
372 if( hasModifier() || dragAction == MOUSE_DRAG_ACTION::SELECT )
373 {
375 }
376 else if( m_selection.Empty() && dragAction != MOUSE_DRAG_ACTION::DRAG_ANY )
377 {
379 }
380 else
381 {
382 // Don't allow starting a drag from a zone filled area that isn't already selected
383 auto zoneFilledAreaFilter =
384 []( const VECTOR2I& aWhere, GENERAL_COLLECTOR& aCollector,
385 PCB_SELECTION_TOOL* aTool )
386 {
387 int accuracy = KiROUND( 5 * aCollector.GetGuide()->OnePixelInIU() );
388 std::set<EDA_ITEM*> remove;
389
390 for( EDA_ITEM* item : aCollector )
391 {
392 if( item->Type() == PCB_ZONE_T || item->Type() == PCB_FP_ZONE_T )
393 {
394 ZONE* zone = static_cast<ZONE*>( item );
395
396 if( !zone->HitTestForCorner( aWhere, accuracy * 2 )
397 && !zone->HitTestForEdge( aWhere, accuracy ) )
398 {
399 remove.insert( zone );
400 }
401 }
402 }
403
404 for( EDA_ITEM* item : remove )
405 aCollector.Remove( item );
406 };
407
408 // See if we can drag before falling back to selectMultiple()
409 bool doDrag = false;
410
411 if( evt->HasPosition() )
412 {
413 if( m_selection.Empty()
414 && selectPoint( evt->DragOrigin(), false, nullptr, zoneFilledAreaFilter ) )
415 {
416 m_selection.SetIsHover( true );
417 doDrag = true;
418 }
419 // Check if dragging has started within any of selected items bounding box.
420 else if( selectionContains( evt->DragOrigin() ) )
421 {
422 doDrag = true;
423 }
424 }
425
426 if( doDrag )
427 {
428 bool haveTrack = m_selection.GetSize() == 1
429 && dynamic_cast<PCB_TRACK*>( m_selection.GetItem( 0 ) );
430
431 if( haveTrack && trackDragAction == TRACK_DRAG_ACTION::DRAG )
433 else if( haveTrack && trackDragAction == TRACK_DRAG_ACTION::DRAG_FREE_ANGLE )
435 else
437 }
438 else
439 {
440 // Otherwise drag a selection box
442 }
443 }
444 }
445 else if( evt->IsCancel() )
446 {
447 m_disambiguateTimer.Stop();
448 m_frame->FocusOnItem( nullptr );
449
450 if( !GetSelection().Empty() )
451 {
453 }
454 else if( evt->FirstResponder() == this && evt->GetCommandId() == (int) WXK_ESCAPE )
455 {
456 if( m_enteredGroup )
457 {
458 ExitGroup();
459 }
460 else
461 {
463
465 controller->ClearHighlight( *evt );
466 }
467 }
468 }
469 else
470 {
471 evt->SetPassEvent();
472 }
473
474
476 {
477 // move cursor prediction
478 if( !hasModifier()
479 && dragAction == MOUSE_DRAG_ACTION::DRAG_SELECTED
480 && !m_selection.Empty()
481 && evt->HasPosition()
482 && selectionContains( evt->Position() ) )
483 {
485 }
486 else
487 {
489 }
490 }
491 }
492
493 // Shutting down; clear the selection
495 m_disambiguateTimer.Stop();
496
497 return 0;
498}
499
500
502{
503 wxCHECK_RET( m_selection.GetSize() == 1 && m_selection[0]->Type() == PCB_GROUP_T,
504 wxT( "EnterGroup called when selection is not a single group" ) );
505 PCB_GROUP* aGroup = static_cast<PCB_GROUP*>( m_selection[0] );
506
507 if( m_enteredGroup != nullptr )
508 ExitGroup();
509
511 m_enteredGroup = aGroup;
514 {
515 select( titem );
516 } );
517
519
520 view()->Hide( m_enteredGroup, true );
523}
524
525
526void PCB_SELECTION_TOOL::ExitGroup( bool aSelectGroup )
527{
528 // Only continue if there is a group entered
529 if( m_enteredGroup == nullptr )
530 return;
531
533 view()->Hide( m_enteredGroup, false );
535
536 if( aSelectGroup )
537 {
540 }
541
543 m_enteredGroup = nullptr;
545}
546
547
549{
550 return m_selection;
551}
552
553
555 bool aConfirmLockedItems )
556{
557 bool selectionEmpty = m_selection.Empty();
558 m_selection.SetIsHover( selectionEmpty );
559
560 if( selectionEmpty )
561 {
562 m_toolMgr->RunAction( PCB_ACTIONS::selectionCursor, true, aClientFilter );
564 }
565
566 if( aClientFilter )
567 {
568 enum DISPOSITION { BEFORE = 1, AFTER, BOTH };
569
570 std::map<EDA_ITEM*, DISPOSITION> itemDispositions;
572 GENERAL_COLLECTOR collector;
573
574 collector.SetGuide( &guide );
575
576 for( EDA_ITEM* item : m_selection )
577 {
578 collector.Append( item );
579 itemDispositions[ item ] = BEFORE;
580 }
581
582 aClientFilter( VECTOR2I(), collector, this );
583
584 for( EDA_ITEM* item : collector )
585 {
586 if( itemDispositions.count( item ) )
587 itemDispositions[ item ] = BOTH;
588 else
589 itemDispositions[ item ] = AFTER;
590 }
591
592 // Unhighlight the BEFORE items before highlighting the AFTER items.
593 // This is so that in the case of groups, if aClientFilter replaces a selection
594 // with the enclosing group, the unhighlight of the element doesn't undo the
595 // recursive highlighting of that element by the group.
596
597 for( std::pair<EDA_ITEM* const, DISPOSITION> itemDisposition : itemDispositions )
598 {
599 EDA_ITEM* item = itemDisposition.first;
600 DISPOSITION disposition = itemDisposition.second;
601
602 if( disposition == BEFORE )
604 }
605
606 for( std::pair<EDA_ITEM* const, DISPOSITION> itemDisposition : itemDispositions )
607 {
608 EDA_ITEM* item = itemDisposition.first;
609 DISPOSITION disposition = itemDisposition.second;
610
611 // Note that we must re-highlight even previously-highlighted items
612 // (ie: disposition BOTH) in case we removed any of their children.
613 if( disposition == AFTER || disposition == BOTH )
614 highlight( item, SELECTED, &m_selection );
615 }
616
618 }
619
620 if( aConfirmLockedItems )
621 {
622 std::vector<BOARD_ITEM*> lockedItems;
623
624 for( EDA_ITEM* item : m_selection )
625 {
626 BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( item );
627
628 if( boardItem->Type() == PCB_GROUP_T )
629 {
630 PCB_GROUP* group = static_cast<PCB_GROUP*>( boardItem );
631 bool lockedDescendant = false;
632
633 group->RunOnDescendants(
634 [&lockedDescendant]( BOARD_ITEM* child )
635 {
636 if( child->IsLocked() )
637 lockedDescendant = true;
638 } );
639
640 if( lockedDescendant )
641 lockedItems.push_back( group );
642 }
643 else if( boardItem->IsLocked() )
644 {
645 lockedItems.push_back( boardItem );
646 }
647 }
648
649 if( !lockedItems.empty() )
650 {
651 DIALOG_LOCKED_ITEMS_QUERY dlg( frame(), (int) lockedItems.size() );
652
653 switch( dlg.ShowModal() )
654 {
655 case wxID_OK:
656 // remove locked items from selection
657 for( BOARD_ITEM* item : lockedItems )
658 unselect( item );
659
660 break;
661
662 case wxID_CANCEL:
663 // cancel operation
665 break;
666
667 case wxID_APPLY:
668 // continue with operation with current selection
669 break;
670 }
671 }
672 }
673
674 return m_selection;
675}
676
677
679{
680 GENERAL_COLLECTORS_GUIDE guide( board()->GetVisibleLayers(),
681 (PCB_LAYER_ID) view()->GetTopLayer(), view() );
682
683 bool padsDisabled = !board()->IsElementVisible( LAYER_PADS );
684
685 // account for the globals
686 guide.SetIgnoreMTextsMarkedNoShow( ! board()->IsElementVisible( LAYER_MOD_TEXT_INVISIBLE ) );
687 guide.SetIgnoreMTextsOnBack( ! board()->IsElementVisible( LAYER_MOD_TEXT ) );
688 guide.SetIgnoreMTextsOnFront( ! board()->IsElementVisible( LAYER_MOD_TEXT ) );
689 guide.SetIgnoreModulesOnBack( ! board()->IsElementVisible( LAYER_MOD_BK ) );
690 guide.SetIgnoreModulesOnFront( ! board()->IsElementVisible( LAYER_MOD_FR ) );
691 guide.SetIgnorePadsOnBack( padsDisabled || ! board()->IsElementVisible( LAYER_PAD_BK ) );
692 guide.SetIgnorePadsOnFront( padsDisabled || ! board()->IsElementVisible( LAYER_PAD_FR ) );
693 guide.SetIgnoreThroughHolePads( padsDisabled || ! board()->IsElementVisible( LAYER_PADS_TH ) );
694 guide.SetIgnoreModulesVals( ! board()->IsElementVisible( LAYER_MOD_VALUES ) );
695 guide.SetIgnoreModulesRefs( ! board()->IsElementVisible( LAYER_MOD_REFERENCES ) );
696 guide.SetIgnoreThroughVias( ! board()->IsElementVisible( LAYER_VIAS ) );
697 guide.SetIgnoreBlindBuriedVias( ! board()->IsElementVisible( LAYER_VIAS ) );
698 guide.SetIgnoreMicroVias( ! board()->IsElementVisible( LAYER_VIAS ) );
699 guide.SetIgnoreTracks( ! board()->IsElementVisible( LAYER_TRACKS ) );
700
701 return guide;
702}
703
704
706{
708}
709
710
711bool PCB_SELECTION_TOOL::selectPoint( const VECTOR2I& aWhere, bool aOnDrag,
712 bool* aSelectionCancelledFlag,
713 CLIENT_SELECTION_FILTER aClientFilter )
714{
716 GENERAL_COLLECTOR collector;
717 const PCB_DISPLAY_OPTIONS& displayOpts = m_frame->GetDisplayOptions();
718
720
722 ExitGroup();
723
726 aWhere, guide );
727
728 // Remove unselectable items
729 for( int i = collector.GetCount() - 1; i >= 0; --i )
730 {
731 if( !Selectable( collector[ i ] ) || ( aOnDrag && collector[i]->IsLocked() ) )
732 collector.Remove( i );
733 }
734
736
737 // Allow the client to do tool- or action-specific filtering to see if we can get down
738 // to a single item
739 if( aClientFilter )
740 aClientFilter( aWhere, collector, this );
741
742 FilterCollectorForHierarchy( collector, false );
743
744 // Apply the stateful filter
745 FilterCollectedItems( collector, false );
746
747 // For subtracting, we only want items that are selected
748 if( m_subtractive )
749 {
750 for( int i = collector.GetCount() - 1; i >= 0; --i )
751 {
752 if( !collector[i]->IsSelected() )
753 collector.Remove( i );
754 }
755 }
756
757 // Apply some ugly heuristics to avoid disambiguation menus whenever possible
758 if( collector.GetCount() > 1 && !m_skip_heuristics )
759 GuessSelectionCandidates( collector, aWhere );
760
761 // If still more than one item we're going to have to ask the user.
762 if( collector.GetCount() > 1 )
763 {
764 if( aOnDrag )
766
767 if( !doSelectionMenu( &collector ) )
768 {
769 if( aSelectionCancelledFlag )
770 *aSelectionCancelledFlag = true;
771
772 return false;
773 }
774 }
775
776 int addedCount = 0;
777 bool anySubtracted = false;
778
780 {
781 if( m_selection.GetSize() > 0 )
782 {
783 ClearSelection( true /*quiet mode*/ );
784 anySubtracted = true;
785 }
786 }
787
788 if( collector.GetCount() > 0 )
789 {
790 for( int i = 0; i < collector.GetCount(); ++i )
791 {
792 if( m_subtractive || ( m_exclusive_or && collector[i]->IsSelected() ) )
793 {
794 unselect( collector[i] );
795 anySubtracted = true;
796 }
797 else
798 {
799 select( collector[i] );
800 addedCount++;
801 }
802 }
803 }
804
805 if( addedCount == 1 )
806 {
808 return true;
809 }
810 else if( addedCount > 1 )
811 {
813 return true;
814 }
815 else if( anySubtracted )
816 {
818 return true;
819 }
820
821 return false;
822}
823
824
825bool PCB_SELECTION_TOOL::selectCursor( bool aForceSelect, CLIENT_SELECTION_FILTER aClientFilter )
826{
827 if( aForceSelect || m_selection.Empty() )
828 {
829 ClearSelection( true /*quiet mode*/ );
830 selectPoint( getViewControls()->GetCursorPosition( false ), false, nullptr, aClientFilter );
831 }
832
833 return !m_selection.Empty();
834}
835
836
837// Some navigation actions are allowed in selectMultiple
847 &ACTIONS::zoomFitObjects, nullptr };
848
849
851{
852 bool cancelled = false; // Was the tool cancelled while it was running?
853 m_multiple = true; // Multiple selection mode is active
855
857 view->Add( &area );
858
859 bool anyAdded = false;
860 bool anySubtracted = false;
861
862 while( TOOL_EVENT* evt = Wait() )
863 {
864 int width = area.GetEnd().x - area.GetOrigin().x;
865
866 /* Selection mode depends on direction of drag-selection:
867 * Left > Right : Select objects that are fully enclosed by selection
868 * Right > Left : Select objects that are crossed by selection
869 */
870 bool greedySelection = width >= 0 ? false : true;
871
872 if( view->IsMirroredX() )
873 greedySelection = !greedySelection;
874
877
878 if( evt->IsCancelInteractive() || evt->IsActivate() )
879 {
880 cancelled = true;
881 break;
882 }
883
884 if( evt->IsDrag( BUT_LEFT ) )
885 {
887 {
888 if( m_selection.GetSize() > 0 )
889 {
890 anySubtracted = true;
891 ClearSelection( true /*quiet mode*/ );
892 }
893 }
894
895 // Start drawing a selection box
896 area.SetOrigin( evt->DragOrigin() );
897 area.SetEnd( evt->Position() );
900 area.SetExclusiveOr( false );
901
902 view->SetVisible( &area, true );
903 view->Update( &area );
904 getViewControls()->SetAutoPan( true );
905 }
906
907 if( evt->IsMouseUp( BUT_LEFT ) )
908 {
909 getViewControls()->SetAutoPan( false );
910
911 // End drawing the selection box
912 view->SetVisible( &area, false );
913
914 std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> candidates;
915 BOX2I selectionBox = area.ViewBBox();
916 view->Query( selectionBox, candidates ); // Get the list of nearby items
917
918 int height = area.GetEnd().y - area.GetOrigin().y;
919
920 // Construct a BOX2I to determine BOARD_ITEM selection
921 BOX2I selectionRect( area.GetOrigin(), VECTOR2I( width, height ) );
922
923 selectionRect.Normalize();
924
925 GENERAL_COLLECTOR collector;
926 GENERAL_COLLECTOR padsCollector;
927 std::set<BOARD_ITEM*> group_items;
928
929 for( PCB_GROUP* group : board()->Groups() )
930 {
931 // The currently entered group does not get limited
932 if( m_enteredGroup == group )
933 continue;
934
935 std::unordered_set<BOARD_ITEM*>& newset = group->GetItems();
936
937 // If we are not greedy and have selected the whole group, add just one item
938 // to allow it to be promoted to the group later
939 if( !greedySelection && selectionRect.Contains( group->GetBoundingBox() )
940 && newset.size() )
941 {
942 for( BOARD_ITEM* group_item : newset )
943 {
944 if( Selectable( group_item ) )
945 collector.Append( *newset.begin() );
946 }
947 }
948
949 for( BOARD_ITEM* group_item : newset )
950 group_items.emplace( group_item );
951 }
952
953 for( const KIGFX::VIEW::LAYER_ITEM_PAIR& candidate : candidates )
954 {
955 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( candidate.first );
956
957 if( item && Selectable( item ) && item->HitTest( selectionRect, !greedySelection )
958 && ( greedySelection || !group_items.count( item ) ) )
959 {
960 if( item->Type() == PCB_PAD_T && !m_isFootprintEditor )
961 padsCollector.Append( item );
962 else
963 collector.Append( item );
964 }
965 }
966
967 // Apply the stateful filter
968 FilterCollectedItems( collector, true );
969
970 FilterCollectorForHierarchy( collector, true );
971
972 // If we selected nothing but pads, allow them to be selected
973 if( collector.GetCount() == 0 )
974 {
975 collector = padsCollector;
976 FilterCollectedItems( collector, true );
977 FilterCollectorForHierarchy( collector, true );
978 }
979
980 for( EDA_ITEM* i : collector )
981 {
982 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( i );
983
984 if( m_subtractive || ( m_exclusive_or && item->IsSelected() ) )
985 {
986 unselect( item );
987 anySubtracted = true;
988 }
989 else
990 {
991 select( item );
992 anyAdded = true;
993 }
994 }
995
996 m_selection.SetIsHover( false );
997
998 // Inform other potentially interested tools
999 if( anyAdded )
1001 else if( anySubtracted )
1003
1004 break; // Stop waiting for events
1005 }
1006
1007 // Allow some actions for navigation
1008 for( int i = 0; allowedActions[i]; ++i )
1009 {
1010 if( evt->IsAction( allowedActions[i] ) )
1011 {
1012 evt->SetPassEvent();
1013 break;
1014 }
1015 }
1016 }
1017
1018 getViewControls()->SetAutoPan( false );
1019
1020 // Stop drawing the selection box
1021 view->Remove( &area );
1022 m_multiple = false; // Multiple selection mode is inactive
1023
1024 if( !cancelled )
1026
1028
1029 return cancelled;
1030}
1031
1032
1034{
1035 wxMouseState keyboardState = wxGetMouseState();
1036
1037 setModifiersState( keyboardState.ShiftDown(), keyboardState.ControlDown(),
1038 keyboardState.AltDown() );
1039
1040 m_skip_heuristics = true;
1042 m_skip_heuristics = false;
1043
1044 return 0;
1045}
1046
1047
1048
1050{
1052
1053 selectCursor( false, aClientFilter );
1054
1055 return 0;
1056}
1057
1058
1060{
1062
1063 return 0;
1064}
1065
1066
1068{
1070
1071 // hold all visible items
1072 std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> selectedItems;
1073
1074 // Filter the view items based on the selection box
1075 BOX2I selectionBox;
1076
1077 // Intermediate step to allow filtering against hierarchy
1078 GENERAL_COLLECTOR collection;
1079
1080 selectionBox.SetMaximum();
1081 view->Query( selectionBox, selectedItems ); // Get the list of selected items
1082
1083 for( const KIGFX::VIEW::LAYER_ITEM_PAIR& item_pair : selectedItems )
1084 {
1085 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( item_pair.first );
1086
1087 if( !item || !Selectable( item ) || !itemPassesFilter( item, true ) )
1088 continue;
1089
1090 collection.Append( item );
1091 }
1092
1093 FilterCollectorForHierarchy( collection, true );
1094
1095 for( EDA_ITEM* item : collection )
1096 select( item );
1097
1099
1101
1102 return 0;
1103}
1104
1105
1107 PCB_SELECTION_TOOL* sTool )
1108{
1109 // Narrow the collection down to a single BOARD_CONNECTED_ITEM for each represented net.
1110 // All other items types are removed.
1111 std::set<int> representedNets;
1112
1113 for( int i = aCollector.GetCount() - 1; i >= 0; i-- )
1114 {
1115 BOARD_CONNECTED_ITEM* item = dynamic_cast<BOARD_CONNECTED_ITEM*>( aCollector[i] );
1116
1117 if( !item )
1118 aCollector.Remove( i );
1119 else if ( representedNets.count( item->GetNetCode() ) )
1120 aCollector.Remove( i );
1121 else
1122 representedNets.insert( item->GetNetCode() );
1123 }
1124}
1125
1126
1128{
1129 std::deque<EDA_ITEM*> selectedItems = m_selection.GetItems();
1130
1131 // Get all footprints and pads
1132 std::vector<BOARD_CONNECTED_ITEM*> toUnroute;
1133
1134 for( EDA_ITEM* item : selectedItems )
1135 {
1136 if( item->Type() == PCB_FOOTPRINT_T )
1137 {
1138 for( PAD* pad : static_cast<FOOTPRINT*>( item )->Pads() )
1139 toUnroute.push_back( pad );
1140 }
1141 else if( BOARD_CONNECTED_ITEM::ClassOf( item ) )
1142 {
1143 toUnroute.push_back( static_cast<BOARD_CONNECTED_ITEM*>( item ) );
1144 }
1145 }
1146
1147 // Clear selection so we don't delete our footprints/pads
1148 ClearSelection( true );
1149
1150 // Get the tracks on our list of pads, then delete them
1151 selectAllConnectedTracks( toUnroute, STOP_CONDITION::STOP_AT_PAD );
1153
1154 // Reselect our footprint/pads as they were in our original selection
1155 for( EDA_ITEM* item : selectedItems )
1156 {
1157 if( item->Type() == PCB_FOOTPRINT_T || item->Type() == PCB_PAD_T )
1158 select( item );
1159 }
1160
1161 return 0;
1162}
1163
1164
1166{
1167 unsigned initialCount = 0;
1168
1169 for( const EDA_ITEM* item : m_selection.GetItems() )
1170 {
1171 if( item->Type() == PCB_FOOTPRINT_T || BOARD_CONNECTED_ITEM::ClassOf( item ) )
1172 initialCount++;
1173 }
1174
1175 if( initialCount == 0 )
1177
1178 m_frame->SetStatusText( _( "Select/Expand Connection..." ) );
1179
1180 for( STOP_CONDITION stopCondition : { STOP_AT_JUNCTION, STOP_AT_PAD, STOP_NEVER } )
1181 {
1182 std::deque<EDA_ITEM*> selectedItems = m_selection.GetItems();
1183
1184 for( EDA_ITEM* item : selectedItems )
1185 item->ClearTempFlags();
1186
1187 std::vector<BOARD_CONNECTED_ITEM*> startItems;
1188
1189 for( EDA_ITEM* item : selectedItems )
1190 {
1191 if( item->Type() == PCB_FOOTPRINT_T )
1192 {
1193 FOOTPRINT* footprint = static_cast<FOOTPRINT*>( item );
1194
1195 for( PAD* pad : footprint->Pads() )
1196 startItems.push_back( pad );
1197 }
1198 else if( BOARD_CONNECTED_ITEM::ClassOf( item ) )
1199 {
1200 startItems.push_back( static_cast<BOARD_CONNECTED_ITEM*>( item ) );
1201 }
1202 }
1203
1204 selectAllConnectedTracks( startItems, stopCondition );
1205
1206 if( m_selection.GetItems().size() > initialCount )
1207 break;
1208 }
1209
1210 m_frame->SetStatusText( wxEmptyString );
1211
1212 // Inform other potentially interested tools
1214
1215 return 0;
1216}
1217
1218
1220 const std::vector<BOARD_CONNECTED_ITEM*>& aStartItems, STOP_CONDITION aStopCondition )
1221{
1222 const LSET allCuMask = LSET::AllCuMask();
1223
1224 PROF_TIMER refreshTimer;
1225 double refreshIntervalMs = 500; // Refresh display with this interval to indicate progress
1226 int lastSelectionSize = (int) m_selection.GetSize();
1227
1228 auto connectivity = board()->GetConnectivity();
1229
1230 std::map<VECTOR2I, std::vector<PCB_TRACK*>> trackMap;
1231 std::map<VECTOR2I, PCB_VIA*> viaMap;
1232 std::map<VECTOR2I, PAD*> padMap;
1233 std::set<PAD*> startPadSet;
1234 std::vector<BOARD_CONNECTED_ITEM*> cleanupItems;
1235 std::vector<std::pair<VECTOR2I, LSET>> activePts;
1236
1237 for( BOARD_CONNECTED_ITEM* startItem : aStartItems )
1238 {
1239 // Track starting pads
1240 if( startItem->Type() == PCB_PAD_T )
1241 startPadSet.insert( static_cast<PAD*>( startItem ) );
1242 }
1243
1244 for( BOARD_CONNECTED_ITEM* startItem : aStartItems )
1245 {
1246 if( startItem->HasFlag( SKIP_STRUCT ) ) // Skip already visited items
1247 continue;
1248
1249 auto connectedItems = connectivity->GetConnectedItems( startItem,
1251
1252 // Build maps of connected items
1253 for( BOARD_CONNECTED_ITEM* item : connectedItems )
1254 {
1255 switch( item->Type() )
1256 {
1257 case PCB_ARC_T:
1258 case PCB_TRACE_T:
1259 {
1260 PCB_TRACK* track = static_cast<PCB_TRACK*>( item );
1261 trackMap[track->GetStart()].push_back( track );
1262 trackMap[track->GetEnd()].push_back( track );
1263 break;
1264 }
1265
1266 case PCB_VIA_T:
1267 {
1268 PCB_VIA* via = static_cast<PCB_VIA*>( item );
1269 viaMap[via->GetStart()] = via;
1270 break;
1271 }
1272
1273 case PCB_PAD_T:
1274 {
1275 PAD* pad = static_cast<PAD*>( item );
1276 padMap[pad->GetPosition()] = pad;
1277 break;
1278 }
1279
1280 default:
1281 break;
1282 }
1283 }
1284
1285 // Set up the initial active points
1286 switch( startItem->Type() )
1287 {
1288 case PCB_ARC_T:
1289 case PCB_TRACE_T:
1290 {
1291 PCB_TRACK* track = static_cast<PCB_TRACK*>( startItem );
1292
1293 activePts.push_back( { track->GetStart(), track->GetLayerSet() } );
1294 activePts.push_back( { track->GetEnd(), track->GetLayerSet() } );
1295 break;
1296 }
1297
1298 case PCB_VIA_T:
1299 activePts.push_back( { startItem->GetPosition(), startItem->GetLayerSet() } );
1300 break;
1301
1302 case PCB_PAD_T:
1303 activePts.push_back( { startItem->GetPosition(), startItem->GetLayerSet() } );
1304 break;
1305
1306 default:
1307 break;
1308 }
1309
1310 bool expand = true;
1311 int failSafe = 0;
1312
1313 // Iterative push from all active points
1314 while( expand && failSafe++ < 100000 )
1315 {
1316 expand = false;
1317
1318 for( int i = (int) activePts.size() - 1; i >= 0; --i )
1319 {
1320 VECTOR2I pt = activePts[i].first;
1321 LSET layerSetCu = activePts[i].second & allCuMask;
1322
1323 auto viaIt = viaMap.find( pt );
1324 auto padIt = padMap.find( pt );
1325
1326 bool gotVia = ( viaIt != viaMap.end() )
1327 && ( layerSetCu & ( viaIt->second->GetLayerSet() ) ).any();
1328
1329 bool gotPad = ( padIt != padMap.end() )
1330 && ( layerSetCu & ( padIt->second->GetLayerSet() ) ).any();
1331
1332 bool gotNonStartPad =
1333 gotPad && ( startPadSet.find( padIt->second ) == startPadSet.end() );
1334
1335 if( aStopCondition == STOP_AT_JUNCTION )
1336 {
1337 size_t pt_count = 0;
1338
1339 for( PCB_TRACK* track : trackMap[pt] )
1340 {
1341 if( track->GetStart() != track->GetEnd()
1342 && layerSetCu.Contains( track->GetLayer() ) )
1343 {
1344 pt_count++;
1345 }
1346 }
1347
1348 if( pt_count > 2 || gotVia || gotNonStartPad )
1349 {
1350 activePts.erase( activePts.begin() + i );
1351 continue;
1352 }
1353 }
1354 else if( aStopCondition == STOP_AT_PAD )
1355 {
1356 if( gotNonStartPad )
1357 {
1358 activePts.erase( activePts.begin() + i );
1359 continue;
1360 }
1361 }
1362
1363 if( gotPad )
1364 {
1365 PAD* pad = padIt->second;
1366
1367 if( !pad->HasFlag( SKIP_STRUCT ) )
1368 {
1369 pad->SetFlags( SKIP_STRUCT );
1370 cleanupItems.push_back( pad );
1371
1372 activePts.push_back( { pad->GetPosition(), pad->GetLayerSet() } );
1373 expand = true;
1374 }
1375 }
1376
1377 for( PCB_TRACK* track : trackMap[pt] )
1378 {
1379 if( !layerSetCu.Contains( track->GetLayer() ) )
1380 continue;
1381
1382 if( !track->IsSelected() )
1383 select( track );
1384
1385 if( !track->HasFlag( SKIP_STRUCT ) )
1386 {
1387 track->SetFlags( SKIP_STRUCT );
1388 cleanupItems.push_back( track );
1389
1390 if( track->GetStart() == pt )
1391 activePts.push_back( { track->GetEnd(), track->GetLayerSet() } );
1392 else
1393 activePts.push_back( { track->GetStart(), track->GetLayerSet() } );
1394
1395 expand = true;
1396 }
1397 }
1398
1399 if( viaMap.count( pt ) )
1400 {
1401 PCB_VIA* via = viaMap[pt];
1402
1403 if( !via->IsSelected() )
1404 select( via );
1405
1406 if( !via->HasFlag( SKIP_STRUCT ) )
1407 {
1408 via->SetFlags( SKIP_STRUCT );
1409 cleanupItems.push_back( via );
1410
1411 activePts.push_back( { via->GetPosition(), via->GetLayerSet() } );
1412 expand = true;
1413 }
1414 }
1415
1416 activePts.erase( activePts.begin() + i );
1417 }
1418
1419 // Refresh display for the feel of progress
1420 if( refreshTimer.msecs() >= refreshIntervalMs )
1421 {
1422 if( m_selection.Size() != lastSelectionSize )
1423 {
1425 lastSelectionSize = m_selection.Size();
1426 }
1427
1428 refreshTimer.Start();
1429 }
1430 }
1431 }
1432
1433 for( BOARD_CONNECTED_ITEM* item : cleanupItems )
1434 item->ClearFlags( SKIP_STRUCT );
1435}
1436
1437
1439{
1440 // Get all pads
1441 std::vector<PAD*> pads;
1442
1443 for( EDA_ITEM* item : m_selection.GetItems() )
1444 {
1445 if( item->Type() == PCB_FOOTPRINT_T )
1446 {
1447 for( PAD* pad : static_cast<FOOTPRINT*>( item )->Pads() )
1448 pads.push_back( pad );
1449 }
1450 else if( item->Type() == PCB_PAD_T )
1451 {
1452 pads.push_back( static_cast<PAD*>( item ) );
1453 }
1454 }
1455
1456 // Select every footprint on the end of the ratsnest for each pad in our selection
1457 std::shared_ptr<CONNECTIVITY_DATA> conn = board()->GetConnectivity();
1458
1459 for( PAD* pad : pads )
1460 {
1461 for( const CN_EDGE& edge : conn->GetRatsnestForPad( pad ) )
1462 {
1463 BOARD_CONNECTED_ITEM* sourceParent = edge.GetSourceNode()->Parent();
1464 BOARD_CONNECTED_ITEM* targetParent = edge.GetTargetNode()->Parent();
1465
1466 if( sourceParent == pad )
1467 {
1468 if( targetParent->Type() == PCB_PAD_T )
1469 select( static_cast<PAD*>( targetParent )->GetParent() );
1470 }
1471 else if( targetParent == pad )
1472 {
1473 if( sourceParent->Type() == PCB_PAD_T )
1474 select( static_cast<PAD*>( sourceParent )->GetParent() );
1475 }
1476 }
1477 }
1478
1479 return 0;
1480}
1481
1482
1484{
1485 PCB_SELECTION originalSelection = m_selection;
1486
1487 // Get all pads
1488 std::vector<PAD*> pads;
1489
1490 for( EDA_ITEM* item : m_selection.GetItems() )
1491 {
1492 if( item->Type() == PCB_FOOTPRINT_T )
1493 {
1494 for( PAD* pad : static_cast<FOOTPRINT*>( item )->Pads() )
1495 pads.push_back( pad );
1496 }
1497 else if( item->Type() == PCB_PAD_T )
1498 {
1499 pads.push_back( static_cast<PAD*>( item ) );
1500 }
1501 }
1502
1504
1505 // Select every footprint on the end of the ratsnest for each pad in our selection
1506 std::shared_ptr<CONNECTIVITY_DATA> conn = board()->GetConnectivity();
1507
1508 for( PAD* pad : pads )
1509 {
1510 const std::vector<CN_EDGE> edges = conn->GetRatsnestForPad( pad );
1511
1512 // Need to have something unconnected to grab
1513 if( edges.size() == 0 )
1514 continue;
1515
1516 double currentDistance = DBL_MAX;
1517 FOOTPRINT* nearest = nullptr;
1518
1519 // Check every ratsnest line for the nearest one
1520 for( const CN_EDGE& edge : edges )
1521 {
1522 // Figure out if we are the source or the target node on the ratnest
1523 const CN_ANCHOR* other = edge.GetSourceNode()->Parent() == pad ? edge.GetTargetNode().get()
1524 : edge.GetSourceNode().get();
1525
1526 // We only want to grab footprints, so the ratnest has to point to a pad
1527 if( other->Parent()->Type() != PCB_PAD_T )
1528 continue;
1529
1530 if( edge.GetLength() < currentDistance )
1531 {
1532 currentDistance = edge.GetLength();
1533 nearest = static_cast<PAD*>( other->Parent() )->GetParent();
1534 }
1535 }
1536
1537 if( nearest != nullptr )
1538 select( nearest );
1539 }
1540
1542
1543 return 0;
1544}
1545
1546
1547void PCB_SELECTION_TOOL::SelectAllItemsOnNet( int aNetCode, bool aSelect )
1548{
1549 std::shared_ptr<CONNECTIVITY_DATA> conn = board()->GetConnectivity();
1550
1551 for( BOARD_ITEM* item : conn->GetNetItems( aNetCode, { PCB_TRACE_T, PCB_ARC_T, PCB_VIA_T } ) )
1552 {
1553 if( itemPassesFilter( item, true ) )
1554 aSelect ? select( item ) : unselect( item );
1555 }
1556}
1557
1558
1560{
1561 bool select = aEvent.IsAction( &PCB_ACTIONS::selectNet );
1562
1563 // If we've been passed an argument, just select that netcode1
1564 int netcode = (int) aEvent.Parameter<intptr_t>();
1565
1566 if( netcode > 0 )
1567 {
1568 SelectAllItemsOnNet( netcode, select );
1569
1570 // Inform other potentially interested tools
1571 if( m_selection.Size() > 0 )
1573 else
1575
1576 return 0;
1577 }
1578
1579 if( !selectCursor() )
1580 return 0;
1581
1582 // copy the selection, since we're going to iterate and modify
1584
1585 for( EDA_ITEM* i : selection )
1586 {
1587 BOARD_CONNECTED_ITEM* connItem = dynamic_cast<BOARD_CONNECTED_ITEM*>( i );
1588
1589 if( connItem )
1590 SelectAllItemsOnNet( connItem->GetNetCode(), select );
1591 }
1592
1593 // Inform other potentially interested tools
1594 if( m_selection.Size() > 0 )
1596 else
1598
1599 return 0;
1600}
1601
1602
1604{
1605 std::vector<BOARD_ITEM*> footprints;
1606
1607 // store all footprints that are on that sheet path
1608 for( FOOTPRINT* footprint : board()->Footprints() )
1609 {
1610 if( footprint == nullptr )
1611 continue;
1612
1613 wxString footprint_path = footprint->GetPath().AsString().BeforeLast( '/' );
1614
1615 if( footprint_path.IsEmpty() )
1616 footprint_path += '/';
1617
1618 if( footprint_path == aSheetPath )
1619 footprints.push_back( footprint );
1620 }
1621
1622 for( BOARD_ITEM* i : footprints )
1623 {
1624 if( i != nullptr )
1625 select( i );
1626 }
1627
1628 selectConnections( footprints );
1629}
1630
1631
1632void PCB_SELECTION_TOOL::selectConnections( const std::vector<BOARD_ITEM*>& aItems )
1633{
1634 // Generate a list of all pads, and of all nets they belong to.
1635 std::list<int> netcodeList;
1636 std::vector<BOARD_CONNECTED_ITEM*> padList;
1637
1638 for( BOARD_ITEM* item : aItems )
1639 {
1640 switch( item->Type() )
1641 {
1642 case PCB_FOOTPRINT_T:
1643 {
1644 for( PAD* pad : static_cast<FOOTPRINT*>( item )->Pads() )
1645 {
1646 if( pad->IsConnected() )
1647 {
1648 netcodeList.push_back( pad->GetNetCode() );
1649 padList.push_back( pad );
1650 }
1651 }
1652
1653 break;
1654 }
1655
1656 case PCB_PAD_T:
1657 {
1658 PAD* pad = static_cast<PAD*>( item );
1659
1660 if( pad->IsConnected() )
1661 {
1662 netcodeList.push_back( pad->GetNetCode() );
1663 padList.push_back( pad );
1664 }
1665
1666 break;
1667 }
1668
1669 default:
1670 break;
1671 }
1672 }
1673
1674 // Sort for binary search
1675 std::sort( padList.begin(), padList.end() );
1676
1677 // remove all duplicates
1678 netcodeList.sort();
1679 netcodeList.unique();
1680
1682
1683 // now we need to find all footprints that are connected to each of these nets then we need
1684 // to determine if these footprints are in the list of footprints
1685 std::vector<int> removeCodeList;
1686 std::shared_ptr<CONNECTIVITY_DATA> conn = board()->GetConnectivity();
1687
1688 for( int netCode : netcodeList )
1689 {
1690 for( BOARD_CONNECTED_ITEM* pad : conn->GetNetItems( netCode, { PCB_PAD_T } ) )
1691 {
1692 if( !std::binary_search( padList.begin(), padList.end(), pad ) )
1693 {
1694 // if we cannot find the pad in the padList then we can assume that that pad
1695 // should not be used, therefore invalidate this netcode.
1696 removeCodeList.push_back( netCode );
1697 break;
1698 }
1699 }
1700 }
1701
1702 for( int removeCode : removeCodeList )
1703 netcodeList.remove( removeCode );
1704
1705 std::unordered_set<BOARD_ITEM*> localConnectionList;
1706
1707 for( int netCode : netcodeList )
1708 {
1709 for( BOARD_ITEM* item : conn->GetNetItems( netCode, { PCB_TRACE_T, PCB_ARC_T, PCB_VIA_T } ) )
1710 localConnectionList.insert( item );
1711 }
1712
1713 for( BOARD_ITEM* item : localConnectionList )
1714 select( item );
1715}
1716
1717
1719{
1720 std::vector<BOARD_ITEM*>* items = aEvent.Parameter<std::vector<BOARD_ITEM*>*>();
1721
1722 if( items )
1723 doSyncSelection( *items, false );
1724
1725 return 0;
1726}
1727
1728
1730{
1731 std::vector<BOARD_ITEM*>* items = aEvent.Parameter<std::vector<BOARD_ITEM*>*>();
1732
1733 if( items )
1734 doSyncSelection( *items, true );
1735
1736 return 0;
1737}
1738
1739
1740void PCB_SELECTION_TOOL::doSyncSelection( const std::vector<BOARD_ITEM*>& aItems, bool aWithNets )
1741{
1742 ClearSelection( true /*quiet mode*/ );
1743
1744 // Perform individual selection of each item before processing the event.
1745 for( BOARD_ITEM* item : aItems )
1746 select( item );
1747
1748 if( aWithNets )
1749 selectConnections( aItems );
1750
1752
1753 if( bbox.GetWidth() != 0 && bbox.GetHeight() != 0 )
1754 {
1756 {
1758 ZoomFitCrossProbeBBox( bbox );
1759
1760 m_frame->FocusOnLocation( bbox.Centre() );
1761 }
1762 }
1763
1765
1767
1768 if( m_selection.Size() > 0 )
1770}
1771
1772
1774{
1775 ClearSelection( true /*quiet mode*/ );
1776 wxString sheetPath = *aEvent.Parameter<wxString*>();
1777
1778 selectAllItemsOnSheet( sheetPath );
1779
1781
1782 if( m_selection.Size() > 0 )
1784
1785 return 0;
1786}
1787
1788
1790{
1791 // this function currently only supports footprints since they are only on one sheet.
1792 EDA_ITEM* item = m_selection.Front();
1793
1794 if( !item )
1795 return 0;
1796
1797 if( item->Type() != PCB_FOOTPRINT_T )
1798 return 0;
1799
1800 FOOTPRINT* footprint = dynamic_cast<FOOTPRINT*>( item );
1801
1802 if( !footprint || footprint->GetPath().empty() )
1803 return 0;
1804
1805 ClearSelection( true /*quiet mode*/ );
1806
1807 // get the sheet path only.
1808 wxString sheetPath = footprint->GetPath().AsString().BeforeLast( '/' );
1809
1810 if( sheetPath.IsEmpty() )
1811 sheetPath += '/';
1812
1813 selectAllItemsOnSheet( sheetPath );
1814
1815 // Inform other potentially interested tools
1816 if( m_selection.Size() > 0 )
1818
1819 return 0;
1820}
1821
1822
1824{
1825 // Should recalculate the view to zoom in on the selection.
1826 BOX2I selectionBox = m_selection.GetBoundingBox();
1828
1829 VECTOR2D screenSize = view->ToWorld( m_frame->GetCanvas()->GetClientSize(), false );
1830 screenSize.x = std::max( 10.0, screenSize.x );
1831 screenSize.y = std::max( 10.0, screenSize.y );
1832
1833 if( selectionBox.GetWidth() != 0 || selectionBox.GetHeight() != 0 )
1834 {
1835 VECTOR2D vsize = selectionBox.GetSize();
1836 double scale = view->GetScale()
1837 / std::max( fabs( vsize.x / screenSize.x ), fabs( vsize.y / screenSize.y ) );
1838 view->SetScale( scale );
1839 view->SetCenter( selectionBox.Centre() );
1840 view->Add( &m_selection );
1841 }
1842
1844}
1845
1846
1848{
1849 // Should recalculate the view to zoom in on the bbox.
1851
1852 if( aBBox.GetWidth() == 0 )
1853 return;
1854
1855 BOX2I bbox = aBBox;
1856 bbox.Normalize();
1857
1858 //#define DEFAULT_PCBNEW_CODE // Un-comment for normal full zoom KiCad algorithm
1859#ifdef DEFAULT_PCBNEW_CODE
1860 auto bbSize = bbox.Inflate( bbox.GetWidth() * 0.2f ).GetSize();
1861 auto screenSize = view->ToWorld( GetCanvas()->GetClientSize(), false );
1862
1863 // The "fabs" on x ensures the right answer when the view is flipped
1864 screenSize.x = std::max( 10.0, fabs( screenSize.x ) );
1865 screenSize.y = std::max( 10.0, screenSize.y );
1866 double ratio = std::max( fabs( bbSize.x / screenSize.x ), fabs( bbSize.y / screenSize.y ) );
1867
1868 // Try not to zoom on every cross-probe; it gets very noisy
1869 if( crossProbingSettings.zoom_to_fit && ( ratio < 0.5 || ratio > 1.0 ) )
1870 view->SetScale( view->GetScale() / ratio );
1871#endif // DEFAULT_PCBNEW_CODE
1872
1873#ifndef DEFAULT_PCBNEW_CODE // Do the scaled zoom
1874 auto bbSize = bbox.Inflate( KiROUND( bbox.GetWidth() * 0.2 ) ).GetSize();
1875 auto screenSize = view->ToWorld( m_frame->GetCanvas()->GetClientSize(), false );
1876
1877 // This code tries to come up with a zoom factor that doesn't simply zoom in
1878 // to the cross probed component, but instead shows a reasonable amount of the
1879 // circuit around it to provide context. This reduces or eliminates the need
1880 // to manually change the zoom because it's too close.
1881
1882 // Using the default text height as a constant to compare against, use the
1883 // height of the bounding box of visible items for a footprint to figure out
1884 // if this is a big footprint (like a processor) or a small footprint (like a resistor).
1885 // This ratio is not useful by itself as a scaling factor. It must be "bent" to
1886 // provide good scaling at varying component sizes. Bigger components need less
1887 // scaling than small ones.
1888 double currTextHeight = pcbIUScale.mmToIU( DEFAULT_TEXT_SIZE );
1889
1890 double compRatio = bbSize.y / currTextHeight; // Ratio of component to text height
1891
1892 // This will end up as the scaling factor we apply to "ratio".
1893 double compRatioBent = 1.0;
1894
1895 // This is similar to the original KiCad code that scaled the zoom to make sure
1896 // components were visible on screen. It's simply a ratio of screen size to
1897 // component size, and its job is to zoom in to make the component fullscreen.
1898 // Earlier in the code the component BBox is given a 20% margin to add some
1899 // breathing room. We compare the height of this enlarged component bbox to the
1900 // default text height. If a component will end up with the sides clipped, we
1901 // adjust later to make sure it fits on screen.
1902 //
1903 // The "fabs" on x ensures the right answer when the view is flipped
1904 screenSize.x = std::max( 10.0, fabs( screenSize.x ) );
1905 screenSize.y = std::max( 10.0, screenSize.y );
1906 double ratio = std::max( -1.0, fabs( bbSize.y / screenSize.y ) );
1907
1908 // Original KiCad code for how much to scale the zoom
1909 double kicadRatio =
1910 std::max( fabs( bbSize.x / screenSize.x ), fabs( bbSize.y / screenSize.y ) );
1911
1912 // LUT to scale zoom ratio to provide reasonable schematic context. Must work
1913 // with footprints of varying sizes (e.g. 0402 package and 200 pin BGA).
1914 // "first" is used as the input and "second" as the output
1915 //
1916 // "first" = compRatio (footprint height / default text height)
1917 // "second" = Amount to scale ratio by
1918 std::vector<std::pair<double, double>> lut{
1919 { 1, 8 }, { 1.5, 5 }, { 3, 3 }, { 4.5, 2.5 }, { 8, 2.0 },
1920 { 12, 1.7 }, { 16, 1.5 }, { 24, 1.3 }, { 32, 1.0 },
1921 };
1922
1923
1924 std::vector<std::pair<double, double>>::iterator it;
1925
1926 compRatioBent = lut.back().second; // Large component default
1927
1928 if( compRatio >= lut.front().first )
1929 {
1930 // Use LUT to do linear interpolation of "compRatio" within "first", then
1931 // use that result to linearly interpolate "second" which gives the scaling
1932 // factor needed.
1933
1934 for( it = lut.begin(); it < lut.end() - 1; it++ )
1935 {
1936 if( it->first <= compRatio && next( it )->first >= compRatio )
1937 {
1938 double diffx = compRatio - it->first;
1939 double diffn = next( it )->first - it->first;
1940
1941 compRatioBent = it->second + ( next( it )->second - it->second ) * diffx / diffn;
1942 break; // We have our interpolated value
1943 }
1944 }
1945 }
1946 else
1947 {
1948 compRatioBent = lut.front().second; // Small component default
1949 }
1950
1951 // If the width of the part we're probing is bigger than what the screen width will be
1952 // after the zoom, then punt and use the KiCad zoom algorithm since it guarantees the
1953 // part's width will be encompassed within the screen. This will apply to parts that
1954 // are much wider than they are tall.
1955
1956 if( bbSize.x > screenSize.x * ratio * compRatioBent )
1957 {
1958 // Use standard KiCad zoom algorithm for parts too wide to fit screen/
1959 ratio = kicadRatio;
1960 compRatioBent = 1.0; // Reset so we don't modify the "KiCad" ratio
1961 wxLogTrace( "CROSS_PROBE_SCALE",
1962 "Part TOO WIDE for screen. Using normal KiCad zoom ratio: %1.5f", ratio );
1963 }
1964
1965 // Now that "compRatioBent" holds our final scaling factor we apply it to the original
1966 // fullscreen zoom ratio to arrive at the final ratio itself.
1967 ratio *= compRatioBent;
1968
1969 bool alwaysZoom = false; // DEBUG - allows us to minimize zooming or not
1970
1971 // Try not to zoom on every cross-probe; it gets very noisy
1972 if( ( ratio < 0.5 || ratio > 1.0 ) || alwaysZoom )
1973 view->SetScale( view->GetScale() / ratio );
1974#endif // ifndef DEFAULT_PCBNEW_CODE
1975}
1976
1977
1979{
1980 bool cleared = false;
1981
1982 if( m_selection.GetSize() > 0 )
1983 {
1984 // Don't fire an event now; most of the time it will be redundant as we're about to
1985 // fire a SelectedEvent.
1986 cleared = true;
1987 ClearSelection( true /*quiet mode*/ );
1988 }
1989
1990 if( aItem )
1991 {
1992 switch( aItem->Type() )
1993 {
1994 case PCB_NETINFO_T:
1995 {
1996 int netCode = static_cast<NETINFO_ITEM*>( aItem )->GetNetCode();
1997
1998 if( netCode > 0 )
1999 {
2000 SelectAllItemsOnNet( netCode, true );
2001 m_frame->FocusOnLocation( aItem->GetCenter() );
2002 }
2003 break;
2004 }
2005
2006 default:
2007 select( aItem );
2008 m_frame->FocusOnLocation( aItem->GetPosition() );
2009 }
2010
2011 // If the item has a bounding box, then zoom out if needed
2012 if( aItem->GetBoundingBox().GetHeight() > 0 && aItem->GetBoundingBox().GetWidth() > 0 )
2013 {
2014 // This adds some margin
2015 double marginFactor = 2;
2016
2017 KIGFX::PCB_VIEW* pcbView = canvas()->GetView();
2018 BOX2D screenBox = pcbView->GetViewport();
2019 VECTOR2I screenSize = screenBox.GetSize();
2020 BOX2I screenRect( screenBox.GetOrigin(), screenSize / marginFactor );
2021
2022 if( !screenRect.Contains( aItem->GetBoundingBox() ) )
2023 {
2024 double scaleX = screenSize.x / static_cast<double>( aItem->GetBoundingBox().GetWidth() );
2025 double scaleY = screenSize.y / static_cast<double>( aItem->GetBoundingBox().GetHeight() );
2026
2027 scaleX /= marginFactor;
2028 scaleY /= marginFactor;
2029
2030 double scale = scaleX > scaleY ? scaleY : scaleX;
2031
2032 if( scale < 1 ) // Don't zoom in, only zoom out
2033 {
2034 pcbView->SetScale( pcbView->GetScale() * ( scale ) );
2035
2036 //Let's refocus because there is an algorithm to avoid dialogs in there.
2037 m_frame->FocusOnLocation( aItem->GetCenter() );
2038 }
2039 }
2040 }
2041 // Inform other potentially interested tools
2043 }
2044 else if( cleared )
2045 {
2047 }
2048
2050}
2051
2052
2058static bool itemIsIncludedByFilter( const BOARD_ITEM& aItem, const BOARD& aBoard,
2059 const DIALOG_FILTER_SELECTION::OPTIONS& aFilterOptions )
2060{
2061 bool include = true;
2062 const PCB_LAYER_ID layer = aItem.GetLayer();
2063
2064 // if the item needs to be checked against the options
2065 if( include )
2066 {
2067 switch( aItem.Type() )
2068 {
2069 case PCB_FOOTPRINT_T:
2070 {
2071 const FOOTPRINT& footprint = static_cast<const FOOTPRINT&>( aItem );
2072
2073 include = aFilterOptions.includeModules;
2074
2075 if( include && !aFilterOptions.includeLockedModules )
2076 include = !footprint.IsLocked();
2077
2078 break;
2079 }
2080 case PCB_TRACE_T:
2081 case PCB_ARC_T:
2082 include = aFilterOptions.includeTracks;
2083 break;
2084
2085 case PCB_VIA_T:
2086 include = aFilterOptions.includeVias;
2087 break;
2088
2089 case PCB_FP_ZONE_T:
2090 case PCB_ZONE_T:
2091 include = aFilterOptions.includeZones;
2092 break;
2093
2094 case PCB_SHAPE_T:
2095 case PCB_TARGET_T:
2096 case PCB_DIM_ALIGNED_T:
2097 case PCB_DIM_CENTER_T:
2098 case PCB_DIM_RADIAL_T:
2100 case PCB_DIM_LEADER_T:
2106 if( layer == Edge_Cuts )
2107 include = aFilterOptions.includeBoardOutlineLayer;
2108 else
2109 include = aFilterOptions.includeItemsOnTechLayers;
2110 break;
2111
2112 case PCB_FP_TEXT_T:
2113 case PCB_FP_TEXTBOX_T:
2114 case PCB_TEXT_T:
2115 case PCB_TEXTBOX_T:
2116 include = aFilterOptions.includePcbTexts;
2117 break;
2118
2119 default:
2120 // no filtering, just select it
2121 break;
2122 }
2123 }
2124
2125 return include;
2126}
2127
2128
2130{
2131 const BOARD& board = *getModel<BOARD>();
2132 DIALOG_FILTER_SELECTION::OPTIONS& opts = m_priv->m_filterOpts;
2133 DIALOG_FILTER_SELECTION dlg( m_frame, opts );
2134
2135 const int cmd = dlg.ShowModal();
2136
2137 if( cmd != wxID_OK )
2138 return 0;
2139
2140 // copy current selection
2141 std::deque<EDA_ITEM*> selection = m_selection.GetItems();
2142
2143 ClearSelection( true /*quiet mode*/ );
2144
2145 // re-select items from the saved selection according to the dialog options
2146 for( EDA_ITEM* i : selection )
2147 {
2148 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( i );
2149 bool include = itemIsIncludedByFilter( *item, board, opts );
2150
2151 if( include )
2152 select( item );
2153 }
2154
2156
2157 return 0;
2158}
2159
2160
2162{
2163 if( aCollector.GetCount() == 0 )
2164 return;
2165
2166 std::set<BOARD_ITEM*> rejected;
2167
2168 for( EDA_ITEM* i : aCollector )
2169 {
2170 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( i );
2171
2172 if( !itemPassesFilter( item, aMultiSelect ) )
2173 rejected.insert( item );
2174 }
2175
2176 for( BOARD_ITEM* item : rejected )
2177 aCollector.Remove( item );
2178}
2179
2180
2181bool PCB_SELECTION_TOOL::itemPassesFilter( BOARD_ITEM* aItem, bool aMultiSelect )
2182{
2183 if( !m_filter.lockedItems )
2184 {
2185 if( aItem->IsLocked() || ( aItem->GetParent() && aItem->GetParent()->IsLocked() ) )
2186 {
2187 if( aItem->Type() == PCB_PAD_T && !aMultiSelect )
2188 {
2189 // allow a single pad to be selected -- there are a lot of operations that
2190 // require this so we allow this one inconsistency
2191 }
2192 else
2193 {
2194 return false;
2195 }
2196 }
2197 }
2198
2199 switch( aItem->Type() )
2200 {
2201 case PCB_FOOTPRINT_T:
2202 if( !m_filter.footprints )
2203 return false;
2204
2205 break;
2206
2207 case PCB_PAD_T:
2208 if( !m_filter.pads )
2209 return false;
2210
2211 break;
2212
2213 case PCB_TRACE_T:
2214 case PCB_ARC_T:
2215 if( !m_filter.tracks )
2216 return false;
2217
2218 break;
2219
2220 case PCB_VIA_T:
2221 if( !m_filter.vias )
2222 return false;
2223
2224 break;
2225
2226 case PCB_FP_ZONE_T:
2227 case PCB_ZONE_T:
2228 {
2229 ZONE* zone = static_cast<ZONE*>( aItem );
2230
2231 if( ( !m_filter.zones && !zone->GetIsRuleArea() )
2232 || ( !m_filter.keepouts && zone->GetIsRuleArea() ) )
2233 {
2234 return false;
2235 }
2236
2237 break;
2238 }
2239
2240 case PCB_FP_SHAPE_T:
2241 case PCB_SHAPE_T:
2242 case PCB_TARGET_T:
2243 if( !m_filter.graphics )
2244 return false;
2245
2246 break;
2247
2248 case PCB_BITMAP_T:
2249 // a bitmap living in a footprint must not be selected inside the board editor
2250 if( !m_filter.graphics )
2251 return false;
2252
2253 if( !m_isFootprintEditor )
2254 {
2255 if( dynamic_cast<FOOTPRINT*>( aItem->GetParent() ) )
2256 return false;
2257 }
2258
2259
2260 break;
2261
2262 case PCB_FP_TEXT_T:
2263 case PCB_FP_TEXTBOX_T:
2264 case PCB_TEXT_T:
2265 case PCB_TEXTBOX_T:
2266 if( !m_filter.text )
2267 return false;
2268
2269 break;
2270
2271 case PCB_DIM_ALIGNED_T:
2272 case PCB_DIM_CENTER_T:
2273 case PCB_DIM_RADIAL_T:
2275 case PCB_DIM_LEADER_T:
2281 if( !m_filter.dimensions )
2282 return false;
2283
2284 break;
2285
2286 default:
2287 if( !m_filter.otherItems )
2288 return false;
2289 }
2290
2291 return true;
2292}
2293
2294
2296{
2297 if( m_selection.Empty() )
2298 return;
2299
2300 while( m_selection.GetSize() )
2302
2303 view()->Update( &m_selection );
2304
2305 m_selection.SetIsHover( false );
2307
2308 // Inform other potentially interested tools
2309 if( !aQuietMode )
2310 {
2313 }
2314}
2315
2316
2318{
2320
2321 bool enteredGroupFound = false;
2322
2323 INSPECTOR_FUNC inspector =
2324 [&]( EDA_ITEM* item, void* testData )
2325 {
2326 if( item->IsSelected() )
2327 {
2328 EDA_ITEM* parent = item->GetParent();
2329
2330 // Let selected parents handle their children.
2331 if( parent && parent->IsSelected() )
2333
2334 highlight( item, SELECTED, &m_selection );
2335 }
2336
2337 if( item == m_enteredGroup )
2338 {
2339 item->SetFlags( ENTERED );
2340 enteredGroupFound = true;
2341 }
2342 else
2343 {
2344 item->ClearFlags( ENTERED );
2345 }
2346
2348 };
2349
2352
2353 if( !enteredGroupFound )
2354 {
2356 m_enteredGroup = nullptr;
2357 }
2358}
2359
2360
2361bool PCB_SELECTION_TOOL::Selectable( const BOARD_ITEM* aItem, bool checkVisibilityOnly ) const
2362{
2363 const RENDER_SETTINGS* settings = getView()->GetPainter()->GetSettings();
2364
2365 auto visibleLayers =
2366 [&]()
2367 {
2369 {
2370 LSET set;
2371
2372 for( PCB_LAYER_ID layer : LSET::AllLayersMask().Seq() )
2373 set.set( layer, view()->IsLayerVisible( layer ) );
2374
2375 return set;
2376 }
2377 else
2378 {
2379 return board()->GetVisibleLayers();
2380 }
2381 };
2382
2383 if( settings->GetHighContrast() )
2384 {
2385 const std::set<int> activeLayers = settings->GetHighContrastLayers();
2386 bool onActiveLayer = false;
2387
2388 for( int layer : activeLayers )
2389 {
2390 // NOTE: Only checking the regular layers (not GAL meta-layers)
2391 if( layer < PCB_LAYER_ID_COUNT && aItem->IsOnLayer( ToLAYER_ID( layer ) ) )
2392 {
2393 onActiveLayer = true;
2394 break;
2395 }
2396 }
2397
2398 if( !onActiveLayer ) // We do not want to select items that are in the background
2399 return false;
2400 }
2401
2402 if( aItem->Type() == PCB_FOOTPRINT_T )
2403 {
2404 // In footprint editor, we do not want to select the footprint itself.
2406 return false;
2407
2408 // Allow selection of footprints if some part of the footprint is visible.
2409 const FOOTPRINT* footprint = static_cast<const FOOTPRINT*>( aItem );
2410 LSET boardSide = footprint->IsFlipped() ? LSET::BackMask() : LSET::FrontMask();
2411
2412 if( !( visibleLayers() & boardSide ).any() && !m_skip_heuristics )
2413 return false;
2414
2415 // If the footprint has no items except the reference and value fields, include the
2416 // footprint in the selections.
2417 if( footprint->GraphicalItems().empty()
2418 && footprint->Pads().empty()
2419 && footprint->Zones().empty() )
2420 {
2421 return true;
2422 }
2423
2424 for( const BOARD_ITEM* item : footprint->GraphicalItems() )
2425 {
2426 if( Selectable( item, true ) )
2427 return true;
2428 }
2429
2430 for( const PAD* pad : footprint->Pads() )
2431 {
2432 if( Selectable( pad, true ) )
2433 return true;
2434 }
2435
2436 for( const ZONE* zone : footprint->Zones() )
2437 {
2438 if( Selectable( zone, true ) )
2439 return true;
2440 }
2441
2442 return false;
2443 }
2444 else if( aItem->Type() == PCB_GROUP_T )
2445 {
2446 PCB_GROUP* group = const_cast<PCB_GROUP*>( static_cast<const PCB_GROUP*>( aItem ) );
2447
2448 // Similar to logic for footprint, a group is selectable if any of its members are.
2449 // (This recurses.)
2450 for( BOARD_ITEM* item : group->GetItems() )
2451 {
2452 if( Selectable( item, true ) )
2453 return true;
2454 }
2455
2456 return false;
2457 }
2458
2459 const ZONE* zone = nullptr;
2460 const PCB_VIA* via = nullptr;
2461 const PAD* pad = nullptr;
2462 const FP_TEXT* text = nullptr;
2463
2464 switch( aItem->Type() )
2465 {
2466 case PCB_ZONE_T:
2467 case PCB_FP_ZONE_T:
2469 return false;
2470
2471 zone = static_cast<const ZONE*>( aItem );
2472
2473 // A footprint zone is only selectable within the footprint editor
2474 if( zone->GetParent()
2475 && zone->GetParent()->Type() == PCB_FOOTPRINT_T
2477 && !checkVisibilityOnly )
2478 {
2479 return false;
2480 }
2481
2482 // zones can exist on multiple layers!
2483 if( !( zone->GetLayerSet() & visibleLayers() ).any() )
2484 return false;
2485
2486 break;
2487
2488 case PCB_TRACE_T:
2489 case PCB_ARC_T:
2491 return false;
2492
2494 {
2495 if( !view()->IsLayerVisible( aItem->GetLayer() ) )
2496 return false;
2497 }
2498 else
2499 {
2500 if( !board()->IsLayerVisible( aItem->GetLayer() ) )
2501 return false;
2502 }
2503
2504 break;
2505
2506 case PCB_VIA_T:
2507 if( !board()->IsElementVisible( LAYER_VIAS ) )
2508 return false;
2509
2510 via = static_cast<const PCB_VIA*>( aItem );
2511
2512 // For vias it is enough if only one of its layers is visible
2513 if( !( visibleLayers() & via->GetLayerSet() ).any() )
2514 return false;
2515
2516 break;
2517
2518 case PCB_FP_TEXT_T:
2520 {
2521 text = static_cast<const FP_TEXT*>( aItem );
2522
2523 if( !text->IsVisible() && !view()->IsLayerVisible( LAYER_MOD_TEXT_INVISIBLE ) )
2524 return false;
2525
2526 if( !view()->IsLayerVisible( aItem->GetLayer() ) )
2527 return false;
2528 }
2529 else
2530 {
2531 if( !view()->IsVisible( aItem ) )
2532 return false;
2533
2534 if( !board()->IsLayerVisible( aItem->GetLayer() ) )
2535 return false;
2536
2537 int controlLayer = UNDEFINED_LAYER;
2538
2539 switch( static_cast<const FP_TEXT*>( aItem )->GetType() )
2540 {
2541 case FP_TEXT::TEXT_is_REFERENCE: controlLayer = LAYER_MOD_REFERENCES; break;
2542 case FP_TEXT::TEXT_is_VALUE: controlLayer = LAYER_MOD_VALUES; break;
2543 case FP_TEXT::TEXT_is_DIVERS: controlLayer = LAYER_MOD_TEXT; break;
2544 }
2545
2546 if( controlLayer == UNDEFINED_LAYER )
2547 return false;
2548
2549 if( !view()->IsLayerVisible( controlLayer ) )
2550 return false;
2551 }
2552
2553 break;
2554
2555 case PCB_FP_SHAPE_T:
2556 case PCB_FP_TEXTBOX_T:
2558 {
2559 if( !view()->IsLayerVisible( aItem->GetLayer() ) )
2560 return false;
2561 }
2562 else
2563 {
2564 // Footprint shape selections are only allowed in footprint editor mode.
2565 if( !checkVisibilityOnly )
2566 return false;
2567
2568 if( !board()->IsLayerVisible( aItem->GetLayer() ) )
2569 return false;
2570 }
2571
2572 break;
2573
2574 case PCB_PAD_T:
2575 pad = static_cast<const PAD*>( aItem );
2576
2577 if( pad->GetAttribute() == PAD_ATTRIB::PTH || pad->GetAttribute() == PAD_ATTRIB::NPTH )
2578 {
2579 // Check render mode (from the Items tab) first
2581 return false;
2582
2583 // A pad's hole is visible on every layer the pad is visible on plus many layers the
2584 // pad is not visible on -- so we only need to check for any visible hole layers.
2585 if( !( visibleLayers() & LSET::PhysicalLayersMask() ).any() )
2586 return false;
2587 }
2588 else
2589 {
2590 // Check render mode (from the Items tab) first
2591 if( pad->IsOnLayer( F_Cu ) && !board()->IsElementVisible( LAYER_PAD_FR ) )
2592 return false;
2593 else if( pad->IsOnLayer( B_Cu ) && !board()->IsElementVisible( LAYER_PAD_BK ) )
2594 return false;
2595
2596 if( !( pad->GetLayerSet() & visibleLayers() ).any() )
2597 return false;
2598 }
2599
2600 break;
2601
2602 // These are not selectable
2603 case PCB_NETINFO_T:
2604 case NOT_USED:
2605 case TYPE_NOT_INIT:
2606 return false;
2607
2608 default: // Suppress warnings
2609 break;
2610 }
2611
2612 return true;
2613}
2614
2615
2617{
2618 if( aItem->IsSelected() )
2619 return;
2620
2621 if( aItem->Type() == PCB_PAD_T )
2622 {
2623 FOOTPRINT* footprint = static_cast<FOOTPRINT*>( aItem->GetParent() );
2624
2625 if( m_selection.Contains( footprint ) )
2626 return;
2627 }
2628
2629 if( m_enteredGroup &&
2630 !PCB_GROUP::WithinScope( static_cast<BOARD_ITEM*>( aItem ), m_enteredGroup,
2632 {
2633 ExitGroup();
2634 }
2635
2636 highlight( aItem, SELECTED, &m_selection );
2637}
2638
2639
2641{
2642 unhighlight( aItem, SELECTED, &m_selection );
2643}
2644
2645
2646void PCB_SELECTION_TOOL::highlight( EDA_ITEM* aItem, int aMode, SELECTION* aGroup )
2647{
2648 if( aGroup )
2649 aGroup->Add( aItem );
2650
2651 highlightInternal( aItem, aMode, aGroup != nullptr );
2652 view()->Update( aItem, KIGFX::REPAINT );
2653
2654 // Many selections are very temporal and updating the display each time just
2655 // creates noise.
2656 if( aMode == BRIGHTENED )
2658}
2659
2660
2661void PCB_SELECTION_TOOL::highlightInternal( EDA_ITEM* aItem, int aMode, bool aUsingOverlay )
2662{
2663 if( aMode == SELECTED )
2664 aItem->SetSelected();
2665 else if( aMode == BRIGHTENED )
2666 aItem->SetBrightened();
2667
2668 if( aUsingOverlay && aMode != BRIGHTENED )
2669 view()->Hide( aItem, true ); // Hide the original item, so it is shown only on overlay
2670
2671 if( aItem->Type() == PCB_FOOTPRINT_T )
2672 {
2673 static_cast<FOOTPRINT*>( aItem )->RunOnChildren(
2674 [&]( BOARD_ITEM* aChild )
2675 {
2676 highlightInternal( aChild, aMode, aUsingOverlay );
2677 } );
2678 }
2679 else if( aItem->Type() == PCB_GROUP_T )
2680 {
2681 static_cast<PCB_GROUP*>( aItem )->RunOnChildren(
2682 [&]( BOARD_ITEM* aChild )
2683 {
2684 highlightInternal( aChild, aMode, aUsingOverlay );
2685 } );
2686 }
2687}
2688
2689
2690void PCB_SELECTION_TOOL::unhighlight( EDA_ITEM* aItem, int aMode, SELECTION* aGroup )
2691{
2692 if( aGroup )
2693 aGroup->Remove( aItem );
2694
2695 unhighlightInternal( aItem, aMode, aGroup != nullptr );
2696 view()->Update( aItem, KIGFX::REPAINT );
2697
2698 // Many selections are very temporal and updating the display each time just creates noise.
2699 if( aMode == BRIGHTENED )
2701}
2702
2703
2704void PCB_SELECTION_TOOL::unhighlightInternal( EDA_ITEM* aItem, int aMode, bool aUsingOverlay )
2705{
2706 if( aMode == SELECTED )
2707 aItem->ClearSelected();
2708 else if( aMode == BRIGHTENED )
2709 aItem->ClearBrightened();
2710
2711 if( aUsingOverlay && aMode != BRIGHTENED )
2712 view()->Hide( aItem, false ); // // Restore original item visibility
2713
2714 if( aItem->Type() == PCB_FOOTPRINT_T )
2715 {
2716 static_cast<FOOTPRINT*>( aItem )->RunOnChildren(
2717 [&]( BOARD_ITEM* aChild )
2718 {
2719 unhighlightInternal( aChild, aMode, aUsingOverlay );
2720 } );
2721 }
2722 else if( aItem->Type() == PCB_GROUP_T )
2723 {
2724 static_cast<PCB_GROUP*>( aItem )->RunOnChildren(
2725 [&]( BOARD_ITEM* aChild )
2726 {
2727 unhighlightInternal( aChild, aMode, aUsingOverlay );
2728 } );
2729 }
2730}
2731
2732
2734{
2735 const unsigned GRIP_MARGIN = 20;
2736 int margin = KiROUND( getView()->ToWorld( GRIP_MARGIN ) );
2737
2738 // Check if the point is located close to any of the currently selected items
2739 for( EDA_ITEM* item : m_selection )
2740 {
2741 BOX2I itemBox = item->ViewBBox();
2742 itemBox.Inflate( margin ); // Give some margin for gripping an item
2743
2744 if( itemBox.Contains( aPoint ) )
2745 {
2746 if( item->HitTest( aPoint, margin ) )
2747 return true;
2748
2749 bool found = false;
2750
2751 std::function<void( PCB_GROUP* )> checkGroup;
2752 checkGroup = [&]( PCB_GROUP* aGroup )
2753 {
2754 aGroup->RunOnChildren(
2755 [&]( BOARD_ITEM* aItem )
2756 {
2757 if( PCB_GROUP* group = dyn_cast<PCB_GROUP*>( aItem ) )
2758 checkGroup( group );
2759 else if( aItem->HitTest( aPoint, margin ) )
2760 found = true;
2761 } );
2762 };
2763
2764 if( PCB_GROUP* group = dyn_cast<PCB_GROUP*>( item ) )
2765 {
2766 checkGroup( group );
2767
2768 if( found )
2769 return true;
2770 }
2771 }
2772 }
2773
2774 return false;
2775}
2776
2777
2778int PCB_SELECTION_TOOL::hitTestDistance( const wxPoint& aWhere, BOARD_ITEM* aItem,
2779 int aMaxDistance ) const
2780{
2781 BOX2D viewportD = getView()->GetViewport();
2782 BOX2I viewport( VECTOR2I( viewportD.GetPosition() ), VECTOR2I( viewportD.GetSize() ) );
2783 int distance = INT_MAX;
2784 SEG loc( aWhere, aWhere );
2785
2786 switch( aItem->Type() )
2787 {
2788 case PCB_TEXT_T:
2789 {
2790 PCB_TEXT* text = static_cast<PCB_TEXT*>( aItem );
2791 text->GetEffectiveTextShape()->Collide( loc, aMaxDistance, &distance );
2792 break;
2793 }
2794
2795 case PCB_TEXTBOX_T:
2796 {
2797 PCB_TEXTBOX* textbox = static_cast<PCB_TEXTBOX*>( aItem );
2798 textbox->GetEffectiveTextShape()->Collide( loc, aMaxDistance, &distance );
2799 break;
2800 }
2801
2802 case PCB_FP_TEXT_T:
2803 {
2804 FP_TEXT* text = static_cast<FP_TEXT*>( aItem );
2805 text->GetEffectiveTextShape()->Collide( loc, aMaxDistance, &distance );
2806 break;
2807 }
2808
2809 case PCB_FP_TEXTBOX_T:
2810 {
2811 FP_TEXTBOX* textbox = static_cast<FP_TEXTBOX*>( aItem );
2812 textbox->GetEffectiveTextShape()->Collide( loc, aMaxDistance, &distance );
2813 break;
2814 }
2815
2816 case PCB_ZONE_T:
2817 {
2818 ZONE* zone = static_cast<ZONE*>( aItem );
2819
2820 // Zone borders are very specific
2821 if( zone->HitTestForEdge( aWhere, aMaxDistance / 2 ) )
2822 distance = 0;
2823 else if( zone->HitTestForEdge( aWhere, aMaxDistance ) )
2824 distance = aMaxDistance / 2;
2825 else
2826 aItem->GetEffectiveShape()->Collide( loc, aMaxDistance, &distance );
2827
2828 break;
2829 }
2830
2831 case PCB_FOOTPRINT_T:
2832 {
2833 FOOTPRINT* footprint = static_cast<FOOTPRINT*>( aItem );
2834 BOX2I bbox = footprint->GetBoundingBox( false, false );
2835
2836 try
2837 {
2838 footprint->GetBoundingHull().Collide( loc, aMaxDistance, &distance );
2839 }
2840 catch( const ClipperLib::clipperException& exc )
2841 {
2842 // This may be overkill and could be an assertion but we are more likely to find
2843 // any clipper errors this way.
2844 wxLogError( wxT( "Clipper library exception '%s' occurred." ), exc.what() );
2845 }
2846
2847 // Consider footprints larger than the viewport only as a last resort
2848 if( bbox.GetHeight() > viewport.GetHeight() || bbox.GetWidth() > viewport.GetWidth() )
2849 distance = INT_MAX / 2;
2850
2851 break;
2852 }
2853
2854 case PCB_MARKER_T:
2855 {
2856 PCB_MARKER* marker = static_cast<PCB_MARKER*>( aItem );
2857 SHAPE_LINE_CHAIN polygon;
2858
2859 marker->ShapeToPolygon( polygon );
2860 polygon.Move( marker->GetPos() );
2861 polygon.Collide( loc, aMaxDistance, &distance );
2862 break;
2863 }
2864
2865 case PCB_GROUP_T:
2866 {
2867 PCB_GROUP* group = static_cast<PCB_GROUP*>( aItem );
2868
2869 for( BOARD_ITEM* member : group->GetItems() )
2870 distance = std::min( distance, hitTestDistance( aWhere, member, aMaxDistance ) );
2871
2872 break;
2873 }
2874
2875 default:
2876 aItem->GetEffectiveShape()->Collide( loc, aMaxDistance, &distance );
2877 break;
2878 }
2879
2880 return distance;
2881}
2882
2883
2884// The general idea here is that if the user clicks directly on a small item inside a larger
2885// one, then they want the small item. The quintessential case of this is clicking on a pad
2886// within a footprint, but we also apply it for text within a footprint, footprints within
2887// larger footprints, and vias within either larger pads or longer tracks.
2888//
2889// These "guesses" presume there is area within the larger item to click in to select it. If
2890// an item is mostly covered by smaller items within it, then the guesses are inappropriate as
2891// there might not be any area left to click to select the larger item. In this case we must
2892// leave the items in the collector and bring up a Selection Clarification menu.
2893//
2894// We currently check for pads and text mostly covering a footprint, but we don't check for
2895// smaller footprints mostly covering a larger footprint.
2896//
2898 const VECTOR2I& aWhere ) const
2899{
2900 std::set<BOARD_ITEM*> preferred;
2901 std::set<BOARD_ITEM*> rejected;
2902 wxPoint where( aWhere.x, aWhere.y );
2903
2904 PCB_LAYER_ID activeLayer = m_frame->GetActiveLayer();
2905 LSET silkLayers( 2, B_SilkS, F_SilkS );
2906
2907 if( silkLayers[activeLayer] )
2908 {
2909 for( int i = 0; i < aCollector.GetCount(); ++i )
2910 {
2911 BOARD_ITEM* item = aCollector[i];
2912 KICAD_T type = item->Type();
2913
2914 if( ( type == PCB_TEXT_T || type == PCB_TEXTBOX_T || type == PCB_SHAPE_T )
2915 && silkLayers[item->GetLayer()] )
2916 {
2917 preferred.insert( item );
2918 }
2919 }
2920
2921 if( preferred.size() > 0 )
2922 {
2923 aCollector.Empty();
2924
2925 for( BOARD_ITEM* item : preferred )
2926 aCollector.Append( item );
2927
2928 return;
2929 }
2930 }
2931
2932 // Prefer exact hits to sloppy ones
2933 constexpr int MAX_SLOP = 5;
2934
2935 int singlePixel = KiROUND( aCollector.GetGuide()->OnePixelInIU() );
2936 int maxSlop = KiROUND( MAX_SLOP * aCollector.GetGuide()->OnePixelInIU() );
2937 int minSlop = INT_MAX;
2938
2939 std::map<BOARD_ITEM*, int> itemsBySloppiness;
2940
2941 for( int i = 0; i < aCollector.GetCount(); ++i )
2942 {
2943 BOARD_ITEM* item = aCollector[i];
2944 int itemSlop = hitTestDistance( where, item, maxSlop );
2945
2946 itemsBySloppiness[ item ] = itemSlop;
2947
2948 if( itemSlop < minSlop )
2949 minSlop = itemSlop;
2950 }
2951
2952 // Prune sloppier items
2953 if( minSlop < INT_MAX )
2954 {
2955 for( std::pair<BOARD_ITEM*, int> pair : itemsBySloppiness )
2956 {
2957 if( pair.second > minSlop + singlePixel )
2958 aCollector.Transfer( pair.first );
2959 }
2960 }
2961
2962 // If the user clicked on a small item within a much larger one then it's pretty clear
2963 // they're trying to select the smaller one.
2964 constexpr double sizeRatio = 1.5;
2965
2966 std::vector<std::pair<BOARD_ITEM*, double>> itemsByArea;
2967
2968 for( int i = 0; i < aCollector.GetCount(); ++i )
2969 {
2970 BOARD_ITEM* item = aCollector[i];
2971 double area = 0.0;
2972
2973 if( ( item->Type() == PCB_ZONE_T || item->Type() == PCB_FP_ZONE_T )
2974 && static_cast<ZONE*>( item )->HitTestForEdge( where, maxSlop / 2 ) )
2975 {
2976 // Zone borders are very specific, so make them "small"
2977 area = (double) SEG::Square( singlePixel ) * MAX_SLOP;
2978 }
2979 else if( item->Type() == PCB_VIA_T )
2980 {
2981 // Vias rarely hide other things, and we don't want them deferring to short track
2982 // segments underneath them -- so artificially reduce their size from πr² to 1.5r².
2983 area = (double) SEG::Square( static_cast<PCB_VIA*>( item )->GetDrill() / 2 ) * 1.5;
2984 }
2985 else if( item->Type() == PCB_BITMAP_T )
2986 {
2987 VECTOR2D size = static_cast<const PCB_BITMAP*>( item )->GetSize();
2988 area = size.x * size.y;
2989 }
2990 else
2991 {
2992 try
2993 {
2994 area = FOOTPRINT::GetCoverageArea( item, aCollector );
2995 }
2996 catch( const ClipperLib::clipperException& e )
2997 {
2998 wxLogError( wxT( "A clipper exception %s was detected." ), e.what() );
2999 }
3000 }
3001
3002 itemsByArea.emplace_back( item, area );
3003 }
3004
3005 std::sort( itemsByArea.begin(), itemsByArea.end(),
3006 []( const std::pair<BOARD_ITEM*, double>& lhs,
3007 const std::pair<BOARD_ITEM*, double>& rhs ) -> bool
3008 {
3009 return lhs.second < rhs.second;
3010 } );
3011
3012 bool rejecting = false;
3013
3014 for( int i = 1; i < (int) itemsByArea.size(); ++i )
3015 {
3016 if( itemsByArea[i].second > itemsByArea[i-1].second * sizeRatio )
3017 rejecting = true;
3018
3019 if( rejecting )
3020 rejected.insert( itemsByArea[i].first );
3021 }
3022
3023 // Special case: if a footprint is completely covered with other features then there's no
3024 // way to select it -- so we need to leave it in the list for user disambiguation.
3025 constexpr double maxCoverRatio = 0.70;
3026
3027 for( int i = 0; i < aCollector.GetCount(); ++i )
3028 {
3029 if( FOOTPRINT* footprint = dynamic_cast<FOOTPRINT*>( aCollector[i] ) )
3030 {
3031 if( footprint->CoverageRatio( aCollector ) > maxCoverRatio )
3032 rejected.erase( footprint );
3033 }
3034 }
3035
3036 // Hopefully we've now got what the user wanted.
3037 if( (unsigned) aCollector.GetCount() > rejected.size() ) // do not remove everything
3038 {
3039 for( BOARD_ITEM* item : rejected )
3040 aCollector.Transfer( item );
3041 }
3042
3043 // Finally, what we are left with is a set of items of similar coverage area. We now reject
3044 // any that are not on the active layer, to reduce the number of disambiguation menus shown.
3045 // If the user wants to force-disambiguate, they can either switch layers or use the modifier
3046 // key to force the menu.
3047 if( aCollector.GetCount() > 1 )
3048 {
3049 bool haveItemOnActive = false;
3050 rejected.clear();
3051
3052 for( int i = 0; i < aCollector.GetCount(); ++i )
3053 {
3054 if( !aCollector[i]->IsOnLayer( activeLayer ) )
3055 rejected.insert( aCollector[i] );
3056 else
3057 haveItemOnActive = true;
3058 }
3059
3060 if( haveItemOnActive )
3061 for( BOARD_ITEM* item : rejected )
3062 aCollector.Transfer( item );
3063 }
3064}
3065
3066
3068 bool aMultiselect ) const
3069{
3070 std::unordered_set<BOARD_ITEM*> toAdd;
3071
3072 // Set CANDIDATE on all parents which are included in the GENERAL_COLLECTOR. This
3073 // algorithm is O(3n), whereas checking for the parent inclusion could potentially be O(n^2).
3074 for( int j = 0; j < aCollector.GetCount(); j++ )
3075 {
3076 if( aCollector[j]->GetParent() )
3077 aCollector[j]->GetParent()->ClearFlags( CANDIDATE );
3078 }
3079
3080 if( aMultiselect )
3081 {
3082 for( int j = 0; j < aCollector.GetCount(); j++ )
3083 aCollector[j]->SetFlags( CANDIDATE );
3084 }
3085
3086 for( int j = 0; j < aCollector.GetCount(); )
3087 {
3088 BOARD_ITEM* item = aCollector[j];
3089 BOARD_ITEM* parent = item->GetParent();
3090 BOARD_ITEM* start = item;
3091
3092 if( !m_isFootprintEditor && parent && parent->Type() == PCB_FOOTPRINT_T )
3093 start = parent;
3094
3095 // If a group is entered, disallow selections of objects outside the group.
3097 {
3098 aCollector.Remove( item );
3099 continue;
3100 }
3101
3102 // If any element is a member of a group, replace those elements with the top containing
3103 // group.
3105 {
3106 if( top != item )
3107 {
3108 toAdd.insert( top );
3109 top->SetFlags(CANDIDATE );
3110
3111 aCollector.Remove( item );
3112 continue;
3113 }
3114 }
3115
3116 // Footprints are a bit easier as they can't be nested.
3117 if( parent && ( parent->GetFlags() & CANDIDATE ) )
3118 {
3119 // Remove children of selected items
3120 aCollector.Remove( item );
3121 continue;
3122 }
3123
3124 ++j;
3125 }
3126
3127 for( BOARD_ITEM* item : toAdd )
3128 {
3129 if( !aCollector.HasItem( item ) )
3130 aCollector.Append( item );
3131 }
3132}
3133
3134
3136{
3137 std::set<BOARD_ITEM*> to_add;
3138
3139 // Iterate from the back so we don't have to worry about removals.
3140 for( int i = aCollector.GetCount() - 1; i >= 0; --i )
3141 {
3142 BOARD_ITEM* item = aCollector[i];
3143
3144 if( !m_isFootprintEditor && item->Type() == PCB_PAD_T
3145 && !frame()->GetPcbNewSettings()->m_AllowFreePads )
3146 {
3147 if( !aCollector.HasItem( item->GetParent() ) )
3148 to_add.insert( item->GetParent() );
3149
3150 aCollector.Remove( item );
3151 }
3152 }
3153
3154 for( BOARD_ITEM* item : to_add )
3155 aCollector.Append( item );
3156}
3157
3158
3160{
3161 // Iterate from the back so we don't have to worry about removals.
3162 for( int i = aCollector.GetCount() - 1; i >= 0; --i )
3163 {
3164 BOARD_ITEM* item = aCollector[i];
3165
3166 if( item->Type() == PCB_MARKER_T )
3167 aCollector.Remove( item );
3168 }
3169}
3170
3171
3173{
3174 getView()->Update( &m_selection );
3176
3177 return 0;
3178}
3179
3180
3182{
3184
3188
3194
3210
3212
3214}
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:109
static TOOL_ACTION cancelInteractive
Definition: actions.h:63
static TOOL_ACTION cursorLeft
Definition: actions.h:118
static TOOL_ACTION zoomOutCenter
Definition: actions.h:96
static TOOL_ACTION zoomIn
Definition: actions.h:93
static TOOL_ACTION cursorLeftFast
Definition: actions.h:123
static TOOL_ACTION cursorDown
Definition: actions.h:117
static TOOL_ACTION zoomOut
Definition: actions.h:94
static TOOL_ACTION cursorRightFast
Definition: actions.h:124
static TOOL_ACTION zoomCenter
Definition: actions.h:97
static TOOL_ACTION panDown
Definition: actions.h:131
static TOOL_ACTION cursorDownFast
Definition: actions.h:122
static TOOL_ACTION cursorUpFast
Definition: actions.h:121
static TOOL_ACTION panLeft
Definition: actions.h:132
static TOOL_ACTION updateMenu
Definition: actions.h:171
static TOOL_ACTION doDelete
Definition: actions.h:73
static TOOL_ACTION zoomFitScreen
Definition: actions.h:98
static TOOL_ACTION panUp
Definition: actions.h:130
static TOOL_ACTION zoomFitObjects
Definition: actions.h:99
static TOOL_ACTION zoomInCenter
Definition: actions.h:95
static TOOL_ACTION panRight
Definition: actions.h:133
static TOOL_ACTION cursorUp
Cursor control with keyboard.
Definition: actions.h:116
static TOOL_ACTION cursorRight
Definition: actions.h:119
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:87
wxMenuItem * Add(const wxString &aLabel, int aId, BITMAPS aIcon)
Add a wxWidgets-style entry to the menu.
CROSS_PROBING_SETTINGS m_CrossProbing
Definition: app_settings.h:173
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
static bool ClassOf(const EDA_ITEM *aItem)
Returns information if the object is derived from BOARD_CONNECTED_ITEM.
Tool for pcb inspection.
int ClearHighlight(const TOOL_EVENT &aEvent)
Perform the appropriate action in response to an Eeschema cross-probe.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:58
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:180
virtual VECTOR2I GetCenter() const
This defaults to the center of the bounding box if not overridden.
Definition: board_item.h:93
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:219
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition: board_item.h:185
virtual bool IsLocked() const
Definition: board_item.cpp:71
BOARD_ITEM_CONTAINER * GetParent() const
Definition: board_item.h:163
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:265
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:1334
LSET GetVisibleLayers() const
A proxy function that calls the correspondent function in m_BoardSettings.
Definition: board.cpp:583
bool IsElementVisible(GAL_LAYER_ID aLayer) const
Test whether a given element category is visible.
Definition: board.cpp:635
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:575
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Return a list of missing connections between components/tracks.
Definition: board.h:424
BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition: box2.h:119
const Vec & GetPosition() const
Definition: box2.h:184
const Vec & GetOrigin() const
Definition: box2.h:183
void SetMaximum()
Definition: box2.h:63
coord_type GetHeight() const
Definition: box2.h:188
coord_type GetWidth() const
Definition: box2.h:187
bool Contains(const Vec &aPoint) const
Definition: box2.h:141
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:506
Vec Centre() const
Definition: box2.h:70
const Vec & GetSize() const
Definition: box2.h:179
CN_ANCHOR represents a physical location that can be connected: a pad or a track/arc/via endpoint.
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:249
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:139
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:141
bool IsSelected() const
Definition: eda_item.h:106
void SetSelected()
Definition: eda_item.h:115
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:222
EDA_ITEM * GetParent() const
Definition: eda_item.h:99
EDA_ITEM_FLAGS GetFlags() const
Definition: eda_item.h:142
std::shared_ptr< SHAPE_COMPOUND > GetEffectiveTextShape(bool aTriangulate=true, bool aUseTextRotation=true) const
build a list of segments (SHAPE_SEGMENT) to describe a text shape.
Definition: eda_text.cpp:853
static const TOOL_EVENT DisambiguatePoint
Definition: actions.h:223
static const TOOL_EVENT ClearedEvent
Definition: actions.h:208
static const TOOL_EVENT InhibitSelectionEditing
Definition: actions.h:219
static const TOOL_EVENT SelectedEvent
Definition: actions.h:206
static const TOOL_EVENT SelectedItemsModified
Selected items were moved, this can be very high frequency on the canvas, use with care.
Definition: actions.h:213
static const TOOL_EVENT UninhibitSelectionEditing
Used to inform tool that it should display the disambiguation menu.
Definition: actions.h:220
static const TOOL_EVENT PointSelectedEvent
Definition: actions.h:205
static const TOOL_EVENT SelectedItemsMoved
Used to inform tools that the selection should temporarily be non-editable.
Definition: actions.h:216
static const TOOL_EVENT UnselectedEvent
Definition: actions.h:207
static double GetCoverageArea(const BOARD_ITEM *aItem, const GENERAL_COLLECTOR &aCollector)
Return the initial comments block or NULL if none, without transfer of ownership.
Definition: footprint.cpp:2029
bool IsFlipped() const
Definition: footprint.h:324
PADS & Pads()
Definition: footprint.h:170
SHAPE_POLY_SET GetBoundingHull() const
Return a bounding polygon for the shapes and pads in the footprint.
Definition: footprint.cpp:936
bool IsLocked() const override
Definition: footprint.h:340
const KIID_PATH & GetPath() const
Definition: footprint.h:224
FP_ZONES & Zones()
Definition: footprint.h:176
DRAWINGS & GraphicalItems()
Definition: footprint.h:173
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: footprint.cpp:805
@ TEXT_is_REFERENCE
Definition: fp_text.h:49
@ TEXT_is_DIVERS
Definition: fp_text.h:51
@ TEXT_is_VALUE
Definition: fp_text.h:50
TEXT_TYPE GetType() const
Definition: fp_text.h:120
A general implementation of a COLLECTORS_GUIDE.
Definition: collectors.h:326
void SetIgnoreBlindBuriedVias(bool ignore)
Definition: collectors.h:471
void SetIgnoreTracks(bool ignore)
Definition: collectors.h:477
void SetIgnoreMTextsMarkedNoShow(bool ignore)
Definition: collectors.h:411
void SetIgnoreModulesOnFront(bool ignore)
Definition: collectors.h:435
void SetIgnoreModulesRefs(bool ignore)
Definition: collectors.h:465
void SetIgnoreMicroVias(bool ignore)
Definition: collectors.h:474
void SetIgnoreZoneFills(bool ignore)
Definition: collectors.h:480
void SetIgnorePadsOnBack(bool ignore)
Definition: collectors.h:441
void SetIgnoreModulesOnBack(bool ignore)
Definition: collectors.h:429
void SetIgnoreModulesVals(bool ignore)
Definition: collectors.h:459
void SetIgnoreThroughVias(bool ignore)
Definition: collectors.h:468
void SetIgnoreThroughHolePads(bool ignore)
Definition: collectors.h:453
void SetIgnoreMTextsOnFront(bool ignore)
Definition: collectors.h:423
void SetIgnoreMTextsOnBack(bool ignore)
Definition: collectors.h:417
void SetIgnorePadsOnFront(bool ignore)
Definition: collectors.h:447
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:293
const COLLECTORS_GUIDE * GetGuide() const
Definition: collectors.h:295
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:596
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:92
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1) override
Add a VIEW_ITEM to the view.
Definition: pcb_view.cpp:58
virtual void Remove(VIEW_ITEM *aItem) override
Remove a VIEW_ITEM from the view.
Definition: pcb_view.cpp:75
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:69
virtual void Add(VIEW_ITEM *aItem)
Add an item to the group.
Definition: view_group.cpp:57
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition: view.h:69
double GetScale() const
Definition: view.h:269
BOX2D GetViewport() const
Return the current viewport visible area rectangle.
Definition: view.cpp:511
virtual void SetScale(double aScale, VECTOR2D aAnchor={ 0, 0 })
Set the scaling factor, zooming around a given anchor point.
Definition: view.cpp:551
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition: view.cpp:349
void UpdateAllLayersColor()
Apply the new coloring scheme to all layers.
Definition: view.cpp:761
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:425
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:1591
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:448
void Hide(VIEW_ITEM *aItem, bool aHide=true)
Temporarily hide the item in the view (e.g.
Definition: view.cpp:1550
bool IsMirroredX() const
Return true if view is flipped across the X axis.
Definition: view.h:243
std::pair< VIEW_ITEM *, int > LAYER_ITEM_PAIR
Definition: view.h:73
bool IsLayerVisible(int aLayer) const
Return information about visibility of a particular layer.
Definition: view.h:410
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition: view.h:213
void SetCenter(const VECTOR2D &aCenter)
Set the center point of the VIEW (i.e.
Definition: view.cpp:577
void MarkTargetDirty(int aTarget)
Set or clear target 'dirty' flag.
Definition: view.h:617
bool IsVisible(const VIEW_ITEM *aItem) const
Return information if the item is visible (or not).
Definition: view.cpp:1569
void SetVisible(VIEW_ITEM *aItem, bool aIsVisible=true)
Set the item visibility.
Definition: view.cpp:1529
wxString AsString() const
Definition: kiid.cpp:359
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:530
static LSET AllLayersMask()
Definition: lset.cpp:808
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:411
bool Contains(PCB_LAYER_ID aLayer)
See if the layer set contains a PCB layer.
Definition: layer_ids.h:600
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:773
static LSET PhysicalLayersMask()
Return a mask holding all layers which are physically realized.
Definition: lset.cpp:870
static LSET FrontMask()
Return a mask holding all technical layers and the external CU layer on front side.
Definition: lset.cpp:895
static LSET BackMask()
Return a mask holding all technical layers and the external CU layer on back side.
Definition: lset.cpp:902
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:67
Definition: pad.h:59
TRACK_DRAG_ACTION m_TrackDragAction
static TOOL_ACTION drag45Degree
Definition: pcb_actions.h:166
static TOOL_ACTION unrouteSelected
Removes all tracks from the selected items to the first pad.
Definition: pcb_actions.h:83
static TOOL_ACTION selectionCursor
Select a single item under the cursor position.
Definition: pcb_actions.h:56
static TOOL_ACTION groupLeave
Definition: pcb_actions.h:478
static TOOL_ACTION grabUnconnected
Select and move nearest unconnected footprint from ratsnest of selection.
Definition: pcb_actions.h:95
static TOOL_ACTION filterSelection
Filter the items in the current selection (invokes dialog)
Definition: pcb_actions.h:107
static TOOL_ACTION highlightNet
Definition: pcb_actions.h:497
static TOOL_ACTION unselectItem
Definition: pcb_actions.h:63
static TOOL_ACTION hideLocalRatsnest
Definition: pcb_actions.h:507
static TOOL_ACTION properties
Activation of the edit tool.
Definition: pcb_actions.h:149
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: pcb_actions.h:59
static TOOL_ACTION selectOnSheetFromEeschema
Select all components on sheet from Eeschema crossprobing.
Definition: pcb_actions.h:98
static TOOL_ACTION selectConnection
Select tracks between junctions or expands an existing selection to pads or the entire connection.
Definition: pcb_actions.h:80
static TOOL_ACTION dragFreeAngle
Definition: pcb_actions.h:167
static TOOL_ACTION clearHighlight
Definition: pcb_actions.h:496
static TOOL_ACTION unselectItems
Definition: pcb_actions.h:67
static TOOL_ACTION selectUnconnected
Select unconnected footprints from ratsnest of selection.
Definition: pcb_actions.h:92
static TOOL_ACTION moveIndividually
move items one-by-one
Definition: pcb_actions.h:113
static TOOL_ACTION syncSelection
Sets selection to specified items, zooms to fit, if enabled.
Definition: pcb_actions.h:70
static TOOL_ACTION groupEnter
Definition: pcb_actions.h:477
static TOOL_ACTION selectItem
Select an item (specified as the event parameter).
Definition: pcb_actions.h:62
static TOOL_ACTION selectSameSheet
Select all components on the same sheet as the selected footprint.
Definition: pcb_actions.h:101
static TOOL_ACTION selectNet
Select all connections belonging to a single net.
Definition: pcb_actions.h:86
static TOOL_ACTION selectionActivate
Activation of the selection tool.
Definition: pcb_actions.h:53
static TOOL_ACTION move
move or drag an item
Definition: pcb_actions.h:110
static TOOL_ACTION syncSelectionWithNets
Sets selection to specified items with connected nets, zooms to fit, if enabled.
Definition: pcb_actions.h:73
static TOOL_ACTION selectItems
Select a list of items (specified as the event parameter)
Definition: pcb_actions.h:66
static TOOL_ACTION deselectNet
Remove all connections belonging to a single net from the active selection.
Definition: pcb_actions.h:89
static TOOL_ACTION selectionMenu
Run a selection menu to select from a list of items.
Definition: pcb_actions.h:76
static TOOL_ACTION selectOnSchematic
Select symbols/pins on schematic corresponding to selected footprints/pads.
Definition: pcb_actions.h:104
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.
void FocusOnItem(BOARD_ITEM *aItem, PCB_LAYER_ID aLayer=UNDEFINED_LAYER)
Object to handle a bitmap image that can be inserted in a PCB.
Definition: pcb_bitmap.h:42
ZONE_DISPLAY_MODE m_ZoneDisplayMode
virtual KIGFX::PCB_VIEW * GetView() const override
Return a pointer to the #VIEW instance used in the panel.
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:276
static bool WithinScope(BOARD_ITEM *aItem, PCB_GROUP *aScope, bool isFootprintEditor)
Definition: pcb_group.cpp:156
static PCB_GROUP * TopLevelGroup(BOARD_ITEM *aItem, PCB_GROUP *aScope, bool isFootprintEditor)
Definition: pcb_group.cpp:150
void RunOnChildren(const std::function< void(BOARD_ITEM *)> &aFunction) const
Invoke a function on all members of the group.
Definition: pcb_group.cpp:407
bool AddItem(BOARD_ITEM *aItem)
Add item to group.
Definition: pcb_group.cpp:80
Tool that displays edit points allowing to modify items by dragging the points.
bool HasPoint()
Indicate the cursor is over an edit point.
Private implementation of firewalled private data.
DIALOG_FILTER_SELECTION::OPTIONS m_filterOpts
The selection tool: currently supports:
void highlight(EDA_ITEM *aItem, int aHighlightMode, SELECTION *aGroup=nullptr) override
Highlight the item visually.
int syncSelectionWithNets(const TOOL_EVENT &aEvent)
int 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)
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
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.
int hitTestDistance(const wxPoint &aWhere, BOARD_ITEM *aItem, int aMaxDistance) const
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 FilterCollectorForFreePads(GENERAL_COLLECTOR &aCollector) const
Check the "allow free pads" setting and if disabled, replace any pads in the collector with their par...
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 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
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)
PCB_SELECTION m_selection
void unhighlight(EDA_ITEM *aItem, int aHighlightMode, SELECTION *aGroup=nullptr) override
Unhighlight the item visually.
const VECTOR2I & GetStart() const
Definition: pcb_track.h:113
const VECTOR2I & GetEnd() const
Definition: pcb_track.h:110
int GetDrill() const
Function GetDrill returns the local drill setting for this PCB_VIA.
Definition: pcb_track.h:522
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)
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:147
bool ToolStackIsEmpty()
Definition: tools_holder.h:128
Represent a single user action.
Definition: tool_action.h:68
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:215
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:82
@ MODEL_RELOAD
Model changes (required full reload)
Definition: tool_base.h:80
Generic, UI-independent tool event.
Definition: tool_event.h:156
T Parameter() const
Return a non-standard parameter assigned to the event.
Definition: tool_event.h:442
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:88
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, bool aNow=false, T aParam=NULL)
Run the specified action.
Definition: tool_manager.h:142
VECTOR2D GetMousePosition() const
KIGFX::VIEW * GetView() const
Definition: tool_manager.h:285
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:57
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
Definition: zone.h:697
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:415
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:422
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: zone.h:122
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.
#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.
@ FRAME_PCB_EDITOR
Definition: frame_type.h:40
@ FRAME_FOOTPRINT_VIEWER_MODAL
Definition: frame_type.h:43
@ FRAME_FOOTPRINT_VIEWER
Definition: frame_type.h:42
@ FRAME_FOOTPRINT_EDITOR
Definition: frame_type.h:41
@ LAYER_MOD_TEXT_INVISIBLE
text marked as invisible
Definition: layer_ids.h:200
@ LAYER_PAD_FR
smd pads, front layer
Definition: layer_ids.h:202
@ LAYER_MOD_TEXT
Definition: layer_ids.h:198
@ LAYER_ZONES
Control for copper zone opacity/visibility (color ignored)
Definition: layer_ids.h:231
@ LAYER_PADS
Meta control for all pads opacity/visibility (color ignored)
Definition: layer_ids.h:230
@ LAYER_TRACKS
Definition: layer_ids.h:212
@ LAYER_MOD_FR
show footprints on front
Definition: layer_ids.h:208
@ LAYER_PAD_BK
smd pads, back layer
Definition: layer_ids.h:203
@ LAYER_MOD_VALUES
show footprints values (when texts are visible)
Definition: layer_ids.h:210
@ LAYER_PADS_TH
multilayer pads, usually with holes
Definition: layer_ids.h:213
@ LAYER_VIAS
Meta control for all vias opacity/visibility.
Definition: layer_ids.h:193
@ LAYER_MOD_BK
show footprints on back
Definition: layer_ids.h:209
@ LAYER_MOD_REFERENCES
show footprints references (when texts are visible)
Definition: layer_ids.h:211
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:59
@ Edge_Cuts
Definition: layer_ids.h:113
@ B_Cu
Definition: layer_ids.h:95
@ F_SilkS
Definition: layer_ids.h:104
@ UNDEFINED_LAYER
Definition: layer_ids.h:60
@ B_SilkS
Definition: layer_ids.h:103
@ F_Cu
Definition: layer_ids.h:64
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition: lset.cpp:932
@ REPAINT
Item needs to be redrawn.
Definition: view_item.h:52
@ TARGET_OVERLAY
Items that may change while the view stays the same (noncached)
Definition: definitions.h:50
Definition: bitmap.cpp:64
@ NPTH
like PAD_PTH, but not plated
@ PTH
Plated through hole pad.
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:34
bool center_on_items
Automatically pan to cross-probed items.
Definition: app_settings.h:33
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:64
@ TC_ANY
Definition: tool_event.h:55
@ MD_ALT
Definition: tool_event.h:140
@ MD_CTRL
Definition: tool_event.h:139
@ MD_SHIFT
Definition: tool_event.h:138
@ BUT_MIDDLE
Definition: tool_event.h:129
@ BUT_LEFT
Definition: tool_event.h:127
@ BUT_RIGHT
Definition: tool_event.h:128
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition: typeinfo.h:78
@ PCB_FP_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
Definition: typeinfo.h:95
@ 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:110
@ PCB_FP_SHAPE_T
class FP_SHAPE, a footprint edge
Definition: typeinfo.h:94
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition: typeinfo.h:107
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:102
@ TYPE_NOT_INIT
Definition: typeinfo.h:81
@ PCB_FP_TEXTBOX_T
class FP_TEXTBOX, wrapped text in a footprint
Definition: typeinfo.h:93
@ PCB_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
Definition: typeinfo.h:108
@ PCB_GROUP_T
class PCB_GROUP, a set of BOARD_ITEMs
Definition: typeinfo.h:115
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
Definition: typeinfo.h:91
@ PCB_ZONE_T
class ZONE, a copper pour area
Definition: typeinfo.h:112
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition: typeinfo.h:90
@ PCB_FP_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
Definition: typeinfo.h:97
@ 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:104
@ PCB_TARGET_T
class PCB_TARGET, a target (graphic item)
Definition: typeinfo.h:111
@ PCB_FP_DIM_ORTHOGONAL_T
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
Definition: typeinfo.h:99
@ PCB_FP_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition: typeinfo.h:96
@ 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:106
@ PCB_FP_ZONE_T
class ZONE, managed by a footprint
Definition: typeinfo.h:100
@ PCB_BITMAP_T
class PCB_BITMAP, bitmap on a layer
Definition: typeinfo.h:89
@ PCB_FP_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
Definition: typeinfo.h:98
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition: typeinfo.h:87
@ PCB_FP_TEXT_T
class FP_TEXT, text in a footprint
Definition: typeinfo.h:92
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition: typeinfo.h:103
@ PCB_NETINFO_T
class NETINFO_ITEM, a description of a net
Definition: typeinfo.h:114
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:101
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
Definition: typeinfo.h:109
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:618