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