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