KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pcb_control.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) 2014-2016 CERN
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 * @author Maciej Suminski <[email protected]>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
22#include "pcb_control.h"
24
25#include <advanced_config.h>
26#include <collectors.h>
27#include <kiplatform/ui.h>
28#include <kiway.h>
29#include <tools/edit_tool.h>
31#include <router/router_tool.h>
32#include <pgm_base.h>
33#include <tools/pcb_actions.h>
38#include <board_commit.h>
39#include <board.h>
41#include <board_item.h>
43#include <clipboard.h>
44#include <design_block.h>
47#include <pcb_dimension.h>
51#include <footprint.h>
53#include <pad.h>
54#include <netinfo.h>
55#include <layer_pairs.h>
56#include <pcb_group.h>
58#include <pcb_reference_image.h>
59#include <pcb_textbox.h>
60#include <pcb_drill_chart.h>
62#include <pcb_drill_map.h>
63#include <pcb_table.h>
64#include <pcb_tablecell.h>
65#include <pcb_track.h>
66#include <pcb_generator.h>
68#include <project_pcb.h>
70#include <filename_resolver.h>
71#include <3d_cache/3d_cache.h>
72#include <embedded_files.h>
73#include <wx/filename.h>
74#include <zone.h>
75#include <confirm.h>
76#include <kidialog.h>
78#include <core/kicad_algo.h>
82#include <kicad_clipboard.h>
83#include <origin_viewitem.h>
84#include <pcb_edit_frame.h>
85#include <pcb_painter.h>
87#include <string>
88#include <tool/tool_manager.h>
96#include <widgets/wx_infobar.h>
97#include <pcb_io/pcb_io.h>
98#include <wx/hyperlink.h>
99
100
101using namespace std::placeholders;
102
103
104// files.cpp
105extern bool AskLoadBoardFileName( PCB_EDIT_FRAME* aParent, wxString* aFileName, int aCtl = 0 );
106
107// board_tables/board_stackup_table.cpp
108extern PCB_TABLE* Build_Board_Stackup_Table( BOARD* aBoard, EDA_UNITS aDisplayUnits );
109// board_tables/board_characteristics_table.cpp
110extern PCB_TABLE* Build_Board_Characteristics_Table( BOARD* aBoard, EDA_UNITS aDisplayUnits );
111
112
114 PCB_TOOL_BASE( "pcbnew.Control" ),
115 m_frame( nullptr ),
116 m_pickerItem( nullptr )
117{
119}
120
121
125
126
128{
130
131 if( aReason == MODEL_RELOAD || aReason == GAL_SWITCH || aReason == REDRAW )
132 {
133 m_gridOrigin->SetPosition( board()->GetDesignSettings().GetGridOrigin() );
134
135 double backgroundBrightness = m_frame->GetCanvas()->GetGAL()->GetClearColor().GetBrightness();
136 COLOR4D color = m_frame->GetGridColor();
137
138 if( backgroundBrightness > 0.5 )
139 color.Darken( 0.25 );
140 else
141 color.Brighten( 0.25 );
142
143 m_gridOrigin->SetColor( color );
144
145 getView()->Remove( m_gridOrigin.get() );
146 getView()->Add( m_gridOrigin.get() );
147 }
148}
149
150
152{
153 if( m_frame->IsType( FRAME_FOOTPRINT_EDITOR ) || m_frame->IsType( FRAME_PCB_EDITOR ) )
154 {
155 if( aEvent.IsAction( &ACTIONS::newLibrary ) )
156 static_cast<PCB_BASE_EDIT_FRAME*>( m_frame )->CreateNewLibrary( _( "New Footprint Library" ) );
157 else if( aEvent.IsAction( &ACTIONS::addLibrary ) )
158 static_cast<PCB_BASE_EDIT_FRAME*>( m_frame )->AddLibrary( _( "Add Footprint Library" ) );
159 }
160
161 return 0;
162}
163
164
166{
167 if( m_frame->IsType( FRAME_FOOTPRINT_EDITOR ) )
168 static_cast<FOOTPRINT_EDIT_FRAME*>( m_frame )->LoadFootprintFromBoard( nullptr );
169
170 return 0;
171}
172
173
175{
176 if( m_frame->IsType( FRAME_FOOTPRINT_EDITOR ) )
177 static_cast<FOOTPRINT_EDIT_FRAME*>( m_frame )->SaveFootprintToBoard( true );
178 else if( m_frame->IsType( FRAME_FOOTPRINT_VIEWER ) )
179 static_cast<FOOTPRINT_VIEWER_FRAME*>( m_frame )->AddFootprintToPCB();
180
181 return 0;
182}
183
184
186{
187 const wxString fn = *aEvent.Parameter<wxString*>();
188 static_cast<PCB_BASE_EDIT_FRAME*>( m_frame )->AddLibrary( _( "Add Footprint Library" ), fn,
190 return 0;
191}
192
193
195{
196 const wxString fn = *aEvent.Parameter<wxString*>();
197 static_cast<FOOTPRINT_EDIT_FRAME*>( m_frame )->ImportFootprint( fn );
198 m_frame->Zoom_Automatique( false );
199 return 0;
200}
201
202
204{
205 if( m_frame->IsType( FRAME_FOOTPRINT_VIEWER ) )
206 static_cast<FOOTPRINT_VIEWER_FRAME*>( m_frame )->SelectAndViewFootprint( aEvent.Parameter<FPVIEWER_CONSTANTS>() );
207
208 return 0;
209}
210
211
212template<class T>
213void Flip( T& aValue )
214{
215 aValue = !aValue;
216}
217
218
220{
221 Flip( displayOptions().m_DisplayPcbTrackFill );
222
223 for( PCB_TRACK* track : board()->Tracks() )
224 {
225 if( track->Type() == PCB_TRACE_T || track->Type() == PCB_ARC_T )
226 view()->Update( track, KIGFX::REPAINT );
227 }
228
229 for( BOARD_ITEM* shape : board()->Drawings() )
230 {
231 if( shape->Type() == PCB_SHAPE_T && static_cast<PCB_SHAPE*>( shape )->IsOnCopperLayer() )
232 view()->Update( shape, KIGFX::REPAINT );
233 }
234
235 canvas()->Refresh();
236
237 return 0;
238}
239
240
242{
243 if( PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame ) )
244 {
245 if( aEvent.IsAction( &PCB_ACTIONS::showRatsnest ) )
246 {
247 // N.B. Do not disable the Ratsnest layer here. We use it for local ratsnest
248 Flip( displayOptions().m_ShowGlobalRatsnest );
249 editFrame->SetElementVisibility( LAYER_RATSNEST, displayOptions().m_ShowGlobalRatsnest );
250 }
251 else if( aEvent.IsAction( &PCB_ACTIONS::ratsnestLineMode ) )
252 {
253 Flip( displayOptions().m_DisplayRatsnestLinesCurved );
254 }
255
256 editFrame->OnDisplayOptionsChanged();
257
259 canvas()->Refresh();
260 }
261
262 return 0;
263}
264
265
267{
268 Flip( displayOptions().m_DisplayViaFill );
269
270 for( PCB_TRACK* track : board()->Tracks() )
271 {
272 if( track->Type() == PCB_VIA_T )
273 view()->Update( track, KIGFX::REPAINT );
274 }
275
276 canvas()->Refresh();
277 return 0;
278}
279
280
287{
288 if( Pgm().GetCommonSettings()->m_DoNotShowAgain.zone_fill_warning )
289 return;
290
291 bool unfilledZones = false;
292
293 for( const ZONE* zone : board()->Zones() )
294 {
295 if( !zone->GetIsRuleArea() && !zone->IsFilled() )
296 {
297 unfilledZones = true;
298 break;
299 }
300 }
301
302 if( unfilledZones )
303 {
304 WX_INFOBAR* infobar = m_frame->GetInfoBar();
305
306 infobar->RemoveAllButtons();
307 infobar->AddLink( _( "Don't show again" ),
308 [&]( wxHyperlinkEvent& aEvent )
309 {
311 m_frame->GetInfoBar()->Dismiss();
312 } );
313
314 wxString msg;
315 msg.Printf( _( "Not all zones are filled. Use Edit > Fill All Zones (%s) if you wish to see all fills." ),
317
318 infobar->ShowMessageFor( msg, 5000, wxICON_WARNING );
319 }
320}
321
322
324{
325 PCB_DISPLAY_OPTIONS opts = m_frame->GetDisplayOptions();
326
327 // Apply new display options to the GAL canvas
329 {
331
333 }
334 else if( aEvent.IsAction( &PCB_ACTIONS::zoneDisplayOutline ) )
335 {
337 }
338 else if( aEvent.IsAction( &PCB_ACTIONS::zoneDisplayFractured ) )
339 {
341 }
343 {
345 }
346 else if( aEvent.IsAction( &PCB_ACTIONS::zoneDisplayToggle ) )
347 {
350 else
352 }
353 else
354 {
355 wxFAIL;
356 }
357
358 m_frame->SetDisplayOptions( opts );
359
360 for( ZONE* zone : board()->Zones() )
361 view()->Update( zone, KIGFX::REPAINT );
362
363 canvas()->Refresh();
364
365 return 0;
366}
367
368
370{
371 PCB_DISPLAY_OPTIONS opts = m_frame->GetDisplayOptions();
372
375
376 m_frame->SetDisplayOptions( opts );
377 return 0;
378}
379
380
382{
383 PCB_DISPLAY_OPTIONS opts = m_frame->GetDisplayOptions();
384
385 switch( opts.m_ContrastModeDisplay )
386 {
390 }
391
392 m_frame->SetDisplayOptions( opts );
393
395 return 0;
396}
397
398
400{
401 if( !Pgm().GetCommonSettings()->m_Input.hotkey_feedback )
402 return 0;
403
404 PCB_DISPLAY_OPTIONS opts = m_frame->GetDisplayOptions();
405
406 wxArrayString labels;
407 labels.Add( _( "Normal" ) );
408 labels.Add( _( "Dimmed" ) );
409 labels.Add( _( "Hidden" ) );
410
411 if( !m_frame->GetHotkeyPopup() )
412 m_frame->CreateHotkeyPopup();
413
414 HOTKEY_CYCLE_POPUP* popup = m_frame->GetHotkeyPopup();
415
416 if( popup )
417 {
418 popup->Popup( _( "Inactive Layer Display" ), labels, static_cast<int>( opts.m_ContrastModeDisplay ) );
419 }
420
421 return 0;
422}
423
424
426{
427 PCB_DISPLAY_OPTIONS opts = m_frame->GetDisplayOptions();
428
429 switch( opts.m_NetColorMode )
430 {
434 }
435
436 m_frame->SetDisplayOptions( opts );
437 return 0;
438}
439
440
442{
443 if( PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame ) )
444 {
445 if( !displayOptions().m_ShowGlobalRatsnest )
446 {
449 }
450 else if( displayOptions().m_RatsnestMode == RATSNEST_MODE::ALL )
451 {
453 }
454 else
455 {
457 }
458
459 editFrame->SetElementVisibility( LAYER_RATSNEST, displayOptions().m_ShowGlobalRatsnest );
460
461 editFrame->OnDisplayOptionsChanged();
462
464 canvas()->Refresh();
465 }
466
467 return 0;
468}
469
470
472{
473 m_frame->SwitchLayer( aEvent.Parameter<PCB_LAYER_ID>() );
474
475 return 0;
476}
477
478
480{
481 BOARD* brd = board();
482 PCB_LAYER_ID layer = m_frame->GetActiveLayer();
483 bool wraparound = false;
484
485 if( !IsCopperLayer( layer ) )
486 {
487 m_frame->SwitchLayer( B_Cu );
488 return 0;
489 }
490
491 LSET cuMask = LSET::AllCuMask( brd->GetCopperLayerCount() );
492 LSEQ layerStack = cuMask.UIOrder();
493
494 int ii = 0;
495
496 // Find the active layer in list
497 for( ; ii < (int) layerStack.size(); ii++ )
498 {
499 if( layer == layerStack[ii] )
500 break;
501 }
502
503 // Find the next visible layer in list
504 for( ; ii < (int) layerStack.size(); ii++ )
505 {
506 int jj = ii + 1;
507
508 if( jj >= (int) layerStack.size() )
509 jj = 0;
510
511 layer = layerStack[jj];
512
513 if( brd->IsLayerVisible( layer ) )
514 break;
515
516 if( jj == 0 ) // the end of list is reached. Try from the beginning
517 {
518 if( wraparound )
519 {
520 wxBell();
521 return 0;
522 }
523 else
524 {
525 wraparound = true;
526 ii = -1;
527 }
528 }
529 }
530
531 wxCHECK( IsCopperLayer( layer ), 0 );
532 m_frame->SwitchLayer( layer );
533
534 return 0;
535}
536
537
539{
540 BOARD* brd = board();
541 PCB_LAYER_ID layer = m_frame->GetActiveLayer();
542 bool wraparound = false;
543
544 if( !IsCopperLayer( layer ) )
545 {
546 m_frame->SwitchLayer( F_Cu );
547 return 0;
548 }
549
550 LSET cuMask = LSET::AllCuMask( brd->GetCopperLayerCount() );
551 LSEQ layerStack = cuMask.UIOrder();
552
553 int ii = 0;
554
555 // Find the active layer in list
556 for( ; ii < (int) layerStack.size(); ii++ )
557 {
558 if( layer == layerStack[ii] )
559 break;
560 }
561
562 // Find the previous visible layer in list
563 for( ; ii >= 0; ii-- )
564 {
565 int jj = ii - 1;
566
567 if( jj < 0 )
568 jj = (int) layerStack.size() - 1;
569
570 layer = layerStack[jj];
571
572 if( brd->IsLayerVisible( layer ) )
573 break;
574
575 if( ii == 0 ) // the start of list is reached. Try from the last
576 {
577 if( wraparound )
578 {
579 wxBell();
580 return 0;
581 }
582 else
583 {
584 wraparound = true;
585 ii = 1;
586 }
587 }
588 }
589
590 wxCHECK( IsCopperLayer( layer ), 0 );
591 m_frame->SwitchLayer( layer );
592
593 return 0;
594}
595
596
598{
599 int currentLayer = m_frame->GetActiveLayer();
600 PCB_SCREEN* screen = m_frame->GetScreen();
601
602 if( currentLayer == screen->m_Route_Layer_TOP )
603 m_frame->SwitchLayer( screen->m_Route_Layer_BOTTOM );
604 else
605 m_frame->SwitchLayer( screen->m_Route_Layer_TOP );
606
607 return 0;
608}
609
610
611// It'd be nice to share the min/max with the DIALOG_COLOR_PICKER, but those are
612// set in wxFormBuilder.
613#define ALPHA_MIN 0.20
614#define ALPHA_MAX 1.00
615#define ALPHA_STEP 0.05
616
617
619{
620 COLOR_SETTINGS* settings = m_frame->GetColorSettings();
621 int currentLayer = m_frame->GetActiveLayer();
622 KIGFX::COLOR4D currentColor = settings->GetColor( currentLayer );
623
624 if( currentColor.a <= ALPHA_MAX - ALPHA_STEP )
625 {
626 currentColor.a += ALPHA_STEP;
627 settings->SetColor( currentLayer, currentColor );
628 m_frame->GetCanvas()->UpdateColors();
629
630 KIGFX::VIEW* view = m_frame->GetCanvas()->GetView();
631 view->UpdateLayerColor( currentLayer );
632 view->UpdateLayerColor( GetNetnameLayer( currentLayer ) );
633
634 if( IsCopperLayer( currentLayer ) )
635 view->UpdateLayerColor( ZONE_LAYER_FOR( currentLayer ) );
636
637 m_frame->GetCanvas()->ForceRefresh();
638 }
639 else
640 {
641 wxBell();
642 }
643
644 return 0;
645}
646
647
649{
650 COLOR_SETTINGS* settings = m_frame->GetColorSettings();
651 int currentLayer = m_frame->GetActiveLayer();
652 KIGFX::COLOR4D currentColor = settings->GetColor( currentLayer );
653
654 if( currentColor.a >= ALPHA_MIN + ALPHA_STEP )
655 {
656 currentColor.a -= ALPHA_STEP;
657 settings->SetColor( currentLayer, currentColor );
658 m_frame->GetCanvas()->UpdateColors();
659
660 KIGFX::VIEW* view = m_frame->GetCanvas()->GetView();
661 view->UpdateLayerColor( currentLayer );
662 view->UpdateLayerColor( GetNetnameLayer( currentLayer ) );
663
664 if( IsCopperLayer( currentLayer ) )
665 view->UpdateLayerColor( ZONE_LAYER_FOR( currentLayer ) );
666
667 m_frame->GetCanvas()->ForceRefresh();
668 }
669 else
670 {
671 wxBell();
672 }
673
674 return 0;
675}
676
677
679{
680 if( PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame ) )
681 {
682 LAYER_PAIR_SETTINGS* settings = editFrame->GetLayerPairSettings();
683
684 if( !settings )
685 return 0;
686
687 int currentIndex;
688 std::vector<LAYER_PAIR_INFO> presets = settings->GetEnabledLayerPairs( currentIndex );
689
690 if( presets.size() < 2 )
691 return 0;
692
693 if( currentIndex < 0 )
694 {
695 wxASSERT_MSG( false, "Current layer pair not found in layer settings" );
696 currentIndex = 0;
697 }
698
699 const int nextIndex = ( currentIndex + 1 ) % presets.size();
700 const LAYER_PAIR& nextPair = presets[nextIndex].GetLayerPair();
701
702 settings->SetCurrentLayerPair( nextPair );
703
705 }
706
707 return 0;
708}
709
710
712{
713 if( !Pgm().GetCommonSettings()->m_Input.hotkey_feedback )
714 return 0;
715
716 if( PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame ) )
717 {
718 LAYER_PAIR_SETTINGS* settings = editFrame->GetLayerPairSettings();
719
720 if( !settings )
721 return 0;
722
723 PCB_LAYER_PRESENTATION layerPresentation( editFrame );
724
725 int currentIndex;
726 std::vector<LAYER_PAIR_INFO> presets = settings->GetEnabledLayerPairs( currentIndex );
727
728 wxArrayString labels;
729 for( const LAYER_PAIR_INFO& layerPairInfo : presets )
730 {
731 wxString label = layerPresentation.getLayerPairName( layerPairInfo.GetLayerPair() );
732
733 if( layerPairInfo.GetName() )
734 label += wxT( " (" ) + *layerPairInfo.GetName() + wxT( ")" );
735
736 labels.Add( label );
737 }
738
739 if( !editFrame->GetHotkeyPopup() )
740 editFrame->CreateHotkeyPopup();
741
742 HOTKEY_CYCLE_POPUP* popup = editFrame->GetHotkeyPopup();
743
744 if( popup )
745 {
746 int selection = currentIndex;
747 popup->Popup( _( "Preset Layer Pairs" ), labels, selection );
748 }
749 }
750
751 return 0;
752}
753
754
756 const VECTOR2D& aPoint )
757{
758 aFrame->GetDesignSettings().SetGridOrigin( VECTOR2I( aPoint ) );
759 aView->GetGAL()->SetGridOrigin( aPoint );
760 originViewItem->SetPosition( aPoint );
761 aView->MarkDirty();
762 aFrame->OnModify();
763}
764
765
767{
768 VECTOR2D* origin = aEvent.Parameter<VECTOR2D*>();
769
770 if( origin )
771 {
772 // We can't undo the other grid dialog settings, so no sense undoing just the origin
773 DoSetGridOrigin( getView(), m_frame, m_gridOrigin.get(), *origin );
774 delete origin;
775 }
776 else
777 {
779 return 0;
780
781 PCB_PICKER_TOOL* picker = m_toolMgr->GetTool<PCB_PICKER_TOOL>();
782
783 if( !picker ) // Happens in footprint wizard
784 return 0;
785
786 // Deactivate other tools; particularly important if another PICKER is currently running
787 Activate();
788
789 picker->SetCursor( KICURSOR::PLACE );
790 picker->ClearHandlers();
791
792 picker->SetClickHandler(
793 [this]( const VECTOR2D& pt ) -> bool
794 {
795 m_frame->SaveCopyInUndoList( m_gridOrigin.get(), UNDO_REDO::GRIDORIGIN );
797 return false; // drill origin is a one-shot; don't continue with tool
798 } );
799
800 m_toolMgr->RunAction( ACTIONS::pickerTool, &aEvent );
801 }
802
803 return 0;
804}
805
806
808{
809 m_frame->SaveCopyInUndoList( m_gridOrigin.get(), UNDO_REDO::GRIDORIGIN );
811 return 0;
812}
813
814
815#define HITTEST_THRESHOLD_PIXELS 5
816
817
819{
820 if( m_isFootprintEditor && !m_frame->GetBoard()->GetFirstFootprint() )
821 return 0;
822
823 PCB_PICKER_TOOL* picker = m_toolMgr->GetTool<PCB_PICKER_TOOL>();
824
825 m_pickerItem = nullptr;
827
828 // Deactivate other tools; particularly important if another PICKER is currently running
829 Activate();
830
831 picker->SetCursor( KICURSOR::REMOVE );
832 picker->SetSnapping( false );
833 picker->ClearHandlers();
834
835 picker->SetClickHandler(
836 [this]( const VECTOR2D& aPosition ) -> bool
837 {
838 if( m_pickerItem )
839 {
840 if( m_pickerItem && m_pickerItem->IsLocked() )
841 {
843 m_statusPopup->SetText( _( "Item locked." ) );
844 m_statusPopup->PopupFor( 2000 );
845 m_statusPopup->Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, 20 ) );
846 return true;
847 }
848
849 PCB_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
850 selectionTool->UnbrightenItem( m_pickerItem );
851
852 PCB_SELECTION items;
853 items.Add( m_pickerItem );
854
855 EDIT_TOOL* editTool = m_toolMgr->GetTool<EDIT_TOOL>();
856 editTool->DeleteItems( items, false );
857
858 m_pickerItem = nullptr;
859 }
860
861 return true;
862 } );
863
864 picker->SetMotionHandler(
865 [this]( const VECTOR2D& aPos )
866 {
867 BOARD* board = m_frame->GetBoard();
868 PCB_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
869 GENERAL_COLLECTORS_GUIDE guide = m_frame->GetCollectorsGuide();
870 GENERAL_COLLECTOR collector;
871 collector.m_Threshold = KiROUND( getView()->ToWorld( HITTEST_THRESHOLD_PIXELS ) );
872
874 collector.Collect( board, GENERAL_COLLECTOR::FootprintItems, aPos, guide );
875 else
876 collector.Collect( board, GENERAL_COLLECTOR::BoardLevelItems, aPos, guide );
877
878 // Remove unselectable items
879 for( int i = collector.GetCount() - 1; i >= 0; --i )
880 {
881 if( !selectionTool->Selectable( collector[i] ) )
882 collector.Remove( i );
883 }
884
885 selectionTool->FilterCollectorForHierarchy( collector, false );
886 selectionTool->FilterCollectedItems( collector, false, nullptr );
887
888 if( collector.GetCount() > 1 )
889 selectionTool->GuessSelectionCandidates( collector, aPos );
890
891 BOARD_ITEM* item = collector.GetCount() == 1 ? collector[0] : nullptr;
892
893 if( m_pickerItem != item )
894 {
895 if( m_pickerItem )
896 selectionTool->UnbrightenItem( m_pickerItem );
897
898 m_pickerItem = item;
899
900 if( m_pickerItem )
901 selectionTool->BrightenItem( m_pickerItem );
902 }
903 } );
904
905 picker->SetFinalizeHandler(
906 [this]( const int& aFinalState )
907 {
908 if( m_pickerItem )
909 m_toolMgr->GetTool<PCB_SELECTION_TOOL>()->UnbrightenItem( m_pickerItem );
910
911 m_statusPopup.reset();
912
913 // Ensure the cursor gets changed&updated
914 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
915 m_frame->GetCanvas()->Refresh();
916 } );
917
918 m_toolMgr->RunAction( ACTIONS::pickerTool, &aEvent );
919
920 return 0;
921}
922
923
924static void pasteFootprintItemsToFootprintEditor( FOOTPRINT* aClipFootprint, BOARD* aBoard,
925 std::vector<BOARD_ITEM*>& aPastedItems )
926{
927 FOOTPRINT* editorFootprint = aBoard->GetFirstFootprint();
928
929 aClipFootprint->SetParent( aBoard );
930
931 for( PAD* pad : aClipFootprint->Pads() )
932 {
933 pad->SetParent( editorFootprint );
934 aPastedItems.push_back( pad );
935 }
936
937 aClipFootprint->Pads().clear();
938
939 // Not all items can be added to the current footprint: mandatory fields are already existing
940 // in the current footprint.
941 //
942 for( PCB_FIELD* field : aClipFootprint->GetFields() )
943 {
944 wxCHECK2( field, continue );
945
946 if( field->IsMandatory() )
947 {
948 if( EDA_GROUP* parentGroup = field->GetParentGroup() )
949 parentGroup->RemoveItem( field );
950 }
951 else
952 {
953 PCB_TEXT* text = static_cast<PCB_TEXT*>( field );
954
955 text->SetTextAngle( text->GetTextAngle() - aClipFootprint->GetOrientation() );
956 text->SetTextAngle( text->GetTextAngle() + editorFootprint->GetOrientation() );
957
958 VECTOR2I pos = field->GetFPRelativePosition();
959 field->SetParent( editorFootprint );
960 field->SetFPRelativePosition( pos );
961
962 aPastedItems.push_back( field );
963 }
964 }
965
966 aClipFootprint->GetFields().clear();
967
968 for( BOARD_ITEM* item : aClipFootprint->GraphicalItems() )
969 {
970 if( item->Type() == PCB_TEXT_T )
971 {
972 PCB_TEXT* text = static_cast<PCB_TEXT*>( item );
973
974 text->SetTextAngle( text->GetTextAngle() - aClipFootprint->GetOrientation() );
975 text->SetTextAngle( text->GetTextAngle() + editorFootprint->GetOrientation() );
976 }
977
978 item->Rotate( item->GetPosition(), -aClipFootprint->GetOrientation() );
979 item->Rotate( item->GetPosition(), editorFootprint->GetOrientation() );
980
981 VECTOR2I pos = item->GetFPRelativePosition();
982 item->SetParent( editorFootprint );
983 item->SetFPRelativePosition( pos );
984
985 aPastedItems.push_back( item );
986 }
987
988 aClipFootprint->GraphicalItems().clear();
989
990 for( ZONE* zone : aClipFootprint->Zones() )
991 {
992 zone->SetParent( editorFootprint );
993 aPastedItems.push_back( zone );
994 }
995
996 aClipFootprint->Zones().clear();
997
998 for( PCB_GROUP* group : aClipFootprint->Groups() )
999 {
1000 group->SetParent( editorFootprint );
1001 aPastedItems.push_back( group );
1002 }
1003
1004 aClipFootprint->Groups().clear();
1005
1006 // Constraints ride along like the other containers; the KIID remap in placeBoardItems points
1007 // their members at the pasted copies.
1008 for( PCB_CONSTRAINT* constraint : aClipFootprint->Constraints() )
1009 {
1010 constraint->SetParent( editorFootprint );
1011 aPastedItems.push_back( constraint );
1012 }
1013
1014 aClipFootprint->Constraints().clear();
1015}
1016
1017
1018void PCB_CONTROL::pruneItemLayers( std::vector<BOARD_ITEM*>& aItems )
1019{
1020 // Do not prune items or layers when copying to the FP editor, because all
1021 // layers are accepted, even if they are not enabled in the dummy board
1022 // This is mainly true for internal copper layers: all are allowed but only one
1023 // (In1.cu) is enabled for the GUI.
1025 return;
1026
1027 LSET enabledLayers = board()->GetEnabledLayers();
1028 const int copperLayers = board()->GetCopperLayerCount();
1029 std::vector<BOARD_ITEM*> returnItems;
1030
1031 for( BOARD_ITEM* item : aItems )
1032 {
1033 if( !item->FitsEnabledLayers( enabledLayers, copperLayers ) )
1034 {
1035 if( EDA_GROUP* parentGroup = item->GetParentGroup() )
1036 parentGroup->RemoveItem( item );
1037
1038 continue;
1039 }
1040
1041 // Confine a kept item to the layers this board has; a layer-agnostic one has none to confine
1042 if( !item->IsLayerAgnostic() )
1043 item->SetLayerSet( item->GetLayerSet() & enabledLayers );
1044
1045 returnItems.push_back( item );
1046 }
1047
1048 if( returnItems.size() < aItems.size() )
1049 {
1050 DisplayError( m_frame, _( "Warning: some pasted items were on layers which are not "
1051 "present in the current board.\n"
1052 "These items could not be pasted.\n" ) );
1053 }
1054
1055 aItems = returnItems;
1056}
1057
1058
1059int PCB_CONTROL::Paste( const TOOL_EVENT& aEvent )
1060{
1061 // The viewer frames cannot paste
1062 if( !m_frame->IsType( FRAME_FOOTPRINT_EDITOR ) && !m_frame->IsType( FRAME_PCB_EDITOR ) )
1063 return 0;
1064
1065 bool isFootprintEditor = m_isFootprintEditor || m_frame->IsType( FRAME_FOOTPRINT_EDITOR );
1066
1067 // The clipboard can contain two different things, an entire kicad_pcb or a single footprint
1068 if( isFootprintEditor && ( !board() || !footprint() ) )
1069 return 0;
1070
1071 // We should never get here if a modal dialog is up... but we do on MacOS.
1072 // https://gitlab.com/kicad/code/kicad/-/issues/18912
1073#ifdef __WXMAC__
1074 if( wxDialog::OSXHasModalDialogsOpen() )
1075 {
1076 wxBell();
1077 return 0;
1078 }
1079#endif
1080
1081 BOARD_COMMIT commit( m_frame );
1082
1083 CLIPBOARD_IO pi;
1084 BOARD_ITEM* clipItem = pi.Parse();
1085
1086 PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
1087
1088 if( selTool && clipItem )
1089 {
1090 PCB_SELECTION& selection = selTool->GetSelection();
1091
1092 bool hasTableCells = false;
1093
1094 for( EDA_ITEM* item : selection )
1095 {
1096 if( item->Type() == PCB_TABLECELL_T )
1097 {
1098 hasTableCells = true;
1099 break;
1100 }
1101 }
1102
1103 if( hasTableCells )
1104 {
1105 PCB_TABLE* clipboardTable = nullptr;
1106
1107 if( clipItem->Type() == PCB_T )
1108 {
1109 BOARD* clipBoard = static_cast<BOARD*>( clipItem );
1110
1111 for( BOARD_ITEM* item : clipBoard->Drawings() )
1112 {
1113 if( item->Type() == PCB_TABLE_T )
1114 {
1115 clipboardTable = static_cast<PCB_TABLE*>( item );
1116 break;
1117 }
1118 }
1119 }
1120
1121 if( clipboardTable )
1122 {
1123 PCB_EDIT_TABLE_TOOL* tableEditTool = m_toolMgr->GetTool<PCB_EDIT_TABLE_TOOL>();
1124
1125 if( tableEditTool )
1126 {
1127 wxString errorMsg;
1128
1129 if( !tableEditTool->validatePasteIntoSelection( selection, errorMsg ) )
1130 {
1131 DisplayError( m_frame, errorMsg );
1132 return 0;
1133 }
1134
1135 if( tableEditTool->pasteCellsIntoSelection( selection, clipboardTable, commit ) )
1136 {
1137 commit.Push( _( "Paste Cells" ) );
1138 return 0;
1139 }
1140 else
1141 {
1142 DisplayError( m_frame, _( "Failed to paste cells" ) );
1143 return 0;
1144 }
1145 }
1146 }
1147 }
1148 }
1149
1150 if( !clipItem )
1151 {
1152 // When the clipboard doesn't parse, create a PCB item with the clipboard contents
1153 std::vector<BOARD_ITEM*> newItems;
1154
1155 if( std::unique_ptr<wxBitmap> clipImg = GetImageFromClipboard() )
1156 {
1157 auto refImg = std::make_unique<PCB_REFERENCE_IMAGE>( m_frame->GetModel() );
1158
1159 if( refImg->GetReferenceImage().SetImage( clipImg->ConvertToImage() ) )
1160 newItems.push_back( refImg.release() );
1161 }
1162 else
1163 {
1164 const wxString clipText = GetClipboardUTF8();
1165
1166 if( clipText.empty() )
1167 return 0;
1168
1169 // If it wasn't content, then paste as a text object.
1170 if( clipText.size() > static_cast<size_t>( ADVANCED_CFG::GetCfg().m_MaxPastedTextLength ) )
1171 {
1172 int result = IsOK( m_frame, _( "Pasting a long text text string may be very slow. "
1173 "Do you want to continue?" ) );
1174 if( !result )
1175 return 0;
1176 }
1177
1178 std::unique_ptr<PCB_TEXT> item = std::make_unique<PCB_TEXT>( m_frame->GetModel() );
1179 item->SetText( clipText );
1180 item->SetLayer( m_frame->GetActiveLayer() );
1181
1182 newItems.push_back( item.release() );
1183 }
1184
1185 bool cancelled = !placeBoardItems( &commit, newItems, true, false, false, false );
1186
1187 if( cancelled )
1188 commit.Revert();
1189 else
1190 commit.Push( _( "Paste Text" ) );
1191 return 0;
1192 }
1193
1194 // If we get here, we have a parsed board/FP to paste
1195
1197 bool clear_nets = false;
1198 const wxString defaultRef = wxT( "REF**" );
1199
1200 if( aEvent.IsAction( &ACTIONS::pasteSpecial ) )
1201 {
1202 DIALOG_PASTE_SPECIAL dlg( m_frame, &mode, defaultRef );
1203
1204 if( clipItem->Type() != PCB_T )
1205 dlg.HideClearNets();
1206
1207 if( dlg.ShowModal() == wxID_CANCEL )
1208 return 0;
1209
1210 clear_nets = dlg.GetClearNets();
1211 }
1212
1213 if( clipItem->Type() == PCB_T )
1214 {
1215 BOARD* clipBoard = static_cast<BOARD*>( clipItem );
1216
1217 if( isFootprintEditor || clear_nets )
1218 {
1219 for( BOARD_CONNECTED_ITEM* item : clipBoard->AllConnectedItems() )
1220 item->SetNet( NETINFO_LIST::OrphanedItem() );
1221 }
1222 else
1223 {
1224 clipBoard->MapNets( m_frame->GetBoard() );
1225 }
1226 }
1227
1228 bool cancelled = false;
1229
1230 switch( clipItem->Type() )
1231 {
1232 case PCB_T:
1233 {
1234 BOARD* clipBoard = static_cast<BOARD*>( clipItem );
1235
1236 if( isFootprintEditor )
1237 {
1238 FOOTPRINT* editorFootprint = board()->GetFirstFootprint();
1239 std::vector<BOARD_ITEM*> pastedItems;
1240
1241 for( PCB_GROUP* group : clipBoard->Groups() )
1242 {
1243 group->SetParent( editorFootprint );
1244 pastedItems.push_back( group );
1245 }
1246
1247 clipBoard->RemoveAll( { PCB_GROUP_T } );
1248
1249 for( FOOTPRINT* clipFootprint : clipBoard->Footprints() )
1250 pasteFootprintItemsToFootprintEditor( clipFootprint, board(), pastedItems );
1251
1252 for( BOARD_ITEM* clipDrawItem : clipBoard->Drawings() )
1253 {
1254 switch( clipDrawItem->Type() )
1255 {
1256 case PCB_TEXT_T:
1257 case PCB_TEXTBOX_T:
1258 case PCB_TABLE_T:
1259 case PCB_DRILL_CHART_T:
1260 case PCB_SHAPE_T:
1261 case PCB_BARCODE_T:
1262 case PCB_DIM_ALIGNED_T:
1263 case PCB_DIM_CENTER_T:
1264 case PCB_DIM_LEADER_T:
1266 case PCB_DIM_RADIAL_T:
1267 case PCB_POINT_T:
1268 clipDrawItem->SetParent( editorFootprint );
1269 pastedItems.push_back( clipDrawItem );
1270 break;
1271
1272 default:
1273 // Everything we *didn't* put into pastedItems is going to get nuked, so
1274 // make sure it's not still included in its parent group.
1275 if( EDA_GROUP* parentGroup = clipDrawItem->GetParentGroup() )
1276 parentGroup->RemoveItem( clipDrawItem );
1277
1278 break;
1279 }
1280 }
1281
1282 // Board-scoped constraints ride along like the footprint-scoped ones above, so a
1283 // constrained sketch keeps its relations when pasted into a footprint. The clipboard
1284 // only carries a constraint whose every member was copied, and placeBoardItems repoints
1285 // those members at the pasted copies.
1286 for( PCB_CONSTRAINT* constraint : clipBoard->Constraints() )
1287 {
1288 constraint->SetParent( editorFootprint );
1289 pastedItems.push_back( constraint );
1290 }
1291
1292 // NB: PCB_SHAPE_T actually removes everything in Drawings() (including PCB_TEXTs,
1293 // PCB_TABLEs, PCB_BARCODEs, dimensions, etc.), not just PCB_SHAPEs.)
1294 clipBoard->RemoveAll( { PCB_SHAPE_T, PCB_CONSTRAINT_T } );
1295
1296 clipBoard->Visit(
1297 [&]( EDA_ITEM* item, void* testData )
1298 {
1299 if( item->IsBOARD_ITEM() )
1300 {
1301 // Anything still on the clipboard didn't get copied and needs to be
1302 // removed from the pasted groups.
1303 BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( item );
1304 EDA_GROUP* parentGroup = boardItem->GetParentGroup();
1305
1306 if( parentGroup )
1307 parentGroup->RemoveItem( boardItem );
1308 }
1309
1311 },
1313
1314 delete clipBoard;
1315
1316 pruneItemLayers( pastedItems );
1317
1318 cancelled = !placeBoardItems( &commit, pastedItems, true, true, mode == PASTE_MODE::UNIQUE_ANNOTATIONS,
1319 false );
1320 }
1321 else // isBoardEditor
1322 {
1323 // Fixup footprint component classes
1324 for( FOOTPRINT* fp : clipBoard->Footprints() )
1325 {
1326 fp->ResolveComponentClassNames( board(), fp->GetTransientComponentClassNames() );
1327 fp->ClearTransientComponentClassNames();
1328 }
1329
1330 if( mode == PASTE_MODE::REMOVE_ANNOTATIONS )
1331 {
1332 for( FOOTPRINT* fp : clipBoard->Footprints() )
1333 fp->SetReference( defaultRef );
1334 }
1335
1336 cancelled = !placeBoardItems( &commit, clipBoard, true, mode == PASTE_MODE::UNIQUE_ANNOTATIONS, false );
1337 }
1338
1339 break;
1340 }
1341
1342 case PCB_FOOTPRINT_T:
1343 {
1344 FOOTPRINT* clipFootprint = static_cast<FOOTPRINT*>( clipItem );
1345 std::vector<BOARD_ITEM*> pastedItems;
1346
1347 if( isFootprintEditor )
1348 {
1349 pasteFootprintItemsToFootprintEditor( clipFootprint, board(), pastedItems );
1350 delete clipFootprint;
1351 }
1352 else
1353 {
1354 if( mode == PASTE_MODE::REMOVE_ANNOTATIONS )
1355 clipFootprint->SetReference( defaultRef );
1356
1357 clipFootprint->SetParent( board() );
1358 clipFootprint->ResolveComponentClassNames( board(), clipFootprint->GetTransientComponentClassNames() );
1359 clipFootprint->ClearTransientComponentClassNames();
1360 pastedItems.push_back( clipFootprint );
1361 }
1362
1363 pruneItemLayers( pastedItems );
1364
1365 cancelled = !placeBoardItems( &commit, pastedItems, true, true, mode == PASTE_MODE::UNIQUE_ANNOTATIONS, false );
1366 break;
1367 }
1368
1369 default:
1370 m_frame->DisplayToolMsg( _( "Invalid clipboard contents" ) );
1371 break;
1372 }
1373
1374 if( cancelled )
1375 commit.Revert();
1376 else
1377 commit.Push( _( "Paste" ) );
1378
1379 return 1;
1380}
1381
1382
1384{
1385 wxString fileName;
1386
1387 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
1388
1389 if( !editFrame )
1390 return 1;
1391
1392 // Pick a file to append
1393 if( !AskLoadBoardFileName( editFrame, &fileName, KICTL_KICAD_ONLY ) )
1394 return 1;
1395
1397 IO_RELEASER<PCB_IO> pi( PCB_IO_MGR::FindPlugin( pluginType ) );
1398
1399 if( !pi )
1400 return 1;
1401
1402 return AppendBoard( *pi, fileName );
1403}
1404
1405
1407{
1408 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
1409
1410 if( !editFrame )
1411 return 1;
1412
1413 if( !editFrame->GetDesignBlockPane()->GetSelectedLibId().IsValid() )
1414 return 1;
1415
1416 DESIGN_BLOCK_PANE* designBlockPane = editFrame->GetDesignBlockPane();
1417 const LIB_ID selectedLibId = designBlockPane->GetSelectedLibId();
1418 std::unique_ptr<DESIGN_BLOCK> designBlock( designBlockPane->GetDesignBlock( selectedLibId, true, true ) );
1419
1420 if( !designBlock )
1421 return 1;
1422
1423 if( designBlock->GetBoardFile().IsEmpty() || !wxFileName::FileExists( designBlock->GetBoardFile() ) )
1424 {
1425 editFrame->ShowInfoBarError( _( "Design block has no layout to place." ), true );
1426 return 1;
1427 }
1428
1430 IO_RELEASER<PCB_IO> pi( PCB_IO_MGR::FindPlugin( pluginType ) );
1431
1432 if( !pi )
1433 return 1;
1434
1435 bool repeatPlacement = false;
1436
1437 if( APP_SETTINGS_BASE* cfg = editFrame->config() )
1438 repeatPlacement = cfg->m_DesignBlockChooserPanel.repeated_placement;
1439
1440 int ret = 0;
1441
1442 do
1443 {
1444 ret = AppendBoard( *pi, designBlock->GetBoardFile(), designBlock.get() );
1445 } while( repeatPlacement && ret == 0 );
1446
1447 return ret;
1448}
1449
1451{
1452 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
1453
1454 if( !editFrame )
1455 return 1;
1456
1457 BOARD* brd = board();
1458
1459 if( !brd )
1460 return 1;
1461
1462 PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
1464
1465 std::vector<PCB_GROUP*> linkedGroups;
1466 int skippedNoLink = 0;
1467
1468 for( EDA_ITEM* item : selection )
1469 {
1470 if( item->Type() != PCB_GROUP_T )
1471 continue;
1472
1473 PCB_GROUP* g = static_cast<PCB_GROUP*>( item );
1474
1475 if( g->HasDesignBlockLink() )
1476 linkedGroups.push_back( g );
1477 else
1478 skippedNoLink++;
1479 }
1480
1481 if( linkedGroups.empty() )
1482 {
1483 m_frame->ShowInfoBarError( _( "No groups with a linked design block are selected." ), true );
1484 return 1;
1485 }
1486
1487 if( !editFrame->GetOverrideLocks() )
1488 {
1489 bool hasLocked = false;
1490
1491 for( PCB_GROUP* g : linkedGroups )
1492 {
1493 for( EDA_ITEM* item : g->GetItems() )
1494 {
1495 if( item->Type() == PCB_FOOTPRINT_T && static_cast<FOOTPRINT*>( item )->IsLocked() )
1496 {
1497 hasLocked = true;
1498 break;
1499 }
1500 }
1501
1502 if( hasLocked )
1503 break;
1504 }
1505
1506 if( hasLocked )
1507 {
1508 m_frame->ShowInfoBarWarning( _( "Selection contains locked items. "
1509 "Enable 'Override locks' to operate on them." ),
1510 true );
1511 return 1;
1512 }
1513 }
1514
1516 BOARD_COMMIT sharedCommit( m_frame );
1517
1518 struct Failure
1519 {
1521 wxString reason;
1522 };
1523 std::vector<Failure> failures;
1524 int applied = 0;
1525 bool cancelled = false;
1526 bool netlessCopperPlaced = false;
1527
1528 std::unique_ptr<WX_PROGRESS_REPORTER> progress;
1529
1530 if( linkedGroups.size() > 1 && Pgm().IsGUI() )
1531 {
1532 progress = std::make_unique<WX_PROGRESS_REPORTER>( m_frame, _( "Applying Design Block Layouts" ),
1533 (int) linkedGroups.size(), PR_CAN_ABORT );
1534 }
1535
1536 auto generateBoundingBox = []( const std::unordered_set<EDA_ITEM*>& aItems )
1537 {
1538 std::vector<VECTOR2I> bbCorners;
1539 bbCorners.reserve( aItems.size() * 4 );
1540
1541 for( EDA_ITEM* item : aItems )
1542 {
1543 const BOX2I bb = item->GetBoundingBox().GetInflated( 100000 );
1544 KIGEOM::CollectBoxCorners( bb, bbCorners );
1545 }
1546
1547 std::vector<VECTOR2I> hullVertices;
1548 BuildConvexHull( hullVertices, bbCorners );
1549
1550 SHAPE_LINE_CHAIN hull( hullVertices );
1551 return KIGEOM::RectifyPolygon( hull );
1552 };
1553
1554 // Apply the linked design block's layout to a single group. Returns with a
1555 // human-readable reason on failure.
1556 auto applyOneGroup = [&]( PCB_GROUP* group, wxString& outErr ) -> bool
1557 {
1558 DESIGN_BLOCK_PANE* pane = editFrame->GetDesignBlockPane();
1559 std::unique_ptr<DESIGN_BLOCK> designBlock(
1560 pane->GetDesignBlock( group->GetDesignBlockLibId(), true, false, &outErr ) );
1561
1562 if( !designBlock )
1563 return false;
1564
1565 if( designBlock->GetBoardFile().IsEmpty() )
1566 {
1567 outErr = _( "the design block has no saved board layout" );
1568 return false;
1569 }
1570
1571 brd->Visit(
1572 []( EDA_ITEM* item, void* )
1573 {
1574 item->SetFlags( MCT_SKIP_STRUCT );
1576 },
1578
1579 auto clearFlags = [&]()
1580 {
1581 brd->Visit(
1582 []( EDA_ITEM* item, void* )
1583 {
1584 item->ClearFlags( MCT_SKIP_STRUCT );
1586 },
1588 };
1589
1590 BOARD_COMMIT tempCommit( m_frame );
1591
1593 IO_RELEASER<PCB_IO> pi( PCB_IO_MGR::FindPlugin( pluginType ) );
1594
1595 if( !pi || AppendBoard( *pi, designBlock->GetBoardFile(), designBlock.get(), &tempCommit, true ) != 0 )
1596 {
1597 clearFlags();
1598 outErr = _( "the design block's board file could not be read" );
1599 return false;
1600 }
1601
1602 RULE_AREA dbRA;
1604 dbRA.m_generateEnabled = true;
1605
1606 brd->Visit(
1607 [&]( EDA_ITEM* item, void* )
1608 {
1609 if( !item->HasFlag( MCT_SKIP_STRUCT ) )
1610 {
1611 dbRA.m_designBlockItems.insert( item );
1612
1613 if( item->Type() == PCB_FOOTPRINT_T )
1614 dbRA.m_components.insert( static_cast<FOOTPRINT*>( item ) );
1615 }
1616
1618 },
1620
1621 if( dbRA.m_designBlockItems.empty() )
1622 {
1623 tempCommit.Revert();
1624 clearFlags();
1625 outErr = _( "the design block's board layout is empty" );
1626 return false;
1627 }
1628
1629 // Footprint-free copper has no matched pads to map nets through, so it is copied as no-net.
1630 bool blockHasNetlessCopper = false;
1631
1632 if( dbRA.m_components.empty() )
1633 {
1634 for( EDA_ITEM* item : dbRA.m_designBlockItems )
1635 {
1636 if( BOARD_ITEM* bi = dynamic_cast<BOARD_ITEM*>( item ); bi && bi->IsConnected() )
1637 {
1638 blockHasNetlessCopper = true;
1639 break;
1640 }
1641 }
1642 }
1643
1644 dbRA.m_zone = new ZONE( brd );
1645 dbRA.m_zone->SetZoneName( group->GetDesignBlockLibId().GetUniStringLibId() );
1646 dbRA.m_zone->SetIsRuleArea( true );
1648 dbRA.m_zone->SetPlacementAreaEnabled( true );
1649 dbRA.m_zone->SetDoNotAllowZoneFills( false );
1650 dbRA.m_zone->SetDoNotAllowVias( false );
1651 dbRA.m_zone->SetDoNotAllowTracks( false );
1652 dbRA.m_zone->SetDoNotAllowPads( false );
1653 dbRA.m_zone->SetDoNotAllowFootprints( false );
1655 dbRA.m_zone->SetPlacementAreaSource( group->GetDesignBlockLibId().GetUniStringLibId() );
1657 dbRA.m_zone->AddPolygon( generateBoundingBox( dbRA.m_designBlockItems ) );
1658 dbRA.m_center = dbRA.m_zone->Outline()->COutline( 0 ).Centre();
1659
1660 RULE_AREA destRA;
1662
1663 for( EDA_ITEM* item : group->GetItems() )
1664 {
1665 if( item->Type() == PCB_FOOTPRINT_T )
1666 destRA.m_components.insert( static_cast<FOOTPRINT*>( item ) );
1667 }
1668
1669 destRA.m_group = group;
1670
1671 if( group->GetItems().empty() )
1672 {
1673 tempCommit.Revert();
1674 clearFlags();
1675 delete dbRA.m_zone;
1676 outErr = _( "the group has no items" );
1677 return false;
1678 }
1679
1680 destRA.m_zone = new ZONE( brd );
1681 destRA.m_zone->SetZoneName( group->GetName().IsEmpty() ? _( "(unnamed group)" ) : group->GetName() );
1682 destRA.m_zone->SetIsRuleArea( true );
1683 destRA.m_zone->SetLayerSet( LSET::AllCuMask() );
1684 destRA.m_zone->SetPlacementAreaEnabled( true );
1685 destRA.m_zone->SetDoNotAllowZoneFills( false );
1686 destRA.m_zone->SetDoNotAllowVias( false );
1687 destRA.m_zone->SetDoNotAllowTracks( false );
1688 destRA.m_zone->SetDoNotAllowPads( false );
1689 destRA.m_zone->SetDoNotAllowFootprints( false );
1691 destRA.m_zone->SetPlacementAreaSource( group->GetName() );
1693 destRA.m_zone->AddPolygon( generateBoundingBox( group->GetItems() ) );
1694 destRA.m_center = destRA.m_zone->Outline()->COutline( 0 ).Centre();
1695
1696 REPEAT_LAYOUT_OPTIONS options = { .m_copyRouting = true,
1697 .m_connectedRoutingOnly = false,
1698 .m_copyPlacement = true,
1699 .m_copyOtherItems = true,
1700 .m_groupItems = false,
1701 .m_includeLockedItems = true,
1702 .m_anchorFp = nullptr };
1703
1704 // Give the appended block's auto-generated nets a private namespace so they cannot fuse by
1705 // name with a different part's net on the board, which would corrupt the topology match
1706 // (issue 24767). Reverted with the temporary block, so the private nets are removed below.
1707 std::vector<NETINFO_ITEM*> isolatedNets =
1709
1710 wxString repeatErr;
1711 int result = mct->RepeatLayout( aEvent, dbRA, destRA, options, &sharedCommit, &repeatErr );
1712
1713 tempCommit.Revert();
1714
1715 for( NETINFO_ITEM* net : isolatedNets )
1716 {
1717 brd->Remove( net );
1718 delete net;
1719 }
1720
1721 clearFlags();
1722 delete dbRA.m_zone;
1723 delete destRA.m_zone;
1724
1725 if( result != 0 )
1726 {
1727 outErr = repeatErr.IsEmpty() ? _( "the layout could not be copied onto the group" ) : repeatErr;
1728 return false;
1729 }
1730
1731 if( blockHasNetlessCopper )
1732 netlessCopperPlaced = true;
1733
1734 return true;
1735 };
1736
1737 for( size_t i = 0; i < linkedGroups.size(); ++i )
1738 {
1739 PCB_GROUP* g = linkedGroups[i];
1740
1741 if( progress )
1742 {
1743 progress->SetCurrentProgress( static_cast<double>( i ) / linkedGroups.size() );
1744 progress->Report(
1745 wxString::Format( _( "Applying layout to group %zu of %zu..." ), i + 1, linkedGroups.size() ) );
1746
1747 if( !progress->KeepRefreshing() )
1748 {
1749 cancelled = true;
1750 break;
1751 }
1752 }
1753
1754 wxString err;
1755
1756 if( applyOneGroup( g, err ) )
1757 applied++;
1758 else
1759 failures.push_back( { g, err } );
1760 }
1761
1762 if( progress )
1763 progress->SetCurrentProgress( 1.0 );
1764
1765 if( cancelled )
1766 {
1767 sharedCommit.Revert();
1768 m_frame->ShowInfoBarMsg( _( "Apply design block layout cancelled." ), true );
1769 return 1;
1770 }
1771
1772 if( applied > 0 )
1773 {
1774 sharedCommit.Push( wxString::Format( _( "Apply design block layout to %d group(s)" ), applied ) );
1775
1776 if( netlessCopperPlaced )
1777 m_frame->ShowInfoBarMsg( _( "Copied copper has no net assigned. Assign nets to connect it." ), true );
1778 }
1779 else
1780 {
1781 sharedCommit.Revert();
1782 }
1783
1784 if( skippedNoLink > 0 || !failures.empty() || linkedGroups.size() > 1 )
1785 {
1786 wxString html;
1787
1788 html << wxT( "<p>" )
1789 << wxString::Format( _( "Applied design block layout to %d of %d group(s)." ), applied,
1790 (int) linkedGroups.size() )
1791 << wxT( "</p>" );
1792
1793 if( skippedNoLink > 0 )
1794 {
1795 html << wxT( "<p>" )
1796 << wxString::Format( _( "Skipped %d selected item(s) that are not groups linked to a "
1797 "design block." ),
1798 skippedNoLink )
1799 << wxT( "</p>" );
1800 }
1801
1802 if( !failures.empty() )
1803 {
1804 html << wxT( "<p>" ) << _( "The following groups could not be processed:" ) << wxT( "</p><ul>" );
1805
1806 for( const Failure& f : failures )
1807 {
1808 wxString name = f.group->GetName().IsEmpty() ? _( "(unnamed group)" ) : f.group->GetName();
1809 wxString reason = f.reason;
1810
1811 reason.Replace( wxT( "\n" ), wxT( "<br>" ) );
1812 html << wxString::Format( wxT( "<li><b>%s</b>: %s</li>" ), name, reason );
1813 }
1814
1815 html << wxT( "</ul>" );
1816 }
1817
1818 HTML_MESSAGE_BOX dlg( m_frame, _( "Apply Design Block Layout" ) );
1819 dlg.SetDialogSizeInDU( 360, 220 );
1820 dlg.AddHTML_Text( html );
1821 dlg.ShowModal();
1822 }
1823
1824 return applied > 0 ? 0 : 1;
1825}
1826
1828{
1829 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
1830
1831 if( !editFrame )
1832 return 1;
1833
1834 // Need to have a group selected and it needs to have a linked design block
1835 PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
1837
1838 if( selection.Size() != 1 || selection[0]->Type() != PCB_GROUP_T )
1839 return 1;
1840
1841 PCB_GROUP* group = static_cast<PCB_GROUP*>( selection[0] );
1842
1843 if( !group->HasDesignBlockLink() )
1844 return 1;
1845
1846 // Get the associated design block
1847 DESIGN_BLOCK_PANE* designBlockPane = editFrame->GetDesignBlockPane();
1848 std::unique_ptr<DESIGN_BLOCK> designBlock( designBlockPane->GetDesignBlock( group->GetDesignBlockLibId(),
1849 true, true ) );
1850
1851 if( !designBlock )
1852 return 1;
1853
1854 if( designBlock->GetBoardFile().IsEmpty() )
1855 {
1856 wxString msg;
1857 msg.Printf( _( "Design block %s does not have a board file." ),
1858 group->GetDesignBlockLibId().GetUniStringLibId() );
1859 m_frame->GetInfoBar()->ShowMessageFor( msg, 5000, wxICON_WARNING );
1860 return 1;
1861 }
1862
1863
1865 IO_RELEASER<PCB_IO> pi( PCB_IO_MGR::FindPlugin( pluginType ) );
1866
1867 if( !pi )
1868 return 1;
1869
1870 if( aEvent.Parameter<bool*>() != nullptr )
1871 return AppendBoard( *pi, designBlock->GetBoardFile(), designBlock.get(),
1872 static_cast<BOARD_COMMIT*>( aEvent.Commit() ), *aEvent.Parameter<bool*>() );
1873 else
1874 return AppendBoard( *pi, designBlock->GetBoardFile(), designBlock.get() );
1875}
1876
1877
1879{
1880 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
1881
1882 if( !editFrame )
1883 return 1;
1884
1885 // Need to have a group selected and it needs to have a linked design block
1886 PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
1888
1889 if( selection.Size() != 1 || selection[0]->Type() != PCB_GROUP_T )
1890 return 1;
1891
1892 PCB_GROUP* group = static_cast<PCB_GROUP*>( selection[0] );
1893
1894 if( !group->HasDesignBlockLink() )
1895 return 1;
1896
1897 // Get the associated design block
1898 DESIGN_BLOCK_PANE* designBlockPane = editFrame->GetDesignBlockPane();
1899 std::unique_ptr<DESIGN_BLOCK> designBlock( designBlockPane->GetDesignBlock( group->GetDesignBlockLibId(),
1900 true, true ) );
1901
1902 if( !designBlock )
1903 return 1;
1904
1905 editFrame->GetDesignBlockPane()->SelectLibId( group->GetDesignBlockLibId() );
1906
1907 return m_toolMgr->RunAction( PCB_ACTIONS::updateDesignBlockFromSelection ) ? 1 : 0;
1908}
1909
1910
1911bool PCB_CONTROL::placeBoardItems( BOARD_COMMIT* aCommit, BOARD* aBoard, bool aAnchorAtOrigin,
1912 bool aReannotateDuplicates, bool aSkipMove )
1913{
1914 // items are new if the current board is not the board source
1915 bool isNew = board() != aBoard;
1916 std::vector<BOARD_ITEM*> items;
1917
1918 for( BOARD_ITEM* item : aBoard->GetItemSet() )
1919 {
1920 // Marker transfer is intentionally not part of append/paste item placement.
1921 if( item->Type() == PCB_MARKER_T )
1922 continue;
1923
1924 bool doCopy = ( item->GetFlags() & SKIP_STRUCT ) == 0;
1925
1926 item->ClearFlags( SKIP_STRUCT );
1927 item->SetFlags( isNew ? IS_NEW : 0 );
1928
1929 if( doCopy )
1930 items.push_back( item );
1931 }
1932
1933 if( isNew )
1934 aBoard->RemoveAll();
1935
1936 // Reparent before calling pruneItemLayers, as SetLayer can have a dependence on the
1937 // item's parent board being set correctly.
1938 if( isNew )
1939 {
1940 for( BOARD_ITEM* item : items )
1941 item->SetParent( board() );
1942 }
1943
1944 pruneItemLayers( items );
1945
1946 return placeBoardItems( aCommit, items, isNew, aAnchorAtOrigin, aReannotateDuplicates, aSkipMove );
1947}
1948
1949
1950bool PCB_CONTROL::placeBoardItems( BOARD_COMMIT* aCommit, std::vector<BOARD_ITEM*>& aItems, bool aIsNew,
1951 bool aAnchorAtOrigin, bool aReannotateDuplicates, bool aSkipMove )
1952{
1953 m_toolMgr->RunAction( ACTIONS::selectionClear );
1954
1955 PCB_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
1956
1957 std::vector<BOARD_ITEM*> itemsToSel;
1958 itemsToSel.reserve( aItems.size() );
1959
1960 // Re-UUIDing pasted items breaks any item that references another by KIID (e.g. a constraint's
1961 // members); record old -> new so those references can be remapped once every item has its new id.
1962 // A grouped shape appears both as a top-level item and as a group child, so reset each item only
1963 // once -- a second reset would record a new->newer entry and corrupt the old->new mapping.
1964 std::map<KIID, KIID> idMap;
1965 std::set<BOARD_ITEM*> resetItems;
1966
1967 auto resetUuidOnce =
1968 [&]( BOARD_ITEM* aItem )
1969 {
1970 if( !resetItems.insert( aItem ).second )
1971 return;
1972
1973 KIID oldUuid = aItem->m_Uuid;
1974 aItem->ResetUuid();
1975 idMap[oldUuid] = aItem->m_Uuid;
1976 };
1977
1978 for( BOARD_ITEM* item : aItems )
1979 {
1980 if( aIsNew )
1981 {
1982 resetUuidOnce( item );
1983
1984 item->RunOnChildren(
1985 [&]( BOARD_ITEM* aChild )
1986 {
1987 resetUuidOnce( aChild );
1988 },
1990
1991 // While BOARD_COMMIT::Push() will add any new items to the entered group,
1992 // we need to do it earlier so that the previews while moving are correct.
1993 if( PCB_GROUP* enteredGroup = selectionTool->GetEnteredGroup() )
1994 {
1995 if( item->IsGroupableType() && !item->GetParentGroup() )
1996 {
1997 aCommit->Modify( enteredGroup, nullptr, RECURSE_MODE::NO_RECURSE );
1998 enteredGroup->AddItem( item );
1999 }
2000 }
2001
2002 item->SetParent( board() );
2003
2004 // A pasted zone must not reuse a name already on the board (issue 23131)
2005 if( item->Type() == PCB_ZONE_T )
2006 {
2007 ZONE* zone = static_cast<ZONE*>( item );
2008
2009 if( !zone->GetZoneName().IsEmpty() )
2010 zone->SetZoneName( board()->GetUniqueZoneName( zone->GetZoneName() ) );
2011 }
2012 }
2013
2014 // Update item attributes if needed
2015 if( BaseType( item->Type() ) == PCB_DIMENSION_T )
2016 {
2017 static_cast<PCB_DIMENSION_BASE*>( item )->UpdateUnits();
2018 }
2019 else if( item->Type() == PCB_FOOTPRINT_T )
2020 {
2021 FOOTPRINT* footprint = static_cast<FOOTPRINT*>( item );
2022
2023 // Update the footprint path with the new KIID path if the footprint is new
2024 if( aIsNew )
2025 footprint->SetPath( KIID_PATH() );
2026
2027 for( BOARD_ITEM* dwg : footprint->GraphicalItems() )
2028 {
2029 if( BaseType( dwg->Type() ) == PCB_DIMENSION_T )
2030 static_cast<PCB_DIMENSION_BASE*>( dwg )->UpdateUnits();
2031 }
2032 }
2033
2034 // We only need to add the items that aren't inside a group currently selected
2035 // to the selection. If an item is inside a group and that group is selected,
2036 // then the selection tool will select it for us.
2037 if( !item->GetParentGroup() || !alg::contains( aItems, item->GetParentGroup()->AsEdaItem() ) )
2038 itemsToSel.push_back( item );
2039 }
2040
2041 // Now that every pasted item has its new UUID, remap KIID references (e.g. constraint members)
2042 // from the old ids to the new ones so they still resolve to the pasted copies.
2043 if( aIsNew && !idMap.empty() )
2044 {
2045 for( BOARD_ITEM* item : aItems )
2046 {
2047 item->RemapKIIDs( idMap );
2048 item->RunOnChildren( [&]( BOARD_ITEM* aChild )
2049 {
2050 aChild->RemapKIIDs( idMap );
2051 },
2053 }
2054 }
2055
2056 // Select the items that should be selected
2057 EDA_ITEMS toSel( itemsToSel.begin(), itemsToSel.end() );
2058 m_toolMgr->RunAction<EDA_ITEMS*>( ACTIONS::selectItems, &toSel );
2059
2060 // Reannotate duplicate footprints (make sense only in board editor )
2061 if( aReannotateDuplicates && m_isBoardEditor )
2062 m_toolMgr->GetTool<BOARD_REANNOTATE_TOOL>()->ReannotateDuplicatesInSelection();
2063
2064 for( BOARD_ITEM* item : aItems )
2065 {
2066 if( aIsNew )
2067 aCommit->Add( item );
2068 else
2069 aCommit->Added( item );
2070 }
2071
2072 PCB_SELECTION& selection = selectionTool->GetSelection();
2073
2074 if( selection.Size() > 0 )
2075 {
2076 if( aAnchorAtOrigin )
2077 {
2078 selection.SetReferencePoint( VECTOR2I( 0, 0 ) );
2079 }
2080 else if( BOARD_ITEM* item = dynamic_cast<BOARD_ITEM*>( selection.GetTopLeftItem() ) )
2081 {
2082 selection.SetReferencePoint( item->GetPosition() );
2083 }
2084
2085 getViewControls()->SetCursorPosition( getViewControls()->GetMousePosition(), false );
2086
2087 m_toolMgr->ProcessEvent( EVENTS::SelectedEvent );
2088
2089 if( !aSkipMove )
2090 return m_toolMgr->RunSynchronousAction( PCB_ACTIONS::move, aCommit );
2091 }
2092
2093 return true;
2094}
2095
2096
2097int PCB_CONTROL::AppendBoard( PCB_IO& pi, const wxString& fileName, DESIGN_BLOCK* aDesignBlock, BOARD_COMMIT* aCommit,
2098 bool aSkipMove )
2099{
2100 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
2101
2102 if( !editFrame )
2103 return 1;
2104
2105 BOARD* brd = board();
2106
2107 if( !brd )
2108 return 1;
2109
2110 // Give ourselves a commit to work with if we weren't provided one
2111 std::unique_ptr<BOARD_COMMIT> tempCommit;
2112 BOARD_COMMIT* commit = aCommit;
2113
2114 if( !commit )
2115 {
2116 tempCommit = std::make_unique<BOARD_COMMIT>( editFrame );
2117 commit = tempCommit.get();
2118 }
2119
2120 // Mark existing items, in order to know what are the new items so we can select only
2121 // the new items after loading
2122 BOARD_ITEM_SET existingItems = brd->GetItemSet();
2123
2124 for( BOARD_ITEM* item : existingItems )
2125 item->SetFlags( SKIP_STRUCT );
2126
2127 auto clearSkipStructOnExistingItems =
2128 [&existingItems]()
2129 {
2130 for( BOARD_ITEM* item : existingItems )
2131 item->ClearFlags( SKIP_STRUCT );
2132 };
2133
2134 std::map<wxString, wxString> oldProperties = brd->GetProperties();
2135 std::map<wxString, wxString> newProperties;
2136
2137 PAGE_INFO oldPageInfo = brd->GetPageSettings();
2138 TITLE_BLOCK oldTitleBlock = brd->GetTitleBlock();
2139
2140 // Keep also the count of copper layers, to adjust if necessary
2141 int initialCopperLayerCount = brd->GetCopperLayerCount();
2142 LSET initialEnabledLayers = brd->GetEnabledLayers();
2143
2144 // Load the data
2145 try
2146 {
2147 std::map<std::string, UTF8> props;
2148
2149 // PCB_IO_EAGLE can use this info to center the BOARD, but it does not yet.
2150
2151 props["page_width"] = std::to_string( editFrame->GetPageSizeIU().x );
2152 props["page_height"] = std::to_string( editFrame->GetPageSizeIU().y );
2154
2156 [&]( wxString aTitle, int aIcon, wxString aMessage, wxString aAction ) -> bool
2157 {
2158 KIDIALOG dlg( editFrame, aMessage, aTitle, wxOK | wxCANCEL | aIcon );
2159
2160 if( !aAction.IsEmpty() )
2161 dlg.SetOKLabel( aAction );
2162
2163 dlg.DoNotShowCheckbox( aMessage, 0 );
2164
2165 return dlg.ShowModal() == wxID_OK;
2166 } );
2167
2168 // Let the user remap the appended board's layers onto this board when they do not match
2169 if( LAYER_MAPPABLE_PLUGIN* mappable = dynamic_cast<LAYER_MAPPABLE_PLUGIN*>( &pi ) )
2170 {
2171 mappable->RegisterCallback(
2172 [editFrame]( const std::vector<INPUT_LAYER_DESC>& aLayerDescs )
2173 {
2174 return DIALOG_MAP_LAYERS::RunModal( editFrame, aLayerDescs );
2175 } );
2176 }
2177
2178 WX_PROGRESS_REPORTER progressReporter( editFrame, _( "Load PCB" ), 1, PR_CAN_ABORT );
2179
2180 pi.SetProgressReporter( &progressReporter );
2181 pi.LoadAndAppendBoard( fileName, *brd, &props, nullptr );
2182 }
2183 catch( const IO_ERROR& ioe )
2184 {
2185 DisplayErrorMessage( editFrame, _( "Error loading board." ), ioe.What() );
2186 clearSkipStructOnExistingItems();
2187
2188 return 1;
2189 }
2190
2191 newProperties = brd->GetProperties();
2192
2193 for( const std::pair<const wxString, wxString>& prop : oldProperties )
2194 newProperties[prop.first] = prop.second;
2195
2196 brd->SetProperties( newProperties );
2197
2198 brd->SetPageSettings( oldPageInfo );
2199 brd->SetTitleBlock( oldTitleBlock );
2200
2201 // rebuild nets and ratsnest before any use of nets
2202 brd->BuildListOfNets();
2203 brd->SynchronizeNetsAndNetClasses( true );
2204 brd->BuildConnectivity();
2205
2206 // New appended items need to inherit the current global ratsnest state.
2207 // Existing items are marked SKIP_STRUCT and are handled elsewhere.
2208 const bool showGlobalRatsnest = displayOptions().m_ShowGlobalRatsnest;
2209
2210 for( BOARD_ITEM* item : brd->GetItemSet() )
2211 {
2212 if( item->GetFlags() & SKIP_STRUCT )
2213 continue;
2214
2215 if( BOARD_CONNECTED_ITEM* connectedItem = dynamic_cast<BOARD_CONNECTED_ITEM*>( item ) )
2216 connectedItem->SetLocalRatsnestVisible( showGlobalRatsnest );
2217
2218 if( item->Type() == PCB_FOOTPRINT_T )
2219 {
2220 for( PAD* pad : static_cast<FOOTPRINT*>( item )->Pads() )
2221 pad->SetLocalRatsnestVisible( showGlobalRatsnest );
2222 }
2223 }
2224
2225 // Synchronize layers
2226 // we should not ask PLUGINs to do these items:
2227 int copperLayerCount = brd->GetCopperLayerCount();
2228
2229 if( copperLayerCount > initialCopperLayerCount )
2230 brd->SetCopperLayerCount( copperLayerCount );
2231
2232 // Enable all used layers, and make them visible:
2233 LSET enabledLayers = brd->GetEnabledLayers();
2234 enabledLayers |= initialEnabledLayers;
2235 brd->SetEnabledLayers( enabledLayers );
2236 brd->SetVisibleLayers( enabledLayers );
2238
2239 if( brd->GetCopperLayerCount() != initialCopperLayerCount )
2240 {
2241 WX_INFOBAR* infobar = editFrame->GetInfoBar();
2242 wxString msg = wxString::Format( _( "Board changed from %d to %d copper layers, stackup updated." ),
2243 initialCopperLayerCount,
2244 brd->GetCopperLayerCount() );
2245 infobar->ShowMessageFor( msg, 6000, wxICON_INFORMATION );
2246 }
2247
2248 int ret = 0;
2249
2250 bool placeAsGroup = false;
2251
2252 if( APP_SETTINGS_BASE* cfg = editFrame->config() )
2253 placeAsGroup = cfg->m_DesignBlockChooserPanel.place_as_group;
2254
2255 if( placeBoardItems( commit, brd, false, false /* Don't reannotate dupes on Append Board */, aSkipMove ) )
2256 {
2257 if( placeAsGroup )
2258 {
2259 PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
2261
2262 // Count items that would be added to the group
2263 int groupableCount = 0;
2264
2265 for( EDA_ITEM* eda_item : selection )
2266 {
2267 if( eda_item->IsBOARD_ITEM()
2268 && !static_cast<BOARD_ITEM*>( eda_item )->GetParentFootprint() )
2269 {
2270 groupableCount++;
2271 }
2272 }
2273
2274 if( groupableCount >= 2 )
2275 {
2276 PCB_GROUP* group = new PCB_GROUP( brd );
2277
2278 if( aDesignBlock )
2279 {
2280 group->SetName( aDesignBlock->GetLibId().GetLibItemName() );
2281 group->SetDesignBlockLibId( aDesignBlock->GetLibId() );
2282 }
2283 else
2284 {
2285 group->SetName( wxFileName( fileName ).GetName() );
2286 }
2287
2288 for( EDA_ITEM* eda_item : selection )
2289 {
2290 if( eda_item->IsBOARD_ITEM() )
2291 {
2292 if( static_cast<BOARD_ITEM*>( eda_item )->IsLocked() )
2293 group->SetLocked( true );
2294 }
2295 }
2296
2297 commit->Add( group );
2298
2299 for( EDA_ITEM* eda_item : selection )
2300 {
2301 if( eda_item->IsBOARD_ITEM()
2302 && !static_cast<BOARD_ITEM*>( eda_item )->GetParentFootprint() )
2303 {
2304 commit->Modify( eda_item );
2305 group->AddItem( eda_item );
2306 }
2307 }
2308
2309 selTool->ClearSelection();
2310 selTool->select( group );
2311
2313 m_frame->OnModify();
2314 m_frame->Refresh();
2315 }
2316 }
2317
2318 // If we were provided a commit, let the caller control when to push it
2319 if( !aCommit )
2320 commit->Push( aDesignBlock ? _( "Place Design Block" ) : _( "Append Board" ) );
2321
2322 editFrame->GetBoard()->BuildConnectivity();
2323 ret = 0;
2324 }
2325 else
2326 {
2327 // If we were provided a commit, let the caller control when to revert it
2328 if( !aCommit )
2329 commit->Revert();
2330
2331 ret = 1;
2332 }
2333
2334 // Refresh the UI for the updated board properties
2335 editFrame->GetAppearancePanel()->OnBoardChanged();
2336 clearSkipStructOnExistingItems();
2337
2338 return ret;
2339}
2340
2341
2342int PCB_CONTROL::Undo( const TOOL_EVENT& aEvent )
2343{
2344 PCB_BASE_EDIT_FRAME* editFrame = dynamic_cast<PCB_BASE_EDIT_FRAME*>( m_frame );
2345 wxCommandEvent dummy;
2346
2347 if( editFrame )
2348 editFrame->RestoreCopyFromUndoList( dummy );
2349
2350 return 0;
2351}
2352
2353
2354int PCB_CONTROL::Redo( const TOOL_EVENT& aEvent )
2355{
2356 PCB_BASE_EDIT_FRAME* editFrame = dynamic_cast<PCB_BASE_EDIT_FRAME*>( m_frame );
2357 wxCommandEvent dummy;
2358
2359 if( editFrame )
2360 editFrame->RestoreCopyFromRedoList( dummy );
2361
2362 return 0;
2363}
2364
2365
2367{
2368 MAGNETIC_SETTINGS& settings = m_isFootprintEditor ? m_frame->GetFootprintEditorSettings()->m_MagneticItems
2369 : m_frame->GetPcbNewSettings()->m_MagneticItems;
2370 bool& snapMode = settings.allLayers;
2371
2373 snapMode = false;
2374 else if( aEvent.IsAction( &PCB_ACTIONS::magneticSnapAllLayers ) )
2375 snapMode = true;
2376 else
2377 snapMode = !snapMode;
2378
2380
2381 return 0;
2382}
2383
2384
2386{
2387 if( !Pgm().GetCommonSettings()->m_Input.hotkey_feedback )
2388 return 0;
2389
2390 wxArrayString labels;
2391 labels.Add( _( "Active Layer" ) );
2392 labels.Add( _( "All Layers" ) );
2393
2394 if( !m_frame->GetHotkeyPopup() )
2395 m_frame->CreateHotkeyPopup();
2396
2397 HOTKEY_CYCLE_POPUP* popup = m_frame->GetHotkeyPopup();
2398
2399 MAGNETIC_SETTINGS& settings = m_isFootprintEditor ? m_frame->GetFootprintEditorSettings()->m_MagneticItems
2400 : m_frame->GetPcbNewSettings()->m_MagneticItems;
2401
2402 if( popup )
2403 popup->Popup( _( "Object Snapping" ), labels, static_cast<int>( settings.allLayers ) );
2404
2405 return 0;
2406}
2407
2408
2410{
2411 PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
2412 ROUTER_TOOL* routerTool = m_toolMgr->GetTool<ROUTER_TOOL>();
2413 PCB_SELECTION& selection = selTool->GetSelection();
2414 PCB_EDIT_FRAME* pcbFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
2415 std::shared_ptr<DRC_ENGINE> drcEngine = m_frame->GetBoard()->GetDesignSettings().m_DRCEngine;
2416 DRC_CONSTRAINT constraint;
2417
2418 std::vector<MSG_PANEL_ITEM> msgItems;
2419
2420 if( routerTool && routerTool->RoutingInProgress() )
2421 {
2422 routerTool->UpdateMessagePanel();
2423 return 0;
2424 }
2425
2426 if( !pcbFrame && !m_frame->GetModel() )
2427 return 0;
2428
2429 if( selection.Empty() )
2430 {
2431 if( !pcbFrame )
2432 {
2433 FOOTPRINT* fp = static_cast<FOOTPRINT*>( m_frame->GetModel() );
2434 fp->GetMsgPanelInfo( m_frame, msgItems );
2435 }
2436 else
2437 {
2438 m_frame->SetMsgPanel( m_frame->GetBoard() );
2439 }
2440 }
2441 else if( selection.GetSize() == 1 )
2442 {
2443 EDA_ITEM* item = selection.Front();
2444
2445 if( std::optional<wxString> uuid = GetMsgPanelDisplayUuid( item->m_Uuid ) )
2446 msgItems.emplace_back( _( "UUID" ), *uuid );
2447
2448 item->GetMsgPanelInfo( m_frame, msgItems );
2449
2450 PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( item );
2451 NETINFO_ITEM* net = track ? track->GetNet() : nullptr;
2452 NETINFO_ITEM* coupledNet = net ? m_frame->GetBoard()->DpCoupledNet( net ) : nullptr;
2453
2454 if( coupledNet )
2455 {
2456 SEG trackSeg( track->GetStart(), track->GetEnd() );
2457 PCB_TRACK* coupledItem = nullptr;
2458 SEG::ecoord closestDist_sq = VECTOR2I::ECOORD_MAX;
2459
2460 for( PCB_TRACK* candidate : m_frame->GetBoard()->Tracks() )
2461 {
2462 if( candidate->GetNet() != coupledNet )
2463 continue;
2464
2465 SEG::ecoord dist_sq = trackSeg.SquaredDistance( SEG( candidate->GetStart(), candidate->GetEnd() ) );
2466
2467 if( !coupledItem || dist_sq < closestDist_sq )
2468 {
2469 coupledItem = candidate;
2470 closestDist_sq = dist_sq;
2471 }
2472 }
2473
2474 constraint = drcEngine->EvalRules( DIFF_PAIR_GAP_CONSTRAINT, track, coupledItem, track->GetLayer() );
2475
2476 wxString msg = m_frame->MessageTextFromMinOptMax( constraint.Value() );
2477
2478 if( !msg.IsEmpty() )
2479 {
2480 msgItems.emplace_back( wxString::Format( _( "DP Gap Constraints: %s" ), msg ),
2481 wxString::Format( _( "(from %s)" ), constraint.GetName() ) );
2482 }
2483
2484 constraint = drcEngine->EvalRules( MAX_UNCOUPLED_CONSTRAINT, track, coupledItem, track->GetLayer() );
2485
2486 if( constraint.Value().HasMax() )
2487 {
2488 msg = m_frame->MessageTextFromValue( constraint.Value().Max() );
2489 msgItems.emplace_back( wxString::Format( _( "DP Max Uncoupled-length: %s" ), msg ),
2490 wxString::Format( _( "(from %s)" ), constraint.GetName() ) );
2491 }
2492 }
2493 }
2494 else if( pcbFrame && selection.GetSize() == 2 )
2495 {
2496 // Pair selection broken into multiple, optional data, starting with the selected item
2497 // names
2498
2499 BOARD_ITEM* a = dynamic_cast<BOARD_ITEM*>( selection[0] );
2500 BOARD_ITEM* b = dynamic_cast<BOARD_ITEM*>( selection[1] );
2501
2502 if( a && b )
2503 {
2504 msgItems.emplace_back( MSG_PANEL_ITEM( a->GetItemDescription( m_frame, false ),
2505 b->GetItemDescription( m_frame, false ) ) );
2506 }
2507
2508 BOARD_CONNECTED_ITEM* a_conn = dynamic_cast<BOARD_CONNECTED_ITEM*>( a );
2509 BOARD_CONNECTED_ITEM* b_conn = dynamic_cast<BOARD_CONNECTED_ITEM*>( b );
2510
2511 if( a_conn && b_conn )
2512 {
2513 LSET overlap = a_conn->GetLayerSet() & b_conn->GetLayerSet() & LSET::AllCuMask();
2514 int a_netcode = a_conn->GetNetCode();
2515 int b_netcode = b_conn->GetNetCode();
2516
2517 if( overlap.count() > 0 )
2518 {
2519 PCB_LAYER_ID layer = overlap.CuStack().front();
2520
2521 if( a_netcode != b_netcode || a_netcode < 0 || b_netcode < 0 )
2522 {
2523 constraint = drcEngine->EvalRules( CLEARANCE_CONSTRAINT, a, b, layer );
2524 msgItems.emplace_back( _( "Resolved Clearance" ),
2525 m_frame->MessageTextFromValue( constraint.m_Value.Min() ) );
2526 }
2527
2528 std::shared_ptr<SHAPE> a_shape( a_conn->GetEffectiveShape( layer ) );
2529 std::shared_ptr<SHAPE> b_shape( b_conn->GetEffectiveShape( layer ) );
2530
2531 int actual_clearance = a_shape->GetClearance( b_shape.get() );
2532
2533 if( actual_clearance > -1 && actual_clearance < std::numeric_limits<int>::max() )
2534 {
2535 msgItems.emplace_back( _( "Actual Clearance" ),
2536 m_frame->MessageTextFromValue( actual_clearance ) );
2537 }
2538 }
2539 }
2540
2541 if( a && b && ( a->HasHole() || b->HasHole() ) )
2542 {
2543 PCB_LAYER_ID active = m_frame->GetActiveLayer();
2545
2546 if( b->IsOnLayer( active ) && IsCopperLayer( active ) )
2547 layer = active;
2548 else if( b->HasHole() && a->IsOnLayer( active ) && IsCopperLayer( active ) )
2549 layer = active;
2550 else if( a->HasHole() && b->IsOnCopperLayer() )
2551 layer = b->GetLayer();
2552 else if( b->HasHole() && a->IsOnCopperLayer() )
2553 layer = a->GetLayer();
2554
2555 if( IsCopperLayer( layer ) )
2556 {
2557 int actual = std::numeric_limits<int>::max();
2558
2559 if( a->HasHole() && b->IsOnCopperLayer() )
2560 {
2561 std::shared_ptr<SHAPE_SEGMENT> hole = a->GetEffectiveHoleShape();
2562 std::shared_ptr<SHAPE> other( b->GetEffectiveShape( layer ) );
2563
2564 actual = std::min( actual, hole->GetClearance( other.get() ) );
2565 }
2566
2567 if( b->HasHole() && a->IsOnCopperLayer() )
2568 {
2569 std::shared_ptr<SHAPE_SEGMENT> hole = b->GetEffectiveHoleShape();
2570 std::shared_ptr<SHAPE> other( a->GetEffectiveShape( layer ) );
2571
2572 actual = std::min( actual, hole->GetClearance( other.get() ) );
2573 }
2574
2575 if( actual < std::numeric_limits<int>::max() )
2576 {
2577 constraint = drcEngine->EvalRules( HOLE_CLEARANCE_CONSTRAINT, a, b, layer );
2578 msgItems.emplace_back( _( "Resolved Hole Clearance" ),
2579 m_frame->MessageTextFromValue( constraint.m_Value.Min() ) );
2580
2581 if( actual > -1 && actual < std::numeric_limits<int>::max() )
2582 {
2583 msgItems.emplace_back( _( "Actual Hole Clearance" ),
2584 m_frame->MessageTextFromValue( actual ) );
2585 }
2586 }
2587 }
2588 }
2589
2590 if( a && b )
2591 {
2592 for( PCB_LAYER_ID edgeLayer : { Edge_Cuts, Margin } )
2593 {
2594 PCB_LAYER_ID active = m_frame->GetActiveLayer();
2596
2597 if( a->IsOnLayer( edgeLayer ) && b->Type() != PCB_FOOTPRINT_T )
2598 {
2599 if( b->IsOnLayer( active ) && IsCopperLayer( active ) )
2600 layer = active;
2601 else if( IsCopperLayer( b->GetLayer() ) )
2602 layer = b->GetLayer();
2603 }
2604 else if( b->IsOnLayer( edgeLayer ) && a->Type() != PCB_FOOTPRINT_T )
2605 {
2606 if( a->IsOnLayer( active ) && IsCopperLayer( active ) )
2607 layer = active;
2608 else if( IsCopperLayer( a->GetLayer() ) )
2609 layer = a->GetLayer();
2610 }
2611
2612 if( layer >= 0 )
2613 {
2614 constraint = drcEngine->EvalRules( EDGE_CLEARANCE_CONSTRAINT, a, b, layer );
2615
2616 if( edgeLayer == Edge_Cuts )
2617 {
2618 msgItems.emplace_back( _( "Resolved Edge Clearance" ),
2619 m_frame->MessageTextFromValue( constraint.m_Value.Min() ) );
2620 }
2621 else
2622 {
2623 msgItems.emplace_back( _( "Resolved Margin Clearance" ),
2624 m_frame->MessageTextFromValue( constraint.m_Value.Min() ) );
2625 }
2626 }
2627 }
2628 }
2629 }
2630
2631 if( selection.GetSize() )
2632 {
2633 if( msgItems.empty() )
2634 {
2635 // Count items by type
2636 std::map<KICAD_T, int> typeCounts;
2637
2638 for( EDA_ITEM* item : selection )
2639 typeCounts[item->Type()]++;
2640
2641 // Check if all items are the same type
2642 bool allSameType = ( typeCounts.size() == 1 );
2643 KICAD_T commonType = allSameType ? typeCounts.begin()->first : NOT_USED;
2644
2645 if( allSameType )
2646 {
2647 // Show "Type: N" for homogeneous selections
2648 wxString typeName = selection.Front()->GetFriendlyName();
2649 msgItems.emplace_back( typeName, wxString::Format( wxT( "%d" ), selection.GetSize() ) );
2650
2651 // For pads, show common properties
2652 if( commonType == PCB_PAD_T )
2653 {
2654 std::set<wxString> layers;
2655 std::set<PAD_SHAPE> shapes;
2656 std::set<VECTOR2I> sizes;
2657
2658 for( EDA_ITEM* item : selection )
2659 {
2660 PAD* pad = static_cast<PAD*>( item );
2661
2662 layers.insert( pad->LayerMaskDescribe() );
2663
2664 pad->Padstack().ForEachUniqueLayer(
2665 [&]( PCB_LAYER_ID aLayer )
2666 {
2667 shapes.insert( pad->GetShape( aLayer ) );
2668 sizes.insert( pad->GetSize( aLayer ) );
2669 } );
2670 }
2671
2672 if( layers.size() == 1 )
2673 msgItems.emplace_back( _( "Layer" ), *layers.begin() );
2674
2675 if( shapes.size() == 1 )
2676 msgItems.emplace_back( _( "Pad Shape" ), PAD::ShowPadShape( *shapes.begin() ) );
2677
2678 if( sizes.size() == 1 )
2679 {
2680 msgItems.emplace_back( _( "Pad Size" ),
2681 wxString::Format( wxT( "%s x %s" ),
2682 m_frame->MessageTextFromValue( sizes.begin()->x ),
2683 m_frame->MessageTextFromValue( sizes.begin()->y ) ) );
2684 }
2685 }
2686 }
2687 else
2688 {
2689 // Show type breakdown for mixed selections
2690 wxString breakdown;
2691
2692 for( const auto& [type, count] : typeCounts )
2693 {
2694 if( !breakdown.IsEmpty() )
2695 breakdown += wxT( ", " );
2696
2697 // Get friendly name from first item of this type
2698 wxString typeName;
2699
2700 for( EDA_ITEM* item : selection )
2701 {
2702 if( item->Type() == type )
2703 {
2704 typeName = item->GetFriendlyName();
2705 break;
2706 }
2707 }
2708
2709 breakdown += wxString::Format( wxT( "%s: %d" ), typeName, count );
2710 }
2711
2712 msgItems.emplace_back( _( "Selected Items" ),
2713 wxString::Format( wxT( "%d (%s)" ), selection.GetSize(), breakdown ) );
2714 }
2715
2716 if( m_isBoardEditor )
2717 {
2718 std::set<wxString> netNames;
2719 std::set<wxString> netClasses;
2720
2721 for( EDA_ITEM* item : selection )
2722 {
2723 if( BOARD_CONNECTED_ITEM* bci = dynamic_cast<BOARD_CONNECTED_ITEM*>( item ) )
2724 {
2725 if( !bci->GetNet() || bci->GetNetCode() <= NETINFO_LIST::UNCONNECTED )
2726 continue;
2727
2728 netNames.insert( UnescapeString( bci->GetNetname() ) );
2729 netClasses.insert( UnescapeString( bci->GetEffectiveNetClass()->GetHumanReadableName() ) );
2730
2731 if( netNames.size() > 1 && netClasses.size() > 1 )
2732 break;
2733 }
2734 }
2735
2736 if( netNames.size() == 1 )
2737 msgItems.emplace_back( _( "Net" ), *netNames.begin() );
2738
2739 if( netClasses.size() == 1 )
2740 msgItems.emplace_back( _( "Resolved Netclass" ), *netClasses.begin() );
2741 }
2742 }
2743
2744 if( selection.GetSize() >= 2 )
2745 {
2746 bool lengthValid = true;
2747 double selectedLength = 0;
2748
2749 // Lambda to accumulate track length if item is a track or arc, otherwise mark invalid
2750 std::function<void( EDA_ITEM* )> accumulateTrackLength;
2751
2752 accumulateTrackLength =
2753 [&]( EDA_ITEM* aItem )
2754 {
2755 if( aItem->Type() == PCB_TRACE_T || aItem->Type() == PCB_ARC_T )
2756 {
2757 selectedLength += static_cast<PCB_TRACK*>( aItem )->GetLength();
2758 }
2759 else if( aItem->Type() == PCB_VIA_T )
2760 {
2761 // zero 2D length
2762 }
2763 else if( aItem->Type() == PCB_SHAPE_T )
2764 {
2765 PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( aItem );
2766
2767 if( shape->GetShape() == SHAPE_T::SEGMENT
2768 || shape->GetShape() == SHAPE_T::ARC
2769 || shape->GetShape() == SHAPE_T::BEZIER )
2770 {
2771 selectedLength += shape->GetLength();
2772 }
2773 else
2774 {
2775 lengthValid = false;
2776 }
2777 }
2778 // Use dynamic_cast to include PCB_GENERATORs.
2779 else if( PCB_GROUP* group = dynamic_cast<PCB_GROUP*>( aItem ) )
2780 {
2781 group->RunOnChildren( accumulateTrackLength, RECURSE_MODE::RECURSE );
2782 }
2783 else
2784 {
2785 lengthValid = false;
2786 }
2787 };
2788
2789 for( EDA_ITEM* item : selection )
2790 {
2791 if( lengthValid )
2792 accumulateTrackLength( item );
2793 }
2794
2795 if( lengthValid )
2796 {
2797 msgItems.emplace_back( _( "Selected 2D Length" ),
2798 m_frame->MessageTextFromValue( selectedLength ) );
2799 }
2800 }
2801
2802 if( selection.GetSize() >= 2 && selection.GetSize() < 100 )
2803 {
2804 LSET enabledLayers = m_frame->GetBoard()->GetEnabledLayers();
2805 LSET enabledCopper = LSET::AllCuMask( m_frame->GetBoard()->GetCopperLayerCount() );
2806 bool areaValid = true;
2807 bool hasCopper = false;
2808 bool hasNonCopper = false;
2809
2810 std::map<PCB_LAYER_ID, SHAPE_POLY_SET> layerPolys;
2811 SHAPE_POLY_SET holes;
2812
2813 std::function<void( EDA_ITEM* )> accumulateArea;
2814
2815 accumulateArea =
2816 [&]( EDA_ITEM* aItem )
2817 {
2818 if( aItem->Type() == PCB_FOOTPRINT_T || aItem->Type() == PCB_MARKER_T )
2819 {
2820 areaValid = false;
2821 return;
2822 }
2823
2824 if( PCB_GROUP* group = dynamic_cast<PCB_GROUP*>( aItem ) )
2825 {
2826 group->RunOnChildren( accumulateArea, RECURSE_MODE::RECURSE );
2827 return;
2828 }
2829
2830 if( BOARD_ITEM* boardItem = dynamic_cast<BOARD_ITEM*>( aItem ) )
2831 {
2832 boardItem->RunOnChildren( accumulateArea, RECURSE_MODE::NO_RECURSE );
2833
2834 LSET itemLayers = boardItem->GetLayerSet() & enabledLayers;
2835
2836 for( PCB_LAYER_ID layer : itemLayers )
2837 {
2838 boardItem->TransformShapeToPolySet( layerPolys[layer], layer, 0,
2840
2841 if( enabledCopper.Contains( layer ) )
2842 hasCopper = true;
2843 else
2844 hasNonCopper = true;
2845 }
2846
2847 if( aItem->Type() == PCB_PAD_T && static_cast<PAD*>( aItem )->HasHole() )
2848 {
2849 static_cast<PAD*>( aItem )->TransformHoleToPolygon( holes, 0, ARC_LOW_DEF,
2850 ERROR_OUTSIDE );
2851 }
2852 else if( aItem->Type() == PCB_VIA_T )
2853 {
2854 PCB_VIA* via = static_cast<PCB_VIA*>( aItem );
2855 VECTOR2I center = via->GetPosition();
2856 int R = via->GetDrillValue() / 2;
2857
2859 }
2860 }
2861 };
2862
2863 for( EDA_ITEM* item : selection )
2864 {
2865 if( areaValid )
2866 accumulateArea( item );
2867 }
2868
2869 if( areaValid )
2870 {
2871 double area = 0.0;
2872
2873 for( auto& [layer, layerPoly] : layerPolys )
2874 {
2875 // Only subtract holes from copper layers
2876 if( enabledCopper.Contains( layer ) )
2877 layerPoly.BooleanSubtract( holes );
2878
2879 area += layerPoly.Area();
2880 }
2881
2882 // Choose appropriate label based on what layers are involved
2883 wxString areaLabel;
2884
2885 if( hasCopper && !hasNonCopper )
2886 areaLabel = _( "Selected 2D Copper Area" );
2887 else if( !hasCopper && hasNonCopper )
2888 areaLabel = _( "Selected 2D Area" );
2889 else
2890 areaLabel = _( "Selected 2D Total Area" );
2891
2892 msgItems.emplace_back( areaLabel,
2893 m_frame->MessageTextFromValue( area, true, EDA_DATA_TYPE::AREA ) );
2894 }
2895 }
2896 }
2897 else
2898 {
2899 m_frame->GetBoard()->GetMsgPanelInfo( m_frame, msgItems );
2900 }
2901
2902 m_frame->SetMsgPanel( msgItems );
2903
2904 // Update vertex editor if it exists
2905 PCB_BASE_EDIT_FRAME* editFrame = dynamic_cast<PCB_BASE_EDIT_FRAME*>( m_frame );
2906 if( editFrame )
2907 {
2908 BOARD_ITEM* selectedItem = ( selection.GetSize() == 1 ) ? dynamic_cast<BOARD_ITEM*>( selection.Front() )
2909 : nullptr;
2910 editFrame->UpdateVertexEditorSelection( selectedItem );
2911 }
2912
2913 return 0;
2914}
2915
2916
2918{
2919 wxFileName fileName = wxFileName( *aEvent.Parameter<wxString*>() );
2920
2921 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
2922
2923 if( !editFrame )
2924 return 1;
2925
2926 wxString filePath = fileName.GetFullPath();
2928 IO_RELEASER<PCB_IO> pi( PCB_IO_MGR::FindPlugin( pluginType ) );
2929
2930 if( !pi )
2931 return 1;
2932
2933 return AppendBoard( *pi, filePath );
2934}
2935
2936
2938{
2939 BOARD_COMMIT commit( this );
2940 EDA_UNITS displayUnit = m_frame->GetUserUnits();
2941 PCB_TABLE* table = Build_Board_Characteristics_Table( m_frame->GetBoard(), displayUnit );
2942 table->SetLayer( m_frame->GetActiveLayer() );
2943
2944 std::vector<BOARD_ITEM*> items;
2945 items.push_back( table );
2946
2947 if( placeBoardItems( &commit, items, true, true, false, false ) )
2948 commit.Push( _( "Place Board Characteristics" ) );
2949 else
2950 delete table;
2951
2952 return 0;
2953}
2954
2955
2957{
2958 BOARD_COMMIT commit( this );
2959 EDA_UNITS displayUnit = m_frame->GetUserUnits();
2960
2961 PCB_TABLE* table = Build_Board_Stackup_Table( m_frame->GetBoard(), displayUnit );
2962 table->SetLayer( m_frame->GetActiveLayer() );
2963
2964 std::vector<BOARD_ITEM*> items;
2965 items.push_back( table );
2966
2967 if( placeBoardItems( &commit, items, true, true, false, false ) )
2968 commit.Push( _( "Place Board Stackup Table" ) );
2969 else
2970 delete table;
2971
2972 return 0;
2973}
2974
2975
2977{
2978 BOARD* board = m_frame->GetBoard();
2979
2980 // Copper, silk, mask, paste, adhesive, Edge.Cuts, Margin and courtyard are manufacturing
2981 // inputs a chart would corrupt. Unlike a map, a chart may share a layer with another
2982 const auto available =
2983 [board]( PCB_LAYER_ID aLayer )
2984 {
2985 return DrillDocumentationLayers().Contains( aLayer ) && board->IsLayerEnabled( aLayer );
2986 };
2987
2988 PCB_LAYER_ID layer = m_frame->GetActiveLayer();
2989
2990 if( !available( layer ) )
2991 {
2992 const LSEQ candidates = DrillDocumentationLayers().Seq();
2993 const auto next = std::find_if( candidates.begin(), candidates.end(), available );
2994
2995 if( next == candidates.end() )
2996 {
2997 m_frame->ShowInfoBarError( _( "No documentation layer is enabled to hold a drill "
2998 "chart." ) );
2999 return 0;
3000 }
3001
3002 layer = *next;
3003 m_frame->SetActiveLayer( layer );
3004 }
3005
3006 // Placing onto a hidden layer draws nothing at all, which is indistinguishable from the
3007 // feature being broken
3008 if( !board->IsLayerVisible( layer ) )
3009 {
3010 m_frame->ShowInfoBarWarning( wxString::Format(
3011 _( "Layer '%s' is hidden; nothing will be shown until you make it visible." ),
3012 board->GetLayerName( layer ) ) );
3013 }
3014
3015 BOARD_COMMIT commit( this );
3016
3017 PCB_DRILL_CHART* chart = new PCB_DRILL_CHART( board );
3018
3019 // Seeded from the board, not default-constructed. RebuildCells builds on whatever it is
3020 // handed, so a default here would drop the board's grouping and its existing marks
3021 DRILL_SYMBOL_PROFILE assigned = board->GetDesignSettings().GetDrillSymbolProfile();
3022
3023 chart->SetLayer( layer );
3024 chart->RebuildCells( *board, &assigned );
3025
3026 // Cascade off any chart already on this layer rather than landing on top of it
3027 int existing = 0;
3028
3029 for( BOARD_ITEM* item : board->Drawings() )
3030 {
3031 if( item->Type() == PCB_DRILL_CHART_T && item->GetLayer() == layer )
3032 existing++;
3033 }
3034
3035 if( existing )
3036 {
3037 const BOX2I bbox = chart->GetBoundingBox();
3038 chart->Move( VECTOR2I( 0, existing * ( bbox.GetHeight() + pcbIUScale.mmToIU( 5 ) ) ) );
3039 }
3040
3041 std::vector<BOARD_ITEM*> items;
3042 items.push_back( chart );
3043
3044 if( placeBoardItems( &commit, items, true, true, false, false ) )
3045 {
3046 // Only now do the assignments become the board's. The profile is design settings,
3047 // which KiCad does not undo, so the board is marked dirty instead
3048 board->GetDesignSettings().GetDrillSymbolProfile() = assigned;
3049 m_frame->OnModify();
3050
3051 commit.Push( _( "Place Drill Chart" ) );
3052 }
3053 else
3054 {
3055 delete chart;
3056 }
3057
3058 return 0;
3059}
3060
3061
3063{
3064 BOARD* board = m_frame->GetBoard();
3065
3066 // Two maps on one layer would overdraw each other's marks, so an occupied layer is no
3067 // more available than one that cannot hold a map at all
3068 const auto available =
3069 [&]( PCB_LAYER_ID aLayer )
3070 {
3071 if( !DrillDocumentationLayers().Contains( aLayer ) || !board->IsLayerEnabled( aLayer ) )
3072 return false;
3073
3074 for( const BOARD_ITEM* item : board->Drawings() )
3075 {
3076 if( item->Type() == PCB_DRILL_MAP_T && item->GetLayer() == aLayer )
3077 return false;
3078 }
3079
3080 return true;
3081 };
3082
3083 PCB_LAYER_ID layer = m_frame->GetActiveLayer();
3084
3085 if( !available( layer ) )
3086 {
3087 const LSEQ candidates = DrillDocumentationLayers().Seq();
3088 const auto next = std::find_if( candidates.begin(), candidates.end(), available );
3089
3090 if( next == candidates.end() )
3091 {
3092 m_frame->ShowInfoBarError( _( "Every documentation layer already has a drill map." ) );
3093 return 0;
3094 }
3095
3096 layer = *next;
3097 m_frame->SetActiveLayer( layer );
3098 }
3099
3100 // Placing onto a hidden layer draws nothing at all, which is indistinguishable from the
3101 // feature being broken
3102 if( !board->IsLayerVisible( layer ) )
3103 {
3104 m_frame->ShowInfoBarWarning( wxString::Format(
3105 _( "Layer '%s' is hidden; nothing will be shown until you make it visible." ),
3106 board->GetLayerName( layer ) ) );
3107 }
3108
3109 BOARD_COMMIT commit( this );
3110
3111 // A map draws on the holes, so there is nothing to drag into place. It lands at zero
3112 // offset and the user moves it from there
3113 PCB_DRILL_MAP* map = new PCB_DRILL_MAP( board );
3114 map->SetLayer( layer );
3115
3116 commit.Add( map );
3117 commit.Push( _( "Place Drill Map" ) );
3118
3119 m_toolMgr->RunAction( ACTIONS::selectionClear );
3120 m_toolMgr->RunAction<EDA_ITEM*>( PCB_ACTIONS::selectItem, map );
3121
3122 return 0;
3123}
3124
3125
3127{
3128
3129 PCB_EDIT_FRAME* frame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
3130
3131 if( !frame )
3132 return 0;
3133
3135 {
3136 m_drillGroupsDialog->Raise();
3137 return 0;
3138 }
3139
3141 m_drillGroupsDialog = dialog;
3142 dialog->Show( true );
3143
3144 return 0;
3145}
3146
3147
3149{
3150 PCB_DISPLAY_OPTIONS opts = m_frame->GetDisplayOptions();
3151 opts.m_FlipBoardView = !opts.m_FlipBoardView;
3152 m_frame->SetDisplayOptions( opts );
3153
3154 return 0;
3155}
3156
3157
3159{
3160 if( aItem->Type() != PCB_SHAPE_T )
3161 return;
3162
3163 PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( aItem );
3164
3165 // Re-caching every non-hatched shape on each edit stalls commits on dense boards.
3166 if( !shape->IsHatchedFill() )
3167 return;
3168
3169 shape->UpdateHatching();
3170
3171 if( aView )
3172 aView->Update( aItem );
3173}
3174
3175
3177{
3178 KIGFX::VIEW* view = this->view();
3179
3180 for( FOOTPRINT* footprint : board()->Footprints() )
3181 footprint->RunOnChildren( std::bind( &PCB_CONTROL::rehatchBoardItem, view, _1 ), NO_RECURSE );
3182
3183 for( BOARD_ITEM* item : board()->Drawings() )
3184 rehatchBoardItem( view, item );
3185
3186 return 0;
3187}
3188
3189
3191{
3192 BOARD* brd = board();
3193
3194 if( !brd )
3195 return 0;
3196
3197 PROJECT& prj = m_frame->Prj();
3199 FILENAME_RESOLVER* resolver = cache ? cache->GetResolver() : nullptr;
3200
3201 wxString workingPath = prj.GetProjectPath();
3202 std::vector<const EMBEDDED_FILES*> stack;
3203 stack.push_back( brd->GetEmbeddedFiles() );
3204
3205 BOARD_COMMIT commit( m_frame );
3206 int embeddedCount = 0;
3207
3208 for( FOOTPRINT* fp : brd->Footprints() )
3209 {
3210 bool fpModified = false;
3211
3212 for( FP_3DMODEL& model : fp->Models() )
3213 {
3214 if( model.m_Filename.StartsWith( FILEEXT::KiCadUriPrefix ) )
3215 continue;
3216
3217 wxString fullPath =
3218 resolver ? resolver->ResolvePath( model.m_Filename, workingPath, stack )
3219 : model.m_Filename;
3220
3221 wxFileName fname( fullPath );
3222 wxString ext = fname.GetExt().Upper();
3223
3224 if( fname.Exists() )
3225 {
3227 brd->GetEmbeddedFiles()->AddFile( fname, false ) )
3228 {
3229 model.m_Filename = file->GetLink();
3230 fpModified = true;
3231 embeddedCount++;
3232
3233 // Store STEP along with WRL for the OCCT(STEP) exporter.
3234 if( ext == "WRL" || ext == "WRZ" )
3235 {
3236 wxArrayString alts;
3237
3238 // Step files
3239 alts.Add( wxT( "stp" ) );
3240 alts.Add( wxT( "step" ) );
3241 alts.Add( wxT( "STP" ) );
3242 alts.Add( wxT( "STEP" ) );
3243 alts.Add( wxT( "Stp" ) );
3244 alts.Add( wxT( "Step" ) );
3245 alts.Add( wxT( "stpz" ) );
3246 alts.Add( wxT( "stpZ" ) );
3247 alts.Add( wxT( "STPZ" ) );
3248
3249 for( const auto& alt : alts )
3250 {
3251 wxFileName altFile( fname.GetPath(),
3252 fname.GetName() + wxT( "." ) + alt );
3253
3254 if( altFile.IsOk() && altFile.FileExists() )
3255 {
3256 brd->GetEmbeddedFiles()->AddFile( altFile, false );
3257 break;
3258 }
3259 }
3260 }
3261 }
3262 }
3263 }
3264
3265 if( fpModified )
3266 commit.Modify( fp );
3267 }
3268
3269 if( embeddedCount > 0 )
3270 {
3271 commit.Push( _( "Embed 3D Models" ) );
3272 wxString msg = wxString::Format( _( "%d 3D model(s) successfully embedded." ), embeddedCount );
3273 m_frame->GetInfoBar()->ShowMessageFor( msg, 5000 );
3274 }
3275
3276 return 0;
3277}
3278
3279
3280// clang-format off
3282{
3285 Go( &PCB_CONTROL::Print, ACTIONS::print.MakeEvent() );
3286
3287 // Footprint library actions
3292
3293 // Display modes
3310
3311 // Layer control
3349
3352
3353 // Grid control
3356
3357 Go( &PCB_CONTROL::Undo, ACTIONS::undo.MakeEvent() );
3358 Go( &PCB_CONTROL::Redo, ACTIONS::redo.MakeEvent() );
3359
3360 // Snapping control
3365
3366 // Miscellaneous
3369
3370 // Append control
3382
3383 Go( &PCB_CONTROL::Paste, ACTIONS::paste.MakeEvent() );
3385
3392
3393 // Add library by dropping file
3396}
3397// clang-format on
const char * name
@ ERROR_OUTSIDE
@ ERROR_INSIDE
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:121
constexpr int ARC_LOW_DEF
Definition base_units.h:136
std::set< BOARD_ITEM *, CompareByUuid > BOARD_ITEM_SET
Set of BOARD_ITEMs ordered by UUID.
Definition board.h:393
PCB_TABLE * Build_Board_Characteristics_Table(BOARD *aBoard, EDA_UNITS aDisplayUnits)
@ NORMAL
Inactive layers are shown normally (no high-contrast mode)
@ HIDDEN
Inactive layers are hidden.
@ DIMMED
Inactive layers are dimmed (old high-contrast mode)
@ RATSNEST
Net/netclass colors are shown on ratsnest lines only.
@ ALL
Net/netclass colors are shown on all net copper.
@ OFF
Net (and netclass) colors are not shown.
@ VISIBLE
Ratsnest lines are drawn to items on visible layers only.
@ ALL
Ratsnest lines are drawn to items on all layers (default)
PCB_TABLE * Build_Board_Stackup_Table(BOARD *aBoard, EDA_UNITS aDisplayUnits)
BOX2< VECTOR2I > BOX2I
Definition box2.h:927
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:995
static TOOL_ACTION paste
Definition actions.h:76
static TOOL_ACTION selectItem
Select an item (specified as the event parameter).
Definition actions.h:223
static TOOL_ACTION addLibrary
Definition actions.h:52
static TOOL_ACTION pickerTool
Definition actions.h:249
static TOOL_ACTION gridResetOrigin
Definition actions.h:192
static TOOL_ACTION pasteSpecial
Definition actions.h:77
static TOOL_ACTION highContrastModeCycle
Definition actions.h:152
static TOOL_ACTION undo
Definition actions.h:71
static TOOL_ACTION highContrastMode
Definition actions.h:151
static TOOL_ACTION redo
Definition actions.h:72
static TOOL_ACTION deleteTool
Definition actions.h:82
static TOOL_ACTION selectionClear
Clear the current selection.
Definition actions.h:220
static TOOL_ACTION print
Definition actions.h:60
static TOOL_ACTION newLibrary
Definition actions.h:51
static TOOL_ACTION gridSetOrigin
Definition actions.h:191
static TOOL_ACTION ddAddLibrary
Definition actions.h:63
static TOOL_ACTION selectItems
Select a list of items (specified as the event parameter)
Definition actions.h:228
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
APP_SETTINGS_BASE is a settings class that should be derived for each standalone KiCad application.
virtual void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Execute the changes.
virtual void Revert() override
Revert the commit by restoring the modified items state.
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
NETINFO_ITEM * GetNet() const
Return #NET_INFO object for a given item.
void SetGridOrigin(const VECTOR2I &aOrigin)
BOARD_STACKUP & GetStackupDescriptor()
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:84
virtual bool IsConnected() const
Returns information if the object is derived from BOARD_CONNECTED_ITEM.
Definition board_item.h:172
virtual std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, DRC_CONSTRAINT_T aUsage=NULL_CONSTRAINT) const
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
virtual bool IsOnLayer(PCB_LAYER_ID aLayer) const
Test to see if this object is on the given layer.
Definition board_item.h:408
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition board_item.h:374
FOOTPRINT * GetParentFootprint() const
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition board_item.h:346
virtual bool IsOnCopperLayer() const
Definition board_item.h:189
virtual std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING aFlash=FLASHING::DEFAULT, DRC_CONSTRAINT_T aUsage=NULL_CONSTRAINT) const
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
virtual bool HasHole() const
Definition board_item.h:207
virtual void RemapKIIDs(const std::map< KIID, KIID > &aIdMap)
Remap KIIDs this item stores to reference other items (e.g.
Definition board_item.h:287
bool SynchronizeWithBoard(BOARD_DESIGN_SETTINGS *aSettings)
Synchronize the BOARD_STACKUP_ITEM* list with the board.
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:409
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:2828
EMBEDDED_FILES * GetEmbeddedFiles() override
Definition board.cpp:3825
void SetVisibleLayers(const LSET &aLayerMask)
A proxy function that calls the correspondent function in m_BoardSettings changes the bit-mask of vis...
Definition board.cpp:1216
void MapNets(BOARD *aDestBoard)
Map all nets in the given board to nets with the same name (if any) in the destination board.
Definition board.cpp:3936
void BuildListOfNets()
Definition board.h:1170
const std::vector< BOARD_CONNECTED_ITEM * > AllConnectedItems()
Definition board.cpp:3901
const PAGE_INFO & GetPageSettings() const
Definition board.h:1010
void SetProperties(const std::map< wxString, wxString > &aProps)
Definition board.h:518
const GROUPS & Groups() const
The groups must maintain the following invariants.
Definition board.h:509
bool BuildConnectivity(PROGRESS_REPORTER *aReporter=nullptr)
Build or rebuild the board connectivity database for the board, especially the list of connected item...
Definition board.cpp:364
void SynchronizeNetsAndNetClasses(bool aResetTrackAndViaSizes)
Copy NETCLASS info to each NET, based on NET membership in a NETCLASS.
Definition board.cpp:3402
FOOTPRINT * GetFirstFootprint() const
Get the first footprint on the board or nullptr.
Definition board.h:704
TITLE_BLOCK & GetTitleBlock()
Definition board.h:1016
int GetCopperLayerCount() const
Definition board.cpp:1131
const std::map< wxString, wxString > & GetProperties() const
Definition board.h:517
const FOOTPRINTS & Footprints() const
Definition board.h:463
void RemoveAll(std::initializer_list< KICAD_T > aTypes={ PCB_NETINFO_T, PCB_MARKER_T, PCB_GROUP_T, PCB_ZONE_T, PCB_GENERATOR_T, PCB_FOOTPRINT_T, PCB_TRACE_T, PCB_SHAPE_T })
An efficient way to remove all items of a certain type from the board.
Definition board.cpp:1782
const BOARD_ITEM_SET GetItemSet()
Collect every owned item (tracks, zones, generators, footprints, drawings, markers,...
Definition board.cpp:4377
void SetPageSettings(const PAGE_INFO &aPageSettings)
Definition board.h:1011
const CONSTRAINTS & Constraints() const
Geometric constraints (#2329) owned by this board.
Definition board.h:513
void SetCopperLayerCount(int aCount)
Definition board.cpp:1137
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:1189
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition board.cpp:1299
const LSET & GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition board.cpp:1183
void Remove(BOARD_ITEM *aBoardItem, REMOVE_MODE aMode=REMOVE_MODE::NORMAL) override
Removes an item from the container.
Definition board.cpp:1668
void SetEnabledLayers(const LSET &aLayerMask)
A proxy function that calls the correspondent function in m_BoardSettings.
Definition board.cpp:1203
void SetTitleBlock(const TITLE_BLOCK &aTitleBlock)
Definition board.h:1018
const DRAWINGS & Drawings() const
Definition board.h:465
constexpr size_type GetHeight() const
Definition box2.h:212
BOARD_ITEM * Parse()
int GetCount() const
Return the number of objects in the list.
Definition collector.h:79
void Remove(int aIndex)
Remove the item at aIndex (first position is 0).
Definition collector.h:107
int m_Threshold
Definition collector.h:234
Color settings are a bit different than most of the settings objects in that there can be more than o...
void SetColor(int aLayer, const COLOR4D &aColor)
COLOR4D GetColor(int aLayer) const
COMMIT & Added(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Notify observers that aItem has been added.
Definition commit.h:80
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr, RECURSE_MODE aRecurse=RECURSE_MODE::NO_RECURSE)
Modify a given item in the model.
Definition commit.h:102
COMMIT & Add(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Add a new item to the model.
Definition commit.h:74
DO_NOT_SHOW_AGAIN m_DoNotShowAgain
void SelectLibId(const LIB_ID &aLibId)
LIB_ID GetSelectedLibId(int *aUnit=nullptr) const
DESIGN_BLOCK * GetDesignBlock(const LIB_ID &aLibId, bool aUseCacheLib, bool aShowErrorMsg, wxString *aErrorMsg=nullptr)
Load design block from design block library table.
const LIB_ID & GetLibId() const
Modeless inspector for the board's drill groups.
static std::map< wxString, PCB_LAYER_ID > RunModal(wxWindow *aParent, const std::vector< INPUT_LAYER_DESC > &aLayerDesc)
Create and show a dialog (modal) and returns the data from it after completion.
bool Show(bool show) override
int ShowModal() override
wxString GetName() const
Definition drc_rule.h:208
MINOPTMAX< int > & Value()
Definition drc_rule.h:201
MINOPTMAX< int > m_Value
Definition drc_rule.h:244
Grouping rules and symbol assignments, shared by reference so a chart and its map can never disagree ...
virtual APP_SETTINGS_BASE * config() const
Return the settings object used in SaveSettings(), and is overloaded in KICAD_MANAGER_FRAME.
void ShowInfoBarError(const wxString &aErrorMsg, bool aShowCloseButton=false, INFOBAR_MESSAGE_TYPE aType=INFOBAR_MESSAGE_TYPE::GENERIC)
Show the WX_INFOBAR displayed on the top of the canvas with a message and an error icon on the left o...
WX_INFOBAR * GetInfoBar()
bool GetOverrideLocks() const
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
A set of EDA_ITEMs (i.e., without duplicates).
Definition eda_group.h:43
bool HasDesignBlockLink() const
Definition eda_group.h:85
void RemoveItem(EDA_ITEM *aItem)
Remove item from group.
Definition eda_group.cpp:77
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:98
virtual void SetPosition(const VECTOR2I &aPos)
Definition eda_item.h:349
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition eda_item.h:158
virtual wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const
Return a user-visible description string of this item.
Definition eda_item.cpp:304
const KIID m_Uuid
Definition eda_item.h:597
virtual EDA_GROUP * GetParentGroup() const
Definition eda_item.h:116
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition eda_item.h:160
virtual void GetMsgPanelInfo(EDA_DRAW_FRAME *aFrame, std::vector< MSG_PANEL_ITEM > &aList)
Populate aList of MSG_PANEL_ITEM objects with it's internal state for display purposes.
Definition eda_item.h:296
bool HasFlag(EDA_ITEM_FLAGS aFlag) const
Definition eda_item.h:168
virtual void SetParent(EDA_ITEM *aParent)
Definition eda_item.cpp:153
SHAPE_T GetShape() const
Definition eda_shape.h:175
bool IsHatchedFill() const
Definition eda_shape.h:130
double GetLength() const
bool validatePasteIntoSelection(const SELECTION &aSel, wxString &aErrorMsg)
Validate if paste-into-cells is possible for the given selection.
bool pasteCellsIntoSelection(const SELECTION &aSel, T_TABLE *aSourceTable, T_COMMIT &aCommit)
Paste text content from source table into selected cells.
The interactive edit tool.
Definition edit_tool.h:54
void DeleteItems(const PCB_SELECTION &aItem, bool aIsCut)
EMBEDDED_FILE * AddFile(const wxFileName &aName, bool aOverwrite)
Load a file from disk and adds it to the collection.
static const TOOL_EVENT ClearedEvent
Definition actions.h:345
static const TOOL_EVENT SelectedEvent
Definition actions.h:343
static const TOOL_EVENT SelectedItemsModified
Selected items were moved, this can be very high frequency on the canvas, use with care.
Definition actions.h:350
static const TOOL_EVENT PointSelectedEvent
Definition actions.h:342
static const TOOL_EVENT ContrastModeChangedByKeyEvent
Definition actions.h:364
static const TOOL_EVENT ConnectivityChangedEvent
Selected item had a property changed (except movement)
Definition actions.h:347
static const TOOL_EVENT UnselectedEvent
Definition actions.h:344
Provide an extensible class to resolve 3D model paths.
Component library viewer main window.
EDA_ANGLE GetOrientation() const
Definition footprint.h:438
ZONES & Zones()
Definition footprint.h:410
CONSTRAINTS & Constraints()
Definition footprint.h:416
std::deque< PAD * > & Pads()
Definition footprint.h:404
void ResolveComponentClassNames(BOARD *aBoard, const std::unordered_set< wxString > &aComponentClassNames)
Resolves a set of component class names to this footprint's actual component class.
const std::unordered_set< wxString > & GetTransientComponentClassNames()
Gets the transient component class names.
Definition footprint.h:1438
void SetReference(const wxString &aReference)
Definition footprint.h:907
bool IsLocked() const override
Definition footprint.h:680
void ClearTransientComponentClassNames()
Remove the transient component class names.
Definition footprint.h:1444
void GetMsgPanelInfo(EDA_DRAW_FRAME *aFrame, std::vector< MSG_PANEL_ITEM > &aList) override
Populate aList of MSG_PANEL_ITEM objects with it's internal state for display purposes.
GROUPS & Groups()
Definition footprint.h:413
void GetFields(std::vector< PCB_FIELD * > &aVector, bool aVisibleOnly) const
Populate a std::vector with PCB_TEXTs.
DRAWINGS & GraphicalItems()
Definition footprint.h:407
A general implementation of a COLLECTORS_GUIDE.
Definition collectors.h:320
Used when the right click button is pressed, or when the select tool is in effect.
Definition collectors.h:203
static const std::vector< KICAD_T > BoardLevelItems
A scan list for all primary board items, omitting items which are subordinate to a FOOTPRINT,...
Definition collectors.h:69
static const std::vector< KICAD_T > AllBoardItems
A scan list for all editable board items.
Definition collectors.h:38
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.
static const std::vector< KICAD_T > FootprintItems
A scan list for primary footprint items.
Definition collectors.h:110
Similar to EDA_VIEW_SWITCHER, this dialog is a popup that shows feedback when using a hotkey to cycle...
void Popup(const wxString &aTitle, const wxArrayString &aItems, int aSelection)
void SetDialogSizeInDU(int aWidth, int aHeight)
Set the dialog size, using a "logical" value.
void AddHTML_Text(const wxString &message)
Add HTML text (without any change) to message list.
virtual void SetProgressReporter(PROGRESS_REPORTER *aReporter)
Set an optional progress reporter.
Definition io_base.h:94
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
virtual const wxString What() const
A composite of Problem() and Where()
Helper class to create more flexible dialogs, including 'do not show again' checkbox handling.
Definition kidialog.h:38
void DoNotShowCheckbox(wxString file, int line)
Shows the 'do not show again' checkbox.
Definition kidialog.cpp:51
int ShowModal() override
Definition kidialog.cpp:89
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:101
COLOR4D & Darken(double aFactor)
Makes the color darker by a given factor.
Definition color4d.h:223
COLOR4D & Brighten(double aFactor)
Makes the color brighter by a given factor.
Definition color4d.h:206
double a
Alpha component.
Definition color4d.h:393
void SetGridOrigin(const VECTOR2D &aGridOrigin)
Set the origin point for the grid.
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:87
virtual void SetCursorPosition(const VECTOR2D &aPosition, bool aWarpView=true, bool aTriggeredByArrows=false, long aArrowCommand=0)=0
Move cursor to the requested position expressed in world coordinates.
bool IsBOARD_ITEM() const
Definition view_item.h:98
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition view.h:63
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition view.cpp:301
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition view.cpp:416
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:1852
GAL * GetGAL() const
Return the GAL this view is using to draw graphical primitives.
Definition view.h:207
void MarkDirty()
Force redraw of view on the next rendering.
Definition view.h:679
Definition kiid.h:46
Plugin class for import plugins that support remappable layers.
All information about a layer pair as stored in the layer pair store.
Management class for layer pairs in a PCB.
Definition layer_pairs.h:43
std::vector< LAYER_PAIR_INFO > GetEnabledLayerPairs(int &aCurrentIndex) const
Get a vector of all enabled layer pairs, in order.
void SetCurrentLayerPair(const LAYER_PAIR &aPair)
Set the "active" layer pair.
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:45
bool IsValid() const
Check if this LID_ID is valid.
Definition lib_id.h:168
const UTF8 & GetLibItemName() const
Definition lib_id.h:98
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
Definition lseq.h:47
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
static const LSET & AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
Definition lset.cpp:604
LSEQ UIOrder() const
Return the copper, technical and user layers in the order shown in layer widget.
Definition lset.cpp:739
LSEQ CuStack() const
Return a sequence of copper layers in starting from the front/top and extending to the back/bottom.
Definition lset.cpp:259
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition lset.cpp:309
static LSET AllCuMask(int aCuLayerCount)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition lset.cpp:595
bool Contains(PCB_LAYER_ID aLayer) const
See if the layer set contains a PCB layer.
Definition lset.h:63
T Min() const
Definition minoptmax.h:29
bool HasMax() const
Definition minoptmax.h:35
T Max() const
Definition minoptmax.h:30
EDA_MSG_PANEL items for displaying messages.
Definition msgpanel.h:50
static std::vector< NETINFO_ITEM * > IsolateDesignBlockAutoNets(BOARD *aBoard, const std::set< FOOTPRINT * > &aFootprints, const std::unordered_set< EDA_ITEM * > &aItems)
Remap auto-generated nets (Net-(...), unconnected-...) of a design block that was appended for layout...
int RepeatLayout(const TOOL_EVENT &aEvent, ZONE *aRefZone)
Handle the data for a net.
Definition netinfo.h:50
static const int UNCONNECTED
Constant that holds the "unconnected net" number (typically 0) all items "connected" to this net are ...
Definition netinfo.h:280
static NETINFO_ITEM * OrphanedItem()
NETINFO_ITEM meaning that there was no net assigned for an item, as there was no board storing net li...
Definition netinfo.h:288
Definition pad.h:61
static wxString ShowPadShape(PAD_SHAPE aShape)
Definition pad.cpp:2540
bool HasHole() const override
Definition pad.h:113
Describe the page size and margins of a paper page on which to eventually print or plot.
Definition page_info.h:75
static TOOL_ACTION layerToggle
static TOOL_ACTION layerInner12
static TOOL_ACTION nextFootprint
static TOOL_ACTION layerInner8
static TOOL_ACTION zoneDisplayToggle
static TOOL_ACTION previousFootprint
static TOOL_ACTION layerInner3
static TOOL_ACTION layerPrev
static TOOL_ACTION showRatsnest
static TOOL_ACTION zoneFillAll
static TOOL_ACTION layerInner2
static TOOL_ACTION magneticSnapAllLayers
static TOOL_ACTION collect3DModels
static TOOL_ACTION saveToLinkedDesignBlock
static TOOL_ACTION placeDrillMap
static TOOL_ACTION ddAppendBoard
Drag and drop.
static TOOL_ACTION layerInner25
static TOOL_ACTION magneticSnapActiveLayer
Snapping controls.
static TOOL_ACTION layerAlphaDec
static TOOL_ACTION zoneDisplayFilled
static TOOL_ACTION layerInner24
static TOOL_ACTION viaDisplayMode
static TOOL_ACTION layerInner29
static TOOL_ACTION placeCharacteristics
static TOOL_ACTION layerInner11
static TOOL_ACTION layerAlphaInc
static TOOL_ACTION layerPairPresetsCycle
static TOOL_ACTION layerInner16
static TOOL_ACTION layerInner26
static TOOL_ACTION layerInner18
static TOOL_ACTION layerInner14
static TOOL_ACTION trackDisplayMode
static TOOL_ACTION magneticSnapToggle
static TOOL_ACTION layerInner6
static TOOL_ACTION applyDesignBlockLayout
static TOOL_ACTION ddImportFootprint
static TOOL_ACTION zoneDisplayTriangulated
static TOOL_ACTION rehatchShapes
static TOOL_ACTION layerInner22
static TOOL_ACTION placeDesignBlock
static TOOL_ACTION layerInner5
static TOOL_ACTION zoneDisplayFractured
static TOOL_ACTION ratsnestModeCycle
static TOOL_ACTION layerInner20
static TOOL_ACTION layerInner7
static TOOL_ACTION layerInner27
static TOOL_ACTION loadFpFromBoard
static TOOL_ACTION appendBoard
static TOOL_ACTION netColorModeCycle
static TOOL_ACTION layerInner1
static TOOL_ACTION layerInner10
static TOOL_ACTION layerInner15
static TOOL_ACTION layerInner17
static TOOL_ACTION flipBoard
static TOOL_ACTION layerBottom
static TOOL_ACTION zoneDisplayOutline
static TOOL_ACTION ratsnestLineMode
static TOOL_ACTION layerInner19
static TOOL_ACTION layerInner9
static TOOL_ACTION showDrillGroups
static TOOL_ACTION placeDrillChart
static TOOL_ACTION move
move or drag an item
static TOOL_ACTION layerInner30
static TOOL_ACTION layerTop
static TOOL_ACTION updateDesignBlockFromSelection
static TOOL_ACTION layerInner4
static TOOL_ACTION layerInner13
static TOOL_ACTION layerInner21
static TOOL_ACTION saveFpToBoard
static TOOL_ACTION layerNext
static TOOL_ACTION placeLinkedDesignBlock
static TOOL_ACTION placeStackup
static TOOL_ACTION layerInner23
static TOOL_ACTION layerInner28
Common, abstract interface for edit frames.
void RestoreCopyFromUndoList(wxCommandEvent &aEvent)
Undo the last edit:
APPEARANCE_CONTROLS * GetAppearancePanel()
void RestoreCopyFromRedoList(wxCommandEvent &aEvent)
Redo the last edit:
void UpdateVertexEditorSelection(BOARD_ITEM *aItem)
Base PCB main window class for Pcbnew, Gerbview, and CvPcb footprint viewer.
const VECTOR2I GetPageSizeIU() const override
Works off of GetPageSettings() to return the size of the paper page in the internal units of this par...
void OnModify() override
Must be called after a change in order to set the "modify" flag and update other data structures and ...
BOARD * GetBoard() const
virtual BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Return the BOARD_DESIGN_SETTINGS for the open project.
A geometric constraint between board items (issue #2329).
int PlaceDrillChart(const TOOL_EVENT &aEvent)
int RehatchShapes(const TOOL_EVENT &aEvent)
void setTransitions() override
< Sets up handlers for various events.
int AppendBoardFromFile(const TOOL_EVENT &aEvent)
int AddLibrary(const TOOL_EVENT &aEvent)
int DdAppendBoard(const TOOL_EVENT &aEvent)
int LoadFpFromBoard(const TOOL_EVENT &aEvent)
int SaveToLinkedDesignBlock(const TOOL_EVENT &aEvent)
int DdImportFootprint(const TOOL_EVENT &aEvent)
int SnapModeFeedback(const TOOL_EVENT &aEvent)
int NetColorModeCycle(const TOOL_EVENT &aEvent)
int SaveFpToBoard(const TOOL_EVENT &aEvent)
int RatsnestModeCycle(const TOOL_EVENT &aEvent)
int TrackDisplayMode(const TOOL_EVENT &aEvent)
int DdAddLibrary(const TOOL_EVENT &aEvent)
int ShowDrillGroups(const TOOL_EVENT &aEvent)
int Redo(const TOOL_EVENT &aEvent)
int PlaceLinkedDesignBlock(const TOOL_EVENT &aEvent)
bool placeBoardItems(BOARD_COMMIT *aCommit, std::vector< BOARD_ITEM * > &aItems, bool aIsNew, bool aAnchorAtOrigin, bool aReannotateDuplicates, bool aSkipMove)
Add and select or just select for move/place command a list of board items.
int LayerPresetFeedback(const TOOL_EVENT &aEvent)
int UpdateMessagePanel(const TOOL_EVENT &aEvent)
int LayerAlphaDec(const TOOL_EVENT &aEvent)
static void rehatchBoardItem(KIGFX::VIEW *aView, BOARD_ITEM *aItem)
Regenerate and redraw an item's hatching, skipping non-hatched shapes. Static for testing.
int LayerNext(const TOOL_EVENT &aEvent)
int PlaceStackup(const TOOL_EVENT &aEvent)
std::unique_ptr< STATUS_TEXT_POPUP > m_statusPopup
int ToggleRatsnest(const TOOL_EVENT &aEvent)
int LayerAlphaInc(const TOOL_EVENT &aEvent)
int HighContrastModeCycle(const TOOL_EVENT &aEvent)
std::unique_ptr< KIGFX::ORIGIN_VIEWITEM > m_gridOrigin
int HighContrastMode(const TOOL_EVENT &aEvent)
int Undo(const TOOL_EVENT &aEvent)
int ViaDisplayMode(const TOOL_EVENT &aEvent)
PCB_BASE_FRAME * m_frame
static void DoSetGridOrigin(KIGFX::VIEW *aView, PCB_BASE_FRAME *aFrame, EDA_ITEM *originViewItem, const VECTOR2D &aPoint)
int CollectAndEmbed3DModels(const TOOL_EVENT &aEvent)
void pruneItemLayers(std::vector< BOARD_ITEM * > &aItems)
Helper for pasting.
int GridPlaceOrigin(const TOOL_EVENT &aEvent)
int FlipPcbView(const TOOL_EVENT &aEvent)
int PlaceCharacteristics(const TOOL_EVENT &aEvent)
wxWeakRef< wxDialog > m_drillGroupsDialog
Modeless, so it outlives the action that opened it.
int ApplyDesignBlockLayout(const TOOL_EVENT &aEvent)
int SnapMode(const TOOL_EVENT &aEvent)
int ContrastModeFeedback(const TOOL_EVENT &aEvent)
int LayerToggle(const TOOL_EVENT &aEvent)
int AppendBoard(PCB_IO &pi, const wxString &fileName, DESIGN_BLOCK *aDesignBlock=nullptr, BOARD_COMMIT *aCommit=nullptr, bool aSkipMove=false)
void Reset(RESET_REASON aReason) override
Bring the tool to a known, initial state.
int IterateFootprint(const TOOL_EVENT &aEvent)
int Print(const TOOL_EVENT &aEvent)
int ZoneDisplayMode(const TOOL_EVENT &aEvent)
int GridResetOrigin(const TOOL_EVENT &aEvent)
BOARD_ITEM * m_pickerItem
int InteractiveDelete(const TOOL_EVENT &aEvent)
int AppendDesignBlock(const TOOL_EVENT &aEvent)
int LayerPrev(const TOOL_EVENT &aEvent)
int PlaceDrillMap(const TOOL_EVENT &aEvent)
int CycleLayerPresets(const TOOL_EVENT &aEvent)
int Paste(const TOOL_EVENT &aEvent)
void unfilledZoneCheck()
We have bug reports indicating that some new users confuse zone filling/unfilling with the display mo...
int LayerSwitch(const TOOL_EVENT &aEvent)
Abstract dimension API.
bool m_FlipBoardView
true if the board is flipped to show the mirrored view
HIGH_CONTRAST_MODE m_ContrastModeDisplay
How inactive layers are displayed.
NET_COLOR_MODE m_NetColorMode
How to use color overrides on specific nets and netclasses.
ZONE_DISPLAY_MODE m_ZoneDisplayMode
void RedrawRatsnest()
Return the bounding box of the view that should be used if model is not valid.
A drill chart placed on the board, kept in step with the holes.
void RebuildCells(const BOARD &aBoard, DRILL_SYMBOL_PROFILE *aAssignedProfile=nullptr)
Regenerate the cells from the board.
Turns on drill symbols at the holes, for one layer.
The main frame for Pcbnew.
PCB_DESIGN_BLOCK_PANE * GetDesignBlockPane() const
static const TOOL_EVENT & SnappingModeChangedByKeyEvent()
Hotkey feedback.
static const TOOL_EVENT & LayerPairPresetChangedByKeyEvent()
A set of BOARD_ITEMs (i.e., without duplicates).
Definition pcb_group.h:51
PCB_FILE_T
The set of file types that the PCB_IO_MGR knows about, and for which there has been a plugin written,...
Definition pcb_io_mgr.h:52
@ KICAD_SEXP
S-expression Pcbnew file format.
Definition pcb_io_mgr.h:54
static PCB_IO * FindPlugin(PCB_FILE_T aFileType)
Return a #PLUGIN which the caller can use to import, export, save, or load design documents.
static PCB_FILE_T FindPluginTypeFromBoardPath(const wxString &aFileName, int aCtl=0)
Return a plugin type given a path for a board file.
A base class that BOARD loading and saving plugins should derive from.
Definition pcb_io.h:76
void LoadAndAppendBoard(const wxString &aFileName, BOARD &aAppendToMe, const std::map< std::string, UTF8 > *aProperties=nullptr, PROJECT *aProject=nullptr)
Same as LoadBoard(), but appends the loaded board to an existing board, which must already exist.
Definition pcb_io.cpp:85
virtual void SetQueryUserCallback(std::function< bool(wxString aTitle, int aIcon, wxString aMessage, wxString aAction)> aCallback)
Registers a KIDIALOG callback for collecting info from the user.
Definition pcb_io.h:106
Class that manages the presentation of PCB layers in a PCB frame.
wxString getLayerPairName(const LAYER_PAIR &aPair) const
Definition sel_layer.cpp:90
Generic tool for picking an item.
void ClearHandlers()
Handlers only.
PCB_LAYER_ID m_Route_Layer_TOP
Definition pcb_screen.h:39
PCB_LAYER_ID m_Route_Layer_BOTTOM
Definition pcb_screen.h:40
The selection tool: currently supports:
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...
void select(EDA_ITEM *aItem) override
Take necessary action mark an item as selected.
bool Selectable(const BOARD_ITEM *aItem, bool checkVisibilityOnly=false) const
PCB_GROUP * GetEnteredGroup()
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.
int ClearSelection(const TOOL_EVENT &aEvent)
PCB_SELECTION & GetSelection()
void FilterCollectedItems(GENERAL_COLLECTOR &aCollector, bool aMultiSelect, PCB_SELECTION_FILTER_OPTIONS *aRejected=nullptr)
Apply the SELECTION_FITLER_OPTIONS to the collector.
void UpdateHatching() const override
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
void Move(const VECTOR2I &aMoveVector) override
Move this object.
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
T * frame() const
KIGFX::PCB_VIEW * view() const
PCB_TOOL_BASE(TOOL_ID aId, const std::string &aName)
Constructor.
BOARD * board() const
PCB_DRAW_PANEL_GAL * canvas() const
PCBNEW_SETTINGS::DISPLAY_OPTIONS & displayOptions() const
const PCB_SELECTION & selection() const
FOOTPRINT * footprint() const
const VECTOR2I & GetStart() const
Definition pcb_track.h:93
const VECTOR2I & GetEnd() const
Definition pcb_track.h:90
virtual COMMON_SETTINGS * GetCommonSettings() const
Definition pgm_base.cpp:546
void SetMotionHandler(MOTION_HANDLER aHandler)
Set a handler for mouse motion.
Definition picker_tool.h:92
void SetClickHandler(CLICK_HANDLER aHandler)
Set a handler for mouse click event.
Definition picker_tool.h:81
void SetSnapping(bool aSnap)
Definition picker_tool.h:65
void SetCursor(KICURSOR aCursor)
Definition picker_tool.h:63
void SetFinalizeHandler(FINALIZE_HANDLER aHandler)
Set a handler for the finalize event.
static S3D_CACHE * Get3DCacheManager(PROJECT *aProject, bool updateProjDir=false)
Return a pointer to an instance of the 3D cache manager.
Container for project specific data.
Definition project.h:63
virtual const wxString GetProjectPath() const
Return the full path of the project.
Definition project.cpp:183
Cache for storing the 3D shapes.
Definition 3d_cache.h:53
FILENAME_RESOLVER * GetResolver() noexcept
Definition 3d_cache.cpp:563
Definition seg.h:38
ecoord SquaredDistance(const SEG &aSeg) const
Definition seg.cpp:76
VECTOR2I::extended_type ecoord
Definition seg.h:40
void BrightenItem(EDA_ITEM *aItem)
void UnbrightenItem(EDA_ITEM *aItem)
virtual void Add(EDA_ITEM *aItem)
A null aItem is ignored; the selection never holds null members.
Definition selection.cpp:38
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
Represent a set of closed polygons.
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
virtual VECTOR2I Centre() const
Compute a center-of-mass of the shape.
Definition shape.h:230
Extension of STATUS_POPUP for displaying a single line text.
Hold the information shown in the lower right corner of a plot, printout, or editing view.
Definition title_block.h:38
T * getEditFrame() const
Return the application window object, casted to requested user type.
Definition tool_base.h:182
const std::string & GetName() const
Return the name of the tool.
Definition tool_base.h:132
KIGFX::VIEW_CONTROLS * getViewControls() const
Return the instance of VIEW_CONTROLS object used in the application.
Definition tool_base.cpp:40
TOOL_MANAGER * m_toolMgr
Definition tool_base.h:220
KIGFX::VIEW * getView() const
Returns the instance of #VIEW object used in the application.
Definition tool_base.cpp:34
RESET_REASON
Determine the reason of reset for a tool.
Definition tool_base.h:74
@ REDRAW
Full drawing refresh.
Definition tool_base.h:79
@ MODEL_RELOAD
Model changes (the sheet for a schematic)
Definition tool_base.h:76
@ GAL_SWITCH
Rendering engine changes.
Definition tool_base.h:78
Generic, UI-independent tool event.
Definition tool_event.h:167
COMMIT * Commit() const
Definition tool_event.h:279
bool IsAction(const TOOL_ACTION *aAction) const
Test if the event contains an action issued upon activation of the given TOOL_ACTION.
T Parameter() const
Return a parameter assigned to the event.
Definition tool_event.h:469
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).
void Activate()
Run the tool.
static constexpr extended_type ECOORD_MAX
Definition vector2d.h:72
A modified version of the wxInfoBar class that allows us to:
Definition wx_infobar.h:76
void RemoveAllButtons()
Remove all the buttons that have been added by the user.
void ShowMessageFor(const wxString &aMessage, int aTime, int aFlags=wxICON_INFORMATION, MESSAGE_TYPE aType=WX_INFOBAR::MESSAGE_TYPE::GENERIC)
Show the infobar with the provided message and icon for a specific period of time.
void AddLink(const wxString &aLinkText, const std::function< void(wxHyperlinkEvent &)> &aFn)
Add a hypertext link to the infobar.
Multi-thread safe progress reporter dialog, intended for use of tasks that parallel reporting back of...
Handle a list of polygons defining a copper zone.
Definition zone.h:70
void SetDoNotAllowPads(bool aEnable)
Definition zone.h:826
void AddPolygon(std::vector< VECTOR2I > &aPolygon)
Add a polygon to the zone outline.
Definition zone.cpp:1424
void SetPlacementAreaSource(const wxString &aSource)
Definition zone.h:813
void SetPlacementAreaSourceType(PLACEMENT_SOURCE_T aType)
Definition zone.h:815
SHAPE_POLY_SET * Outline()
Definition zone.h:418
void SetHatchStyle(ZONE_BORDER_DISPLAY_STYLE aStyle)
Definition zone.h:681
void SetIsRuleArea(bool aEnable)
Definition zone.h:808
void SetDoNotAllowTracks(bool aEnable)
Definition zone.h:825
const wxString & GetZoneName() const
Definition zone.h:160
void SetLayerSet(const LSET &aLayerSet) override
Definition zone.cpp:666
void SetDoNotAllowVias(bool aEnable)
Definition zone.h:824
void SetDoNotAllowFootprints(bool aEnable)
Definition zone.h:827
void SetDoNotAllowZoneFills(bool aEnable)
Definition zone.h:823
void SetZoneName(const wxString &aName)
Definition zone.h:161
void SetPlacementAreaEnabled(bool aEnabled)
Definition zone.h:810
std::unique_ptr< wxBitmap > GetImageFromClipboard()
Get image data from the clipboard, if there is any.
std::string GetClipboardUTF8()
Return the information currently stored in the system clipboard.
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition confirm.cpp:274
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition confirm.cpp:217
void DisplayError(wxWindow *aParent, const wxString &aText)
Display an error or warning message box with aMessage.
Definition confirm.cpp:192
This file is part of the common library.
void TransformCircleToPolygon(SHAPE_LINE_CHAIN &aBuffer, const VECTOR2I &aCenter, int aRadius, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a circle to a polygon, using multiple straight lines.
void BuildConvexHull(std::vector< VECTOR2I > &aResult, const std::vector< VECTOR2I > &aPoly)
Calculate the convex hull of a list of points in counter-clockwise order.
@ REMOVE
Definition cursors.h:50
@ PLACE
Definition cursors.h:94
@ ARROW
Definition cursors.h:42
#define ALPHA_MAX
@ DIFF_PAIR_GAP_CONSTRAINT
Definition drc_rule.h:78
@ EDGE_CLEARANCE_CONSTRAINT
Definition drc_rule.h:55
@ CLEARANCE_CONSTRAINT
Definition drc_rule.h:51
@ MAX_UNCOUPLED_CONSTRAINT
Definition drc_rule.h:79
@ HOLE_CLEARANCE_CONSTRAINT
Definition drc_rule.h:53
LSET DrillDocumentationLayers()
Layers a chart or map may live on.
#define _(s)
Declaration of the eda_3d_viewer class.
@ RECURSE
Definition eda_item.h:51
@ NO_RECURSE
Definition eda_item.h:52
#define IS_NEW
New item, just created.
#define MCT_SKIP_STRUCT
flag used by the multichannel tool to mark items that should be skipped
#define SKIP_STRUCT
flag indicating that the structure should be ignored
@ SEGMENT
Definition eda_shape.h:56
EDA_UNITS
Definition eda_units.h:44
static FILENAME_RESOLVER * resolver
@ FRAME_PCB_EDITOR
Definition frame_type.h:38
@ FRAME_FOOTPRINT_VIEWER
Definition frame_type.h:41
@ FRAME_FOOTPRINT_EDITOR
Definition frame_type.h:39
static const std::string KiCadUriPrefix
wxString KeyNameFromKeyCode(int aKeycode, bool *aIsFound)
Return the key name from the key code.
std::unique_ptr< T > IO_RELEASER
Helper to hold and release an IO_BASE object when exceptions are thrown.
Definition io_mgr.h:33
#define KICTL_KICAD_ONLY
chosen file is from KiCad according to user
int GetNetnameLayer(int aLayer)
Return a netname layer corresponding to the given layer.
Definition layer_ids.h:880
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition layer_ids.h:703
@ LAYER_RATSNEST
Definition layer_ids.h:249
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
@ Edge_Cuts
Definition layer_ids.h:108
@ B_Cu
Definition layer_ids.h:61
@ Margin
Definition layer_ids.h:109
@ UNDEFINED_LAYER
Definition layer_ids.h:57
@ F_Cu
Definition layer_ids.h:60
#define ZONE_LAYER_FOR(boardLayer)
Definition layer_ids.h:387
std::optional< wxString > GetMsgPanelDisplayUuid(const KIID &aKiid)
Get a formatted UUID string for display in the message panel, according to the current advanced confi...
Definition msgpanel.cpp:216
SHAPE_LINE_CHAIN RectifyPolygon(const SHAPE_LINE_CHAIN &aPoly)
void CollectBoxCorners(const BOX2I &aBox, std::vector< VECTOR2I > &aCorners)
Add the 4 corners of a BOX2I to a vector.
@ REPAINT
Item needs to be redrawn.
Definition view_item.h:54
wxPoint GetMousePosition()
Returns the mouse position in screen coordinates.
Definition wxgtk/ui.cpp:839
constexpr char APPEND_PRESERVE_DESTINATION_STACKUP[]
Definition pcb_io.h:44
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
Definition kicad_algo.h:96
bool AskLoadBoardFileName(PCB_EDIT_FRAME *aParent, wxString *aFileName, int aCtl=0)
Show a wxFileDialog asking for a BOARD filename to open.
PCB_TABLE * Build_Board_Characteristics_Table(BOARD *aBoard, EDA_UNITS aDisplayUnits)
PCB_TABLE * Build_Board_Stackup_Table(BOARD *aBoard, EDA_UNITS aDisplayUnits)
#define ALPHA_STEP
static void pasteFootprintItemsToFootprintEditor(FOOTPRINT *aClipFootprint, BOARD *aBoard, std::vector< BOARD_ITEM * > &aPastedItems)
#define ALPHA_MIN
void Flip(T &aValue)
Class to handle a set of BOARD_ITEMs.
bool AskLoadBoardFileName(PCB_EDIT_FRAME *aParent, wxString *aFileName, int aCtl=0)
Show a wxFileDialog asking for a BOARD filename to open.
PGM_BASE & Pgm()
The global program "get" accessor.
see class PGM_BASE
CITER next(CITER it)
Definition ptree.cpp:120
#define HITTEST_THRESHOLD_PIXELS
std::vector< EDA_ITEM * > EDA_ITEMS
Utility functions for working with shapes.
std::vector< FAB_LAYER_COLOR > dummy
wxString UnescapeString(const wxString &aSource)
VECTOR2I m_center
std::unordered_set< EDA_ITEM * > m_designBlockItems
PLACEMENT_SOURCE_T m_sourceType
std::set< FOOTPRINT * > m_components
PCB_GROUP * m_group
KIBIS_MODEL * model
VECTOR2I center
int actual
wxString result
Test unit parsing edge cases and error handling.
constexpr KICAD_T BaseType(const KICAD_T aType)
Return the underlying type of the given type.
Definition typeinfo.h:259
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition typeinfo.h:70
@ PCB_T
Definition typeinfo.h:74
@ PCB_CONSTRAINT_T
a geometric constraint between board items
Definition typeinfo.h:237
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition typeinfo.h:80
@ PCB_DIM_ORTHOGONAL_T
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
Definition typeinfo.h:98
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition typeinfo.h:95
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:89
@ PCB_DRILL_MAP_T
class PCB_DRILL_MAP, drill symbols drawn at the holes
Definition typeinfo.h:240
@ PCB_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
Definition typeinfo.h:96
@ PCB_GROUP_T
class PCB_GROUP, a set of BOARD_ITEMs
Definition typeinfo.h:103
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
Definition typeinfo.h:85
@ PCB_ZONE_T
class ZONE, a copper pour area
Definition typeinfo.h:100
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition typeinfo.h:84
@ NOT_USED
the 3d code uses this value
Definition typeinfo.h:71
@ PCB_MARKER_T
class PCB_MARKER, a marker used to show something
Definition typeinfo.h:91
@ PCB_BARCODE_T
class PCB_BARCODE, a barcode (graphic item)
Definition typeinfo.h:93
@ PCB_TABLECELL_T
class PCB_TABLECELL, PCB_TEXTBOX for use in tables
Definition typeinfo.h:87
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
Definition typeinfo.h:78
@ PCB_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
Definition typeinfo.h:94
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition typeinfo.h:79
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition typeinfo.h:90
@ PCB_DIMENSION_T
class PCB_DIMENSION_BASE: abstract dimension meta-type
Definition typeinfo.h:92
@ PCB_TABLE_T
class PCB_TABLE, table of PCB_TABLECELLs
Definition typeinfo.h:86
@ PCB_POINT_T
class PCB_POINT, a 0-dimensional point
Definition typeinfo.h:105
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition typeinfo.h:88
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
Definition typeinfo.h:97
@ PCB_DRILL_CHART_T
class PCB_DRILL_CHART, a live drill chart derived from PCB_TABLE
Definition typeinfo.h:239
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683
VECTOR2< double > VECTOR2D
Definition vector2d.h:682
Definition of file extensions used in Kicad.
#define PR_CAN_ABORT