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>
52#include <pad.h>
53#include <netinfo.h>
54#include <layer_pairs.h>
55#include <pcb_group.h>
57#include <pcb_reference_image.h>
58#include <pcb_textbox.h>
59#include <pcb_table.h>
60#include <pcb_tablecell.h>
61#include <pcb_track.h>
62#include <pcb_generator.h>
64#include <project_pcb.h>
66#include <filename_resolver.h>
67#include <3d_cache/3d_cache.h>
68#include <embedded_files.h>
69#include <wx/filename.h>
70#include <zone.h>
71#include <confirm.h>
72#include <kidialog.h>
74#include <core/kicad_algo.h>
78#include <kicad_clipboard.h>
79#include <origin_viewitem.h>
80#include <pcb_edit_frame.h>
81#include <pcb_painter.h>
83#include <string>
84#include <tool/tool_manager.h>
92#include <widgets/wx_infobar.h>
93#include <pcb_io/pcb_io.h>
94#include <wx/hyperlink.h>
95
96
97using namespace std::placeholders;
98
99
100// files.cpp
101extern bool AskLoadBoardFileName( PCB_EDIT_FRAME* aParent, wxString* aFileName, int aCtl = 0 );
102
103// board_tables/board_stackup_table.cpp
104extern PCB_TABLE* Build_Board_Stackup_Table( BOARD* aBoard, EDA_UNITS aDisplayUnits );
105// board_tables/board_characteristics_table.cpp
106extern PCB_TABLE* Build_Board_Characteristics_Table( BOARD* aBoard, EDA_UNITS aDisplayUnits );
107
108
110 PCB_TOOL_BASE( "pcbnew.Control" ),
111 m_frame( nullptr ),
112 m_pickerItem( nullptr )
113{
115}
116
117
121
122
124{
126
127 if( aReason == MODEL_RELOAD || aReason == GAL_SWITCH || aReason == REDRAW )
128 {
129 m_gridOrigin->SetPosition( board()->GetDesignSettings().GetGridOrigin() );
130
131 double backgroundBrightness = m_frame->GetCanvas()->GetGAL()->GetClearColor().GetBrightness();
132 COLOR4D color = m_frame->GetGridColor();
133
134 if( backgroundBrightness > 0.5 )
135 color.Darken( 0.25 );
136 else
137 color.Brighten( 0.25 );
138
139 m_gridOrigin->SetColor( color );
140
141 getView()->Remove( m_gridOrigin.get() );
142 getView()->Add( m_gridOrigin.get() );
143 }
144}
145
146
148{
149 if( m_frame->IsType( FRAME_FOOTPRINT_EDITOR ) || m_frame->IsType( FRAME_PCB_EDITOR ) )
150 {
151 if( aEvent.IsAction( &ACTIONS::newLibrary ) )
152 static_cast<PCB_BASE_EDIT_FRAME*>( m_frame )->CreateNewLibrary( _( "New Footprint Library" ) );
153 else if( aEvent.IsAction( &ACTIONS::addLibrary ) )
154 static_cast<PCB_BASE_EDIT_FRAME*>( m_frame )->AddLibrary( _( "Add Footprint Library" ) );
155 }
156
157 return 0;
158}
159
160
162{
163 if( m_frame->IsType( FRAME_FOOTPRINT_EDITOR ) )
164 static_cast<FOOTPRINT_EDIT_FRAME*>( m_frame )->LoadFootprintFromBoard( nullptr );
165
166 return 0;
167}
168
169
171{
172 if( m_frame->IsType( FRAME_FOOTPRINT_EDITOR ) )
173 static_cast<FOOTPRINT_EDIT_FRAME*>( m_frame )->SaveFootprintToBoard( true );
174 else if( m_frame->IsType( FRAME_FOOTPRINT_VIEWER ) )
175 static_cast<FOOTPRINT_VIEWER_FRAME*>( m_frame )->AddFootprintToPCB();
176
177 return 0;
178}
179
180
182{
183 const wxString fn = *aEvent.Parameter<wxString*>();
184 static_cast<PCB_BASE_EDIT_FRAME*>( m_frame )->AddLibrary( _( "Add Footprint Library" ), fn,
186 return 0;
187}
188
189
191{
192 const wxString fn = *aEvent.Parameter<wxString*>();
193 static_cast<FOOTPRINT_EDIT_FRAME*>( m_frame )->ImportFootprint( fn );
194 m_frame->Zoom_Automatique( false );
195 return 0;
196}
197
198
200{
201 if( m_frame->IsType( FRAME_FOOTPRINT_VIEWER ) )
202 static_cast<FOOTPRINT_VIEWER_FRAME*>( m_frame )->SelectAndViewFootprint( aEvent.Parameter<FPVIEWER_CONSTANTS>() );
203
204 return 0;
205}
206
207
208template<class T>
209void Flip( T& aValue )
210{
211 aValue = !aValue;
212}
213
214
216{
217 Flip( displayOptions().m_DisplayPcbTrackFill );
218
219 for( PCB_TRACK* track : board()->Tracks() )
220 {
221 if( track->Type() == PCB_TRACE_T || track->Type() == PCB_ARC_T )
222 view()->Update( track, KIGFX::REPAINT );
223 }
224
225 for( BOARD_ITEM* shape : board()->Drawings() )
226 {
227 if( shape->Type() == PCB_SHAPE_T && static_cast<PCB_SHAPE*>( shape )->IsOnCopperLayer() )
228 view()->Update( shape, KIGFX::REPAINT );
229 }
230
231 canvas()->Refresh();
232
233 return 0;
234}
235
236
238{
239 if( PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame ) )
240 {
241 if( aEvent.IsAction( &PCB_ACTIONS::showRatsnest ) )
242 {
243 // N.B. Do not disable the Ratsnest layer here. We use it for local ratsnest
244 Flip( displayOptions().m_ShowGlobalRatsnest );
245 editFrame->SetElementVisibility( LAYER_RATSNEST, displayOptions().m_ShowGlobalRatsnest );
246 }
247 else if( aEvent.IsAction( &PCB_ACTIONS::ratsnestLineMode ) )
248 {
249 Flip( displayOptions().m_DisplayRatsnestLinesCurved );
250 }
251
252 editFrame->OnDisplayOptionsChanged();
253
255 canvas()->Refresh();
256 }
257
258 return 0;
259}
260
261
263{
264 Flip( displayOptions().m_DisplayViaFill );
265
266 for( PCB_TRACK* track : board()->Tracks() )
267 {
268 if( track->Type() == PCB_VIA_T )
269 view()->Update( track, KIGFX::REPAINT );
270 }
271
272 canvas()->Refresh();
273 return 0;
274}
275
276
283{
284 if( Pgm().GetCommonSettings()->m_DoNotShowAgain.zone_fill_warning )
285 return;
286
287 bool unfilledZones = false;
288
289 for( const ZONE* zone : board()->Zones() )
290 {
291 if( !zone->GetIsRuleArea() && !zone->IsFilled() )
292 {
293 unfilledZones = true;
294 break;
295 }
296 }
297
298 if( unfilledZones )
299 {
300 WX_INFOBAR* infobar = m_frame->GetInfoBar();
301 wxHyperlinkCtrl* button = new wxHyperlinkCtrl( infobar, wxID_ANY, _( "Don't show again" ), wxEmptyString );
302
303 button->Bind( wxEVT_COMMAND_HYPERLINK, std::function<void( wxHyperlinkEvent& aEvent )>(
304 [&]( wxHyperlinkEvent& aEvent )
305 {
307 m_frame->GetInfoBar()->Dismiss();
308 } ) );
309
310 infobar->RemoveAllButtons();
311 infobar->AddButton( button );
312
313 wxString msg;
314 msg.Printf( _( "Not all zones are filled. Use Edit > Fill All Zones (%s) "
315 "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
1007
1008void PCB_CONTROL::pruneItemLayers( std::vector<BOARD_ITEM*>& aItems )
1009{
1010 // Do not prune items or layers when copying to the FP editor, because all
1011 // layers are accepted, even if they are not enabled in the dummy board
1012 // This is mainly true for internal copper layers: all are allowed but only one
1013 // (In1.cu) is enabled for the GUI.
1015 return;
1016
1017 LSET enabledLayers = board()->GetEnabledLayers();
1018 std::vector<BOARD_ITEM*> returnItems;
1019 bool fpItemDeleted = false;
1020
1021 for( BOARD_ITEM* item : aItems )
1022 {
1023 if( item->Type() == PCB_FOOTPRINT_T )
1024 {
1025 FOOTPRINT* fp = static_cast<FOOTPRINT*>( item );
1026
1027 // Items living in a parent footprint are never removed, even if their
1028 // layer does not exist in the board editor
1029 // Otherwise the parent footprint could be seriously broken especially
1030 // if some layers are later re-enabled.
1031 // Moreover a fp lives in a fp library, that does not know the enabled
1032 // layers of a given board, so fp items are just ignored when on not
1033 // enabled layers in board editor
1034 returnItems.push_back( fp );
1035 }
1036 else if( item->Type() == PCB_GROUP_T || item->Type() == PCB_GENERATOR_T )
1037 {
1038 returnItems.push_back( item );
1039 }
1040 else
1041 {
1042 LSET allowed = item->GetLayerSet() & enabledLayers;
1043 bool item_valid = true;
1044
1045 // Ensure, for vias, the top and bottom layers are compatible with
1046 // the current board copper layers.
1047 // Otherwise they must be skipped, even is one layer is valid
1048 if( item->Type() == PCB_VIA_T )
1049 item_valid = static_cast<PCB_VIA*>( item )->HasValidLayerPair( board()->GetCopperLayerCount() );
1050
1051 if( allowed.any() && item_valid )
1052 {
1053 item->SetLayerSet( allowed );
1054 returnItems.push_back( item );
1055 }
1056 else
1057 {
1058 if( EDA_GROUP* parentGroup = item->GetParentGroup() )
1059 parentGroup->RemoveItem( item );
1060 }
1061 }
1062 }
1063
1064 if( ( returnItems.size() < aItems.size() ) || fpItemDeleted )
1065 {
1066 DisplayError( m_frame, _( "Warning: some pasted items were on layers which are not "
1067 "present in the current board.\n"
1068 "These items could not be pasted.\n" ) );
1069 }
1070
1071 aItems = returnItems;
1072}
1073
1074
1075int PCB_CONTROL::Paste( const TOOL_EVENT& aEvent )
1076{
1077 // The viewer frames cannot paste
1078 if( !m_frame->IsType( FRAME_FOOTPRINT_EDITOR ) && !m_frame->IsType( FRAME_PCB_EDITOR ) )
1079 return 0;
1080
1081 bool isFootprintEditor = m_isFootprintEditor || m_frame->IsType( FRAME_FOOTPRINT_EDITOR );
1082
1083 // The clipboard can contain two different things, an entire kicad_pcb or a single footprint
1084 if( isFootprintEditor && ( !board() || !footprint() ) )
1085 return 0;
1086
1087 // We should never get here if a modal dialog is up... but we do on MacOS.
1088 // https://gitlab.com/kicad/code/kicad/-/issues/18912
1089#ifdef __WXMAC__
1090 if( wxDialog::OSXHasModalDialogsOpen() )
1091 {
1092 wxBell();
1093 return 0;
1094 }
1095#endif
1096
1097 BOARD_COMMIT commit( m_frame );
1098
1099 CLIPBOARD_IO pi;
1100 BOARD_ITEM* clipItem = pi.Parse();
1101
1102 PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
1103
1104 if( selTool && clipItem )
1105 {
1106 PCB_SELECTION& selection = selTool->GetSelection();
1107
1108 bool hasTableCells = false;
1109
1110 for( EDA_ITEM* item : selection )
1111 {
1112 if( item->Type() == PCB_TABLECELL_T )
1113 {
1114 hasTableCells = true;
1115 break;
1116 }
1117 }
1118
1119 if( hasTableCells )
1120 {
1121 PCB_TABLE* clipboardTable = nullptr;
1122
1123 if( clipItem->Type() == PCB_T )
1124 {
1125 BOARD* clipBoard = static_cast<BOARD*>( clipItem );
1126
1127 for( BOARD_ITEM* item : clipBoard->Drawings() )
1128 {
1129 if( item->Type() == PCB_TABLE_T )
1130 {
1131 clipboardTable = static_cast<PCB_TABLE*>( item );
1132 break;
1133 }
1134 }
1135 }
1136
1137 if( clipboardTable )
1138 {
1139 PCB_EDIT_TABLE_TOOL* tableEditTool = m_toolMgr->GetTool<PCB_EDIT_TABLE_TOOL>();
1140
1141 if( tableEditTool )
1142 {
1143 wxString errorMsg;
1144
1145 if( !tableEditTool->validatePasteIntoSelection( selection, errorMsg ) )
1146 {
1147 DisplayError( m_frame, errorMsg );
1148 return 0;
1149 }
1150
1151 if( tableEditTool->pasteCellsIntoSelection( selection, clipboardTable, commit ) )
1152 {
1153 commit.Push( _( "Paste Cells" ) );
1154 return 0;
1155 }
1156 else
1157 {
1158 DisplayError( m_frame, _( "Failed to paste cells" ) );
1159 return 0;
1160 }
1161 }
1162 }
1163 }
1164 }
1165
1166 if( !clipItem )
1167 {
1168 // When the clipboard doesn't parse, create a PCB item with the clipboard contents
1169 std::vector<BOARD_ITEM*> newItems;
1170
1171 if( std::unique_ptr<wxBitmap> clipImg = GetImageFromClipboard() )
1172 {
1173 auto refImg = std::make_unique<PCB_REFERENCE_IMAGE>( m_frame->GetModel() );
1174
1175 if( refImg->GetReferenceImage().SetImage( clipImg->ConvertToImage() ) )
1176 newItems.push_back( refImg.release() );
1177 }
1178 else
1179 {
1180 const wxString clipText = GetClipboardUTF8();
1181
1182 if( clipText.empty() )
1183 return 0;
1184
1185 // If it wasn't content, then paste as a text object.
1186 if( clipText.size() > static_cast<size_t>( ADVANCED_CFG::GetCfg().m_MaxPastedTextLength ) )
1187 {
1188 int result = IsOK( m_frame, _( "Pasting a long text text string may be very slow. "
1189 "Do you want to continue?" ) );
1190 if( !result )
1191 return 0;
1192 }
1193
1194 std::unique_ptr<PCB_TEXT> item = std::make_unique<PCB_TEXT>( m_frame->GetModel() );
1195 item->SetText( clipText );
1196 item->SetLayer( m_frame->GetActiveLayer() );
1197
1198 newItems.push_back( item.release() );
1199 }
1200
1201 bool cancelled = !placeBoardItems( &commit, newItems, true, false, false, false );
1202
1203 if( cancelled )
1204 commit.Revert();
1205 else
1206 commit.Push( _( "Paste Text" ) );
1207 return 0;
1208 }
1209
1210 // If we get here, we have a parsed board/FP to paste
1211
1213 bool clear_nets = false;
1214 const wxString defaultRef = wxT( "REF**" );
1215
1216 if( aEvent.IsAction( &ACTIONS::pasteSpecial ) )
1217 {
1218 DIALOG_PASTE_SPECIAL dlg( m_frame, &mode, defaultRef );
1219
1220 if( clipItem->Type() != PCB_T )
1221 dlg.HideClearNets();
1222
1223 if( dlg.ShowModal() == wxID_CANCEL )
1224 return 0;
1225
1226 clear_nets = dlg.GetClearNets();
1227 }
1228
1229 if( clipItem->Type() == PCB_T )
1230 {
1231 BOARD* clipBoard = static_cast<BOARD*>( clipItem );
1232
1233 if( isFootprintEditor || clear_nets )
1234 {
1235 for( BOARD_CONNECTED_ITEM* item : clipBoard->AllConnectedItems() )
1236 item->SetNet( NETINFO_LIST::OrphanedItem() );
1237 }
1238 else
1239 {
1240 clipBoard->MapNets( m_frame->GetBoard() );
1241 }
1242 }
1243
1244 bool cancelled = false;
1245
1246 switch( clipItem->Type() )
1247 {
1248 case PCB_T:
1249 {
1250 BOARD* clipBoard = static_cast<BOARD*>( clipItem );
1251
1252 if( isFootprintEditor )
1253 {
1254 FOOTPRINT* editorFootprint = board()->GetFirstFootprint();
1255 std::vector<BOARD_ITEM*> pastedItems;
1256
1257 for( PCB_GROUP* group : clipBoard->Groups() )
1258 {
1259 group->SetParent( editorFootprint );
1260 pastedItems.push_back( group );
1261 }
1262
1263 clipBoard->RemoveAll( { PCB_GROUP_T } );
1264
1265 for( FOOTPRINT* clipFootprint : clipBoard->Footprints() )
1266 pasteFootprintItemsToFootprintEditor( clipFootprint, board(), pastedItems );
1267
1268 for( BOARD_ITEM* clipDrawItem : clipBoard->Drawings() )
1269 {
1270 switch( clipDrawItem->Type() )
1271 {
1272 case PCB_TEXT_T:
1273 case PCB_TEXTBOX_T:
1274 case PCB_TABLE_T:
1275 case PCB_SHAPE_T:
1276 case PCB_BARCODE_T:
1277 case PCB_DIM_ALIGNED_T:
1278 case PCB_DIM_CENTER_T:
1279 case PCB_DIM_LEADER_T:
1281 case PCB_DIM_RADIAL_T:
1282 clipDrawItem->SetParent( editorFootprint );
1283 pastedItems.push_back( clipDrawItem );
1284 break;
1285
1286 default:
1287 // Everything we *didn't* put into pastedItems is going to get nuked, so
1288 // make sure it's not still included in its parent group.
1289 if( EDA_GROUP* parentGroup = clipDrawItem->GetParentGroup() )
1290 parentGroup->RemoveItem( clipDrawItem );
1291
1292 break;
1293 }
1294 }
1295
1296 // NB: PCB_SHAPE_T actually removes everything in Drawings() (including PCB_TEXTs,
1297 // PCB_TABLEs, PCB_BARCODEs, dimensions, etc.), not just PCB_SHAPEs.)
1298 clipBoard->RemoveAll( { PCB_SHAPE_T } );
1299
1300 clipBoard->Visit(
1301 [&]( EDA_ITEM* item, void* testData )
1302 {
1303 if( item->IsBOARD_ITEM() )
1304 {
1305 // Anything still on the clipboard didn't get copied and needs to be
1306 // removed from the pasted groups.
1307 BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( item );
1308 EDA_GROUP* parentGroup = boardItem->GetParentGroup();
1309
1310 if( parentGroup )
1311 parentGroup->RemoveItem( boardItem );
1312 }
1313
1315 },
1317
1318 delete clipBoard;
1319
1320 pruneItemLayers( pastedItems );
1321
1322 cancelled = !placeBoardItems( &commit, pastedItems, true, true, mode == PASTE_MODE::UNIQUE_ANNOTATIONS,
1323 false );
1324 }
1325 else // isBoardEditor
1326 {
1327 // Fixup footprint component classes
1328 for( FOOTPRINT* fp : clipBoard->Footprints() )
1329 {
1330 fp->ResolveComponentClassNames( board(), fp->GetTransientComponentClassNames() );
1331 fp->ClearTransientComponentClassNames();
1332 }
1333
1334 if( mode == PASTE_MODE::REMOVE_ANNOTATIONS )
1335 {
1336 for( FOOTPRINT* fp : clipBoard->Footprints() )
1337 fp->SetReference( defaultRef );
1338 }
1339
1340 cancelled = !placeBoardItems( &commit, clipBoard, true, mode == PASTE_MODE::UNIQUE_ANNOTATIONS, false );
1341 }
1342
1343 break;
1344 }
1345
1346 case PCB_FOOTPRINT_T:
1347 {
1348 FOOTPRINT* clipFootprint = static_cast<FOOTPRINT*>( clipItem );
1349 std::vector<BOARD_ITEM*> pastedItems;
1350
1351 if( isFootprintEditor )
1352 {
1353 pasteFootprintItemsToFootprintEditor( clipFootprint, board(), pastedItems );
1354 delete clipFootprint;
1355 }
1356 else
1357 {
1358 if( mode == PASTE_MODE::REMOVE_ANNOTATIONS )
1359 clipFootprint->SetReference( defaultRef );
1360
1361 clipFootprint->SetParent( board() );
1362 clipFootprint->ResolveComponentClassNames( board(), clipFootprint->GetTransientComponentClassNames() );
1363 clipFootprint->ClearTransientComponentClassNames();
1364 pastedItems.push_back( clipFootprint );
1365 }
1366
1367 pruneItemLayers( pastedItems );
1368
1369 cancelled = !placeBoardItems( &commit, pastedItems, true, true, mode == PASTE_MODE::UNIQUE_ANNOTATIONS, false );
1370 break;
1371 }
1372
1373 default:
1374 m_frame->DisplayToolMsg( _( "Invalid clipboard contents" ) );
1375 break;
1376 }
1377
1378 if( cancelled )
1379 commit.Revert();
1380 else
1381 commit.Push( _( "Paste" ) );
1382
1383 return 1;
1384}
1385
1386
1388{
1389 wxString fileName;
1390
1391 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
1392
1393 if( !editFrame )
1394 return 1;
1395
1396 // Pick a file to append
1397 if( !AskLoadBoardFileName( editFrame, &fileName, KICTL_KICAD_ONLY ) )
1398 return 1;
1399
1401 IO_RELEASER<PCB_IO> pi( PCB_IO_MGR::FindPlugin( pluginType ) );
1402
1403 if( !pi )
1404 return 1;
1405
1406 return AppendBoard( *pi, fileName );
1407}
1408
1409
1411{
1412 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
1413
1414 if( !editFrame )
1415 return 1;
1416
1417 if( !editFrame->GetDesignBlockPane()->GetSelectedLibId().IsValid() )
1418 return 1;
1419
1420 DESIGN_BLOCK_PANE* designBlockPane = editFrame->GetDesignBlockPane();
1421 const LIB_ID selectedLibId = designBlockPane->GetSelectedLibId();
1422 std::unique_ptr<DESIGN_BLOCK> designBlock( designBlockPane->GetDesignBlock( selectedLibId, true, true ) );
1423
1424 if( !designBlock )
1425 {
1426 wxString msg;
1427 msg.Printf( _( "Could not find design block %s." ), selectedLibId.GetUniStringLibId() );
1428 editFrame->ShowInfoBarError( msg, true );
1429 return 1;
1430 }
1431
1432 if( designBlock->GetBoardFile().IsEmpty() || !wxFileName::FileExists( designBlock->GetBoardFile() ) )
1433 {
1434 editFrame->ShowInfoBarError( _( "Design block has no layout to place." ), true );
1435 return 1;
1436 }
1437
1439 IO_RELEASER<PCB_IO> pi( PCB_IO_MGR::FindPlugin( pluginType ) );
1440
1441 if( !pi )
1442 return 1;
1443
1444 bool repeatPlacement = false;
1445
1446 if( APP_SETTINGS_BASE* cfg = editFrame->config() )
1447 repeatPlacement = cfg->m_DesignBlockChooserPanel.repeated_placement;
1448
1449 int ret = 0;
1450
1451 do
1452 {
1453 ret = AppendBoard( *pi, designBlock->GetBoardFile(), designBlock.get() );
1454 } while( repeatPlacement && ret == 0 );
1455
1456 return ret;
1457}
1458
1460{
1461 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
1462
1463 if( !editFrame )
1464 return 1;
1465
1466 BOARD* brd = board();
1467
1468 if( !brd )
1469 return 1;
1470
1471 PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
1473
1474 std::vector<PCB_GROUP*> linkedGroups;
1475 int skippedNoLink = 0;
1476
1477 for( EDA_ITEM* item : selection )
1478 {
1479 if( item->Type() != PCB_GROUP_T )
1480 continue;
1481
1482 PCB_GROUP* g = static_cast<PCB_GROUP*>( item );
1483
1484 if( g->HasDesignBlockLink() )
1485 linkedGroups.push_back( g );
1486 else
1487 skippedNoLink++;
1488 }
1489
1490 if( linkedGroups.empty() )
1491 {
1492 m_frame->ShowInfoBarError( _( "No groups with a linked design block are selected." ), true );
1493 return 1;
1494 }
1495
1496 if( !editFrame->GetOverrideLocks() )
1497 {
1498 bool hasLocked = false;
1499
1500 for( PCB_GROUP* g : linkedGroups )
1501 {
1502 for( EDA_ITEM* item : g->GetItems() )
1503 {
1504 if( item->Type() == PCB_FOOTPRINT_T && static_cast<FOOTPRINT*>( item )->IsLocked() )
1505 {
1506 hasLocked = true;
1507 break;
1508 }
1509 }
1510
1511 if( hasLocked )
1512 break;
1513 }
1514
1515 if( hasLocked )
1516 {
1517 m_frame->ShowInfoBarWarning( _( "Selection contains locked items. "
1518 "Enable 'Override locks' to operate on them." ),
1519 true );
1520 return 1;
1521 }
1522 }
1523
1525 BOARD_COMMIT sharedCommit( m_frame );
1526
1527 struct Failure
1528 {
1530 wxString reason;
1531 };
1532 std::vector<Failure> failures;
1533 int applied = 0;
1534 bool cancelled = false;
1535 bool netlessCopperPlaced = false;
1536
1537 std::unique_ptr<WX_PROGRESS_REPORTER> progress;
1538
1539 if( linkedGroups.size() > 1 && Pgm().IsGUI() )
1540 {
1541 progress = std::make_unique<WX_PROGRESS_REPORTER>( m_frame, _( "Applying Design Block Layouts" ),
1542 (int) linkedGroups.size(), PR_CAN_ABORT );
1543 }
1544
1545 auto generateBoundingBox = []( const std::unordered_set<EDA_ITEM*>& aItems )
1546 {
1547 std::vector<VECTOR2I> bbCorners;
1548 bbCorners.reserve( aItems.size() * 4 );
1549
1550 for( EDA_ITEM* item : aItems )
1551 {
1552 const BOX2I bb = item->GetBoundingBox().GetInflated( 100000 );
1553 KIGEOM::CollectBoxCorners( bb, bbCorners );
1554 }
1555
1556 std::vector<VECTOR2I> hullVertices;
1557 BuildConvexHull( hullVertices, bbCorners );
1558
1559 SHAPE_LINE_CHAIN hull( hullVertices );
1560 return KIGEOM::RectifyPolygon( hull );
1561 };
1562
1563 // Apply the linked design block's layout to a single group. Returns with a
1564 // human-readable reason on failure.
1565 auto applyOneGroup = [&]( PCB_GROUP* group, wxString& outErr ) -> bool
1566 {
1567 DESIGN_BLOCK_PANE* pane = editFrame->GetDesignBlockPane();
1568 std::unique_ptr<DESIGN_BLOCK> designBlock( pane->GetDesignBlock( group->GetDesignBlockLibId(), true, true ) );
1569
1570 if( !designBlock )
1571 {
1572 outErr = _( "design block is not in the loaded libraries" );
1573 return false;
1574 }
1575
1576 if( designBlock->GetBoardFile().IsEmpty() )
1577 {
1578 outErr = _( "design block has no saved PCB layout" );
1579 return false;
1580 }
1581
1582 brd->Visit(
1583 []( EDA_ITEM* item, void* )
1584 {
1585 item->SetFlags( MCT_SKIP_STRUCT );
1587 },
1589
1590 auto clearFlags = [&]()
1591 {
1592 brd->Visit(
1593 []( EDA_ITEM* item, void* )
1594 {
1595 item->ClearFlags( MCT_SKIP_STRUCT );
1597 },
1599 };
1600
1601 BOARD_COMMIT tempCommit( m_frame );
1602
1604 IO_RELEASER<PCB_IO> pi( PCB_IO_MGR::FindPlugin( pluginType ) );
1605
1606 if( !pi || AppendBoard( *pi, designBlock->GetBoardFile(), designBlock.get(), &tempCommit, true ) != 0 )
1607 {
1608 clearFlags();
1609 outErr = _( "could not load the design block's layout" );
1610 return false;
1611 }
1612
1613 RULE_AREA dbRA;
1615 dbRA.m_generateEnabled = true;
1616
1617 brd->Visit(
1618 [&]( EDA_ITEM* item, void* )
1619 {
1620 if( !item->HasFlag( MCT_SKIP_STRUCT ) )
1621 {
1622 dbRA.m_designBlockItems.insert( item );
1623
1624 if( item->Type() == PCB_FOOTPRINT_T )
1625 dbRA.m_components.insert( static_cast<FOOTPRINT*>( item ) );
1626 }
1627
1629 },
1631
1632 if( dbRA.m_designBlockItems.empty() )
1633 {
1634 tempCommit.Revert();
1635 clearFlags();
1636 outErr = _( "design block contains no items to apply" );
1637 return false;
1638 }
1639
1640 // Footprint-free copper has no matched pads to map nets through, so it is copied as no-net.
1641 bool blockHasNetlessCopper = false;
1642
1643 if( dbRA.m_components.empty() )
1644 {
1645 for( EDA_ITEM* item : dbRA.m_designBlockItems )
1646 {
1647 if( BOARD_ITEM* bi = dynamic_cast<BOARD_ITEM*>( item ); bi && bi->IsConnected() )
1648 {
1649 blockHasNetlessCopper = true;
1650 break;
1651 }
1652 }
1653 }
1654
1655 dbRA.m_zone = new ZONE( brd );
1656 dbRA.m_zone->SetIsRuleArea( true );
1658 dbRA.m_zone->SetPlacementAreaEnabled( true );
1659 dbRA.m_zone->SetDoNotAllowZoneFills( false );
1660 dbRA.m_zone->SetDoNotAllowVias( false );
1661 dbRA.m_zone->SetDoNotAllowTracks( false );
1662 dbRA.m_zone->SetDoNotAllowPads( false );
1663 dbRA.m_zone->SetDoNotAllowFootprints( false );
1665 dbRA.m_zone->SetPlacementAreaSource( group->GetDesignBlockLibId().GetUniStringLibId() );
1667 dbRA.m_zone->AddPolygon( generateBoundingBox( dbRA.m_designBlockItems ) );
1668 dbRA.m_center = dbRA.m_zone->Outline()->COutline( 0 ).Centre();
1669
1670 RULE_AREA destRA;
1672
1673 for( EDA_ITEM* item : group->GetItems() )
1674 {
1675 if( item->Type() == PCB_FOOTPRINT_T )
1676 destRA.m_components.insert( static_cast<FOOTPRINT*>( item ) );
1677 }
1678
1679 destRA.m_group = group;
1680
1681 if( group->GetItems().empty() )
1682 {
1683 tempCommit.Revert();
1684 clearFlags();
1685 delete dbRA.m_zone;
1686 outErr = _( "group is empty" );
1687 return false;
1688 }
1689
1690 destRA.m_zone = new ZONE( brd );
1691 destRA.m_zone->SetZoneName( wxString::Format( wxT( "design-block-dest-%s" ),
1692 group->GetDesignBlockLibId().GetUniStringLibId() ) );
1693 destRA.m_zone->SetIsRuleArea( true );
1694 destRA.m_zone->SetLayerSet( LSET::AllCuMask() );
1695 destRA.m_zone->SetPlacementAreaEnabled( true );
1696 destRA.m_zone->SetDoNotAllowZoneFills( false );
1697 destRA.m_zone->SetDoNotAllowVias( false );
1698 destRA.m_zone->SetDoNotAllowTracks( false );
1699 destRA.m_zone->SetDoNotAllowPads( false );
1700 destRA.m_zone->SetDoNotAllowFootprints( false );
1702 destRA.m_zone->SetPlacementAreaSource( group->GetName() );
1704 destRA.m_zone->AddPolygon( generateBoundingBox( group->GetItems() ) );
1705 destRA.m_center = destRA.m_zone->Outline()->COutline( 0 ).Centre();
1706
1707 REPEAT_LAYOUT_OPTIONS options = { .m_copyRouting = true,
1708 .m_connectedRoutingOnly = false,
1709 .m_copyPlacement = true,
1710 .m_copyOtherItems = true,
1711 .m_groupItems = false,
1712 .m_includeLockedItems = true,
1713 .m_anchorFp = nullptr };
1714
1715 // Give the appended block's auto-generated nets a private namespace so they cannot fuse by
1716 // name with a different part's net on the board, which would corrupt the topology match
1717 // (issue 24767). Reverted with the temporary block, so the private nets are removed below.
1718 std::vector<NETINFO_ITEM*> isolatedNets =
1720
1721 wxString repeatErr;
1722 int result = mct->RepeatLayout( aEvent, dbRA, destRA, options, &sharedCommit, &repeatErr );
1723
1724 tempCommit.Revert();
1725
1726 for( NETINFO_ITEM* net : isolatedNets )
1727 {
1728 brd->Remove( net );
1729 delete net;
1730 }
1731
1732 clearFlags();
1733 delete dbRA.m_zone;
1734 delete destRA.m_zone;
1735
1736 if( result != 0 )
1737 {
1738 outErr = repeatErr.IsEmpty() ? _( "layout copy failed" ) : repeatErr;
1739 return false;
1740 }
1741
1742 if( blockHasNetlessCopper )
1743 netlessCopperPlaced = true;
1744
1745 return true;
1746 };
1747
1748 for( size_t i = 0; i < linkedGroups.size(); ++i )
1749 {
1750 PCB_GROUP* g = linkedGroups[i];
1751
1752 if( progress )
1753 {
1754 progress->SetCurrentProgress( static_cast<double>( i ) / linkedGroups.size() );
1755 progress->Report(
1756 wxString::Format( _( "Applying layout to group %zu of %zu..." ), i + 1, linkedGroups.size() ) );
1757
1758 if( !progress->KeepRefreshing() )
1759 {
1760 cancelled = true;
1761 break;
1762 }
1763 }
1764
1765 wxString err;
1766
1767 if( applyOneGroup( g, err ) )
1768 applied++;
1769 else
1770 failures.push_back( { g, err } );
1771 }
1772
1773 if( progress )
1774 progress->SetCurrentProgress( 1.0 );
1775
1776 if( cancelled )
1777 {
1778 sharedCommit.Revert();
1779 m_frame->ShowInfoBarMsg( _( "Apply design block layout cancelled." ), true );
1780 return 1;
1781 }
1782
1783 if( applied > 0 )
1784 {
1785 sharedCommit.Push( wxString::Format( _( "Apply design block layout to %d group(s)" ), applied ) );
1786
1787 if( netlessCopperPlaced )
1788 m_frame->ShowInfoBarMsg( _( "Copied copper has no net assigned. Assign nets to connect it." ), true );
1789 }
1790 else
1791 {
1792 sharedCommit.Revert();
1793 }
1794
1795 if( skippedNoLink > 0 || !failures.empty() || linkedGroups.size() > 1 )
1796 {
1797 wxString html;
1798
1799 html << wxT( "<p>" )
1800 << wxString::Format( _( "Applied design block layout to %d of %d group(s)." ), applied,
1801 (int) linkedGroups.size() )
1802 << wxT( "</p>" );
1803
1804 if( skippedNoLink > 0 )
1805 {
1806 html << wxT( "<p>" )
1807 << wxString::Format( _( "Skipped %d selected item(s) that are not groups linked to a "
1808 "design block." ),
1809 skippedNoLink )
1810 << wxT( "</p>" );
1811 }
1812
1813 if( !failures.empty() )
1814 {
1815 html << wxT( "<p>" ) << _( "The following groups could not be processed:" ) << wxT( "</p><ul>" );
1816
1817 for( const Failure& f : failures )
1818 {
1819 wxString name = f.group->GetName().IsEmpty() ? _( "(unnamed group)" ) : f.group->GetName();
1820 html << wxString::Format( wxT( "<li><b>%s</b>: %s</li>" ), name, f.reason );
1821 }
1822
1823 html << wxT( "</ul>" );
1824 }
1825
1826 HTML_MESSAGE_BOX dlg( m_frame, _( "Apply Design Block Layout" ) );
1827 dlg.SetDialogSizeInDU( 360, 220 );
1828 dlg.AddHTML_Text( html );
1829 dlg.ShowModal();
1830 }
1831
1832 return applied > 0 ? 0 : 1;
1833}
1834
1836{
1837 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
1838
1839 if( !editFrame )
1840 return 1;
1841
1842 // Need to have a group selected and it needs to have a linked design block
1843 PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
1845
1846 if( selection.Size() != 1 || selection[0]->Type() != PCB_GROUP_T )
1847 return 1;
1848
1849 PCB_GROUP* group = static_cast<PCB_GROUP*>( selection[0] );
1850
1851 if( !group->HasDesignBlockLink() )
1852 return 1;
1853
1854 // Get the associated design block
1855 DESIGN_BLOCK_PANE* designBlockPane = editFrame->GetDesignBlockPane();
1856 std::unique_ptr<DESIGN_BLOCK> designBlock( designBlockPane->GetDesignBlock( group->GetDesignBlockLibId(),
1857 true, true ) );
1858
1859 if( !designBlock )
1860 {
1861 wxString msg;
1862 msg.Printf( _( "Could not find design block %s." ), group->GetDesignBlockLibId().GetUniStringLibId() );
1863 m_frame->GetInfoBar()->ShowMessageFor( msg, 5000, wxICON_WARNING );
1864 return 1;
1865 }
1866
1867 if( designBlock->GetBoardFile().IsEmpty() )
1868 {
1869 wxString msg;
1870 msg.Printf( _( "Design block %s does not have a board file." ),
1871 group->GetDesignBlockLibId().GetUniStringLibId() );
1872 m_frame->GetInfoBar()->ShowMessageFor( msg, 5000, wxICON_WARNING );
1873 return 1;
1874 }
1875
1876
1878 IO_RELEASER<PCB_IO> pi( PCB_IO_MGR::FindPlugin( pluginType ) );
1879
1880 if( !pi )
1881 return 1;
1882
1883 if( aEvent.Parameter<bool*>() != nullptr )
1884 return AppendBoard( *pi, designBlock->GetBoardFile(), designBlock.get(),
1885 static_cast<BOARD_COMMIT*>( aEvent.Commit() ), *aEvent.Parameter<bool*>() );
1886 else
1887 return AppendBoard( *pi, designBlock->GetBoardFile(), designBlock.get() );
1888}
1889
1890
1892{
1893 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
1894
1895 if( !editFrame )
1896 return 1;
1897
1898 // Need to have a group selected and it needs to have a linked design block
1899 PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
1901
1902 if( selection.Size() != 1 || selection[0]->Type() != PCB_GROUP_T )
1903 return 1;
1904
1905 PCB_GROUP* group = static_cast<PCB_GROUP*>( selection[0] );
1906
1907 if( !group->HasDesignBlockLink() )
1908 return 1;
1909
1910 // Get the associated design block
1911 DESIGN_BLOCK_PANE* designBlockPane = editFrame->GetDesignBlockPane();
1912 std::unique_ptr<DESIGN_BLOCK> designBlock( designBlockPane->GetDesignBlock( group->GetDesignBlockLibId(),
1913 true, true ) );
1914
1915 if( !designBlock )
1916 {
1917 wxString msg;
1918 msg.Printf( _( "Could not find design block %s." ), group->GetDesignBlockLibId().GetUniStringLibId() );
1919 m_frame->GetInfoBar()->ShowMessageFor( msg, 5000, wxICON_WARNING );
1920 return 1;
1921 }
1922
1923 editFrame->GetDesignBlockPane()->SelectLibId( group->GetDesignBlockLibId() );
1924
1925 return m_toolMgr->RunAction( PCB_ACTIONS::updateDesignBlockFromSelection ) ? 1 : 0;
1926}
1927
1928
1929bool PCB_CONTROL::placeBoardItems( BOARD_COMMIT* aCommit, BOARD* aBoard, bool aAnchorAtOrigin,
1930 bool aReannotateDuplicates, bool aSkipMove )
1931{
1932 // items are new if the current board is not the board source
1933 bool isNew = board() != aBoard;
1934 std::vector<BOARD_ITEM*> items;
1935
1936 for( BOARD_ITEM* item : aBoard->GetItemSet() )
1937 {
1938 // Marker transfer is intentionally not part of append/paste item placement.
1939 if( item->Type() == PCB_MARKER_T )
1940 continue;
1941
1942 bool doCopy = ( item->GetFlags() & SKIP_STRUCT ) == 0;
1943
1944 item->ClearFlags( SKIP_STRUCT );
1945 item->SetFlags( isNew ? IS_NEW : 0 );
1946
1947 if( doCopy )
1948 items.push_back( item );
1949 }
1950
1951 if( isNew )
1952 aBoard->RemoveAll();
1953
1954 // Reparent before calling pruneItemLayers, as SetLayer can have a dependence on the
1955 // item's parent board being set correctly.
1956 if( isNew )
1957 {
1958 for( BOARD_ITEM* item : items )
1959 item->SetParent( board() );
1960 }
1961
1962 pruneItemLayers( items );
1963
1964 return placeBoardItems( aCommit, items, isNew, aAnchorAtOrigin, aReannotateDuplicates, aSkipMove );
1965}
1966
1967
1968bool PCB_CONTROL::placeBoardItems( BOARD_COMMIT* aCommit, std::vector<BOARD_ITEM*>& aItems, bool aIsNew,
1969 bool aAnchorAtOrigin, bool aReannotateDuplicates, bool aSkipMove )
1970{
1971 m_toolMgr->RunAction( ACTIONS::selectionClear );
1972
1973 PCB_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
1974
1975 std::vector<BOARD_ITEM*> itemsToSel;
1976 itemsToSel.reserve( aItems.size() );
1977
1978 for( BOARD_ITEM* item : aItems )
1979 {
1980 if( aIsNew )
1981 {
1982 item->ResetUuid();
1983
1984 item->RunOnChildren(
1985 []( BOARD_ITEM* aChild )
1986 {
1987 aChild->ResetUuid();
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 // Select the items that should be selected
2042 EDA_ITEMS toSel( itemsToSel.begin(), itemsToSel.end() );
2043 m_toolMgr->RunAction<EDA_ITEMS*>( ACTIONS::selectItems, &toSel );
2044
2045 // Reannotate duplicate footprints (make sense only in board editor )
2046 if( aReannotateDuplicates && m_isBoardEditor )
2047 m_toolMgr->GetTool<BOARD_REANNOTATE_TOOL>()->ReannotateDuplicatesInSelection();
2048
2049 for( BOARD_ITEM* item : aItems )
2050 {
2051 if( aIsNew )
2052 aCommit->Add( item );
2053 else
2054 aCommit->Added( item );
2055 }
2056
2057 PCB_SELECTION& selection = selectionTool->GetSelection();
2058
2059 if( selection.Size() > 0 )
2060 {
2061 if( aAnchorAtOrigin )
2062 {
2063 selection.SetReferencePoint( VECTOR2I( 0, 0 ) );
2064 }
2065 else if( BOARD_ITEM* item = dynamic_cast<BOARD_ITEM*>( selection.GetTopLeftItem() ) )
2066 {
2067 selection.SetReferencePoint( item->GetPosition() );
2068 }
2069
2070 getViewControls()->SetCursorPosition( getViewControls()->GetMousePosition(), false );
2071
2072 m_toolMgr->ProcessEvent( EVENTS::SelectedEvent );
2073
2074 if( !aSkipMove )
2075 return m_toolMgr->RunSynchronousAction( PCB_ACTIONS::move, aCommit );
2076 }
2077
2078 return true;
2079}
2080
2081
2082int PCB_CONTROL::AppendBoard( PCB_IO& pi, const wxString& fileName, DESIGN_BLOCK* aDesignBlock, BOARD_COMMIT* aCommit,
2083 bool aSkipMove )
2084{
2085 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
2086
2087 if( !editFrame )
2088 return 1;
2089
2090 BOARD* brd = board();
2091
2092 if( !brd )
2093 return 1;
2094
2095 // Give ourselves a commit to work with if we weren't provided one
2096 std::unique_ptr<BOARD_COMMIT> tempCommit;
2097 BOARD_COMMIT* commit = aCommit;
2098
2099 if( !commit )
2100 {
2101 tempCommit = std::make_unique<BOARD_COMMIT>( editFrame );
2102 commit = tempCommit.get();
2103 }
2104
2105 // Mark existing items, in order to know what are the new items so we can select only
2106 // the new items after loading
2107 BOARD_ITEM_SET existingItems = brd->GetItemSet();
2108
2109 for( BOARD_ITEM* item : existingItems )
2110 item->SetFlags( SKIP_STRUCT );
2111
2112 auto clearSkipStructOnExistingItems =
2113 [&existingItems]()
2114 {
2115 for( BOARD_ITEM* item : existingItems )
2116 item->ClearFlags( SKIP_STRUCT );
2117 };
2118
2119 std::map<wxString, wxString> oldProperties = brd->GetProperties();
2120 std::map<wxString, wxString> newProperties;
2121
2122 PAGE_INFO oldPageInfo = brd->GetPageSettings();
2123 TITLE_BLOCK oldTitleBlock = brd->GetTitleBlock();
2124
2125 // Keep also the count of copper layers, to adjust if necessary
2126 int initialCopperLayerCount = brd->GetCopperLayerCount();
2127 LSET initialEnabledLayers = brd->GetEnabledLayers();
2128
2129 // Load the data
2130 try
2131 {
2132 std::map<std::string, UTF8> props;
2133
2134 // PCB_IO_EAGLE can use this info to center the BOARD, but it does not yet.
2135
2136 props["page_width"] = std::to_string( editFrame->GetPageSizeIU().x );
2137 props["page_height"] = std::to_string( editFrame->GetPageSizeIU().y );
2139
2141 [&]( wxString aTitle, int aIcon, wxString aMessage, wxString aAction ) -> bool
2142 {
2143 KIDIALOG dlg( editFrame, aMessage, aTitle, wxOK | wxCANCEL | aIcon );
2144
2145 if( !aAction.IsEmpty() )
2146 dlg.SetOKLabel( aAction );
2147
2148 dlg.DoNotShowCheckbox( aMessage, 0 );
2149
2150 return dlg.ShowModal() == wxID_OK;
2151 } );
2152
2153 // Let the user remap the appended board's layers onto this board when they do not match
2154 if( LAYER_MAPPABLE_PLUGIN* mappable = dynamic_cast<LAYER_MAPPABLE_PLUGIN*>( &pi ) )
2155 {
2156 mappable->RegisterCallback(
2157 [editFrame]( const std::vector<INPUT_LAYER_DESC>& aLayerDescs )
2158 {
2159 return DIALOG_MAP_LAYERS::RunModal( editFrame, aLayerDescs );
2160 } );
2161 }
2162
2163 WX_PROGRESS_REPORTER progressReporter( editFrame, _( "Load PCB" ), 1, PR_CAN_ABORT );
2164
2165 pi.SetProgressReporter( &progressReporter );
2166 pi.LoadBoard( fileName, brd, &props, nullptr );
2167 }
2168 catch( const IO_ERROR& ioe )
2169 {
2170 DisplayErrorMessage( editFrame, _( "Error loading board." ), ioe.What() );
2171 clearSkipStructOnExistingItems();
2172
2173 return 0;
2174 }
2175
2176 newProperties = brd->GetProperties();
2177
2178 for( const std::pair<const wxString, wxString>& prop : oldProperties )
2179 newProperties[prop.first] = prop.second;
2180
2181 brd->SetProperties( newProperties );
2182
2183 brd->SetPageSettings( oldPageInfo );
2184 brd->SetTitleBlock( oldTitleBlock );
2185
2186 // rebuild nets and ratsnest before any use of nets
2187 brd->BuildListOfNets();
2188 brd->SynchronizeNetsAndNetClasses( true );
2189 brd->BuildConnectivity();
2190
2191 // New appended items need to inherit the current global ratsnest state.
2192 // Existing items are marked SKIP_STRUCT and are handled elsewhere.
2193 const bool showGlobalRatsnest = displayOptions().m_ShowGlobalRatsnest;
2194
2195 for( BOARD_ITEM* item : brd->GetItemSet() )
2196 {
2197 if( item->GetFlags() & SKIP_STRUCT )
2198 continue;
2199
2200 if( BOARD_CONNECTED_ITEM* connectedItem = dynamic_cast<BOARD_CONNECTED_ITEM*>( item ) )
2201 connectedItem->SetLocalRatsnestVisible( showGlobalRatsnest );
2202
2203 if( item->Type() == PCB_FOOTPRINT_T )
2204 {
2205 for( PAD* pad : static_cast<FOOTPRINT*>( item )->Pads() )
2206 pad->SetLocalRatsnestVisible( showGlobalRatsnest );
2207 }
2208 }
2209
2210 // Synchronize layers
2211 // we should not ask PLUGINs to do these items:
2212 int copperLayerCount = brd->GetCopperLayerCount();
2213
2214 if( copperLayerCount > initialCopperLayerCount )
2215 brd->SetCopperLayerCount( copperLayerCount );
2216
2217 // Enable all used layers, and make them visible:
2218 LSET enabledLayers = brd->GetEnabledLayers();
2219 enabledLayers |= initialEnabledLayers;
2220 brd->SetEnabledLayers( enabledLayers );
2221 brd->SetVisibleLayers( enabledLayers );
2223
2224 if( brd->GetCopperLayerCount() != initialCopperLayerCount )
2225 {
2226 editFrame->GetInfoBar()->ShowMessageFor(
2227 wxString::Format( _( "Board changed from %d to %d copper layers, stackup updated." ),
2228 initialCopperLayerCount, brd->GetCopperLayerCount() ),
2229 6000, wxICON_INFORMATION );
2230 }
2231
2232 int ret = 0;
2233
2234 bool placeAsGroup = false;
2235
2236 if( APP_SETTINGS_BASE* cfg = editFrame->config() )
2237 placeAsGroup = cfg->m_DesignBlockChooserPanel.place_as_group;
2238
2239 if( placeBoardItems( commit, brd, false, false /* Don't reannotate dupes on Append Board */, aSkipMove ) )
2240 {
2241 if( placeAsGroup )
2242 {
2243 PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
2245
2246 // Count items that would be added to the group
2247 int groupableCount = 0;
2248
2249 for( EDA_ITEM* eda_item : selection )
2250 {
2251 if( eda_item->IsBOARD_ITEM()
2252 && !static_cast<BOARD_ITEM*>( eda_item )->GetParentFootprint() )
2253 {
2254 groupableCount++;
2255 }
2256 }
2257
2258 if( groupableCount >= 2 )
2259 {
2260 PCB_GROUP* group = new PCB_GROUP( brd );
2261
2262 if( aDesignBlock )
2263 {
2264 group->SetName( aDesignBlock->GetLibId().GetLibItemName() );
2265 group->SetDesignBlockLibId( aDesignBlock->GetLibId() );
2266 }
2267 else
2268 {
2269 group->SetName( wxFileName( fileName ).GetName() );
2270 }
2271
2272 for( EDA_ITEM* eda_item : selection )
2273 {
2274 if( eda_item->IsBOARD_ITEM() )
2275 {
2276 if( static_cast<BOARD_ITEM*>( eda_item )->IsLocked() )
2277 group->SetLocked( true );
2278 }
2279 }
2280
2281 commit->Add( group );
2282
2283 for( EDA_ITEM* eda_item : selection )
2284 {
2285 if( eda_item->IsBOARD_ITEM()
2286 && !static_cast<BOARD_ITEM*>( eda_item )->GetParentFootprint() )
2287 {
2288 commit->Modify( eda_item );
2289 group->AddItem( eda_item );
2290 }
2291 }
2292
2293 selTool->ClearSelection();
2294 selTool->select( group );
2295
2297 m_frame->OnModify();
2298 m_frame->Refresh();
2299 }
2300 }
2301
2302 // If we were provided a commit, let the caller control when to push it
2303 if( !aCommit )
2304 commit->Push( aDesignBlock ? _( "Place Design Block" ) : _( "Append Board" ) );
2305
2306 editFrame->GetBoard()->BuildConnectivity();
2307 ret = 0;
2308 }
2309 else
2310 {
2311 // If we were provided a commit, let the caller control when to revert it
2312 if( !aCommit )
2313 commit->Revert();
2314
2315 ret = 1;
2316 }
2317
2318 // Refresh the UI for the updated board properties
2319 editFrame->GetAppearancePanel()->OnBoardChanged();
2320 clearSkipStructOnExistingItems();
2321
2322 return ret;
2323}
2324
2325
2326int PCB_CONTROL::Undo( const TOOL_EVENT& aEvent )
2327{
2328 PCB_BASE_EDIT_FRAME* editFrame = dynamic_cast<PCB_BASE_EDIT_FRAME*>( m_frame );
2329 wxCommandEvent dummy;
2330
2331 if( editFrame )
2332 editFrame->RestoreCopyFromUndoList( dummy );
2333
2334 return 0;
2335}
2336
2337
2338int PCB_CONTROL::Redo( const TOOL_EVENT& aEvent )
2339{
2340 PCB_BASE_EDIT_FRAME* editFrame = dynamic_cast<PCB_BASE_EDIT_FRAME*>( m_frame );
2341 wxCommandEvent dummy;
2342
2343 if( editFrame )
2344 editFrame->RestoreCopyFromRedoList( dummy );
2345
2346 return 0;
2347}
2348
2349
2351{
2352 MAGNETIC_SETTINGS& settings = m_isFootprintEditor ? m_frame->GetFootprintEditorSettings()->m_MagneticItems
2353 : m_frame->GetPcbNewSettings()->m_MagneticItems;
2354 bool& snapMode = settings.allLayers;
2355
2357 snapMode = false;
2358 else if( aEvent.IsAction( &PCB_ACTIONS::magneticSnapAllLayers ) )
2359 snapMode = true;
2360 else
2361 snapMode = !snapMode;
2362
2364
2365 return 0;
2366}
2367
2368
2370{
2371 if( !Pgm().GetCommonSettings()->m_Input.hotkey_feedback )
2372 return 0;
2373
2374 wxArrayString labels;
2375 labels.Add( _( "Active Layer" ) );
2376 labels.Add( _( "All Layers" ) );
2377
2378 if( !m_frame->GetHotkeyPopup() )
2379 m_frame->CreateHotkeyPopup();
2380
2381 HOTKEY_CYCLE_POPUP* popup = m_frame->GetHotkeyPopup();
2382
2383 MAGNETIC_SETTINGS& settings = m_isFootprintEditor ? m_frame->GetFootprintEditorSettings()->m_MagneticItems
2384 : m_frame->GetPcbNewSettings()->m_MagneticItems;
2385
2386 if( popup )
2387 popup->Popup( _( "Object Snapping" ), labels, static_cast<int>( settings.allLayers ) );
2388
2389 return 0;
2390}
2391
2392
2394{
2395 PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
2396 ROUTER_TOOL* routerTool = m_toolMgr->GetTool<ROUTER_TOOL>();
2397 PCB_SELECTION& selection = selTool->GetSelection();
2398 PCB_EDIT_FRAME* pcbFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
2399 std::shared_ptr<DRC_ENGINE> drcEngine = m_frame->GetBoard()->GetDesignSettings().m_DRCEngine;
2400 DRC_CONSTRAINT constraint;
2401
2402 std::vector<MSG_PANEL_ITEM> msgItems;
2403
2404 if( routerTool && routerTool->RoutingInProgress() )
2405 {
2406 routerTool->UpdateMessagePanel();
2407 return 0;
2408 }
2409
2410 if( !pcbFrame && !m_frame->GetModel() )
2411 return 0;
2412
2413 if( selection.Empty() )
2414 {
2415 if( !pcbFrame )
2416 {
2417 FOOTPRINT* fp = static_cast<FOOTPRINT*>( m_frame->GetModel() );
2418 fp->GetMsgPanelInfo( m_frame, msgItems );
2419 }
2420 else
2421 {
2422 m_frame->SetMsgPanel( m_frame->GetBoard() );
2423 }
2424 }
2425 else if( selection.GetSize() == 1 )
2426 {
2427 EDA_ITEM* item = selection.Front();
2428
2429 if( std::optional<wxString> uuid = GetMsgPanelDisplayUuid( item->m_Uuid ) )
2430 msgItems.emplace_back( _( "UUID" ), *uuid );
2431
2432 item->GetMsgPanelInfo( m_frame, msgItems );
2433
2434 PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( item );
2435 NETINFO_ITEM* net = track ? track->GetNet() : nullptr;
2436 NETINFO_ITEM* coupledNet = net ? m_frame->GetBoard()->DpCoupledNet( net ) : nullptr;
2437
2438 if( coupledNet )
2439 {
2440 SEG trackSeg( track->GetStart(), track->GetEnd() );
2441 PCB_TRACK* coupledItem = nullptr;
2442 SEG::ecoord closestDist_sq = VECTOR2I::ECOORD_MAX;
2443
2444 for( PCB_TRACK* candidate : m_frame->GetBoard()->Tracks() )
2445 {
2446 if( candidate->GetNet() != coupledNet )
2447 continue;
2448
2449 SEG::ecoord dist_sq = trackSeg.SquaredDistance( SEG( candidate->GetStart(), candidate->GetEnd() ) );
2450
2451 if( !coupledItem || dist_sq < closestDist_sq )
2452 {
2453 coupledItem = candidate;
2454 closestDist_sq = dist_sq;
2455 }
2456 }
2457
2458 constraint = drcEngine->EvalRules( DIFF_PAIR_GAP_CONSTRAINT, track, coupledItem, track->GetLayer() );
2459
2460 wxString msg = m_frame->MessageTextFromMinOptMax( constraint.Value() );
2461
2462 if( !msg.IsEmpty() )
2463 {
2464 msgItems.emplace_back( wxString::Format( _( "DP Gap Constraints: %s" ), msg ),
2465 wxString::Format( _( "(from %s)" ), constraint.GetName() ) );
2466 }
2467
2468 constraint = drcEngine->EvalRules( MAX_UNCOUPLED_CONSTRAINT, track, coupledItem, track->GetLayer() );
2469
2470 if( constraint.Value().HasMax() )
2471 {
2472 msg = m_frame->MessageTextFromValue( constraint.Value().Max() );
2473 msgItems.emplace_back( wxString::Format( _( "DP Max Uncoupled-length: %s" ), msg ),
2474 wxString::Format( _( "(from %s)" ), constraint.GetName() ) );
2475 }
2476 }
2477 }
2478 else if( pcbFrame && selection.GetSize() == 2 )
2479 {
2480 // Pair selection broken into multiple, optional data, starting with the selected item
2481 // names
2482
2483 BOARD_ITEM* a = dynamic_cast<BOARD_ITEM*>( selection[0] );
2484 BOARD_ITEM* b = dynamic_cast<BOARD_ITEM*>( selection[1] );
2485
2486 if( a && b )
2487 {
2488 msgItems.emplace_back( MSG_PANEL_ITEM( a->GetItemDescription( m_frame, false ),
2489 b->GetItemDescription( m_frame, false ) ) );
2490 }
2491
2492 BOARD_CONNECTED_ITEM* a_conn = dynamic_cast<BOARD_CONNECTED_ITEM*>( a );
2493 BOARD_CONNECTED_ITEM* b_conn = dynamic_cast<BOARD_CONNECTED_ITEM*>( b );
2494
2495 if( a_conn && b_conn )
2496 {
2497 LSET overlap = a_conn->GetLayerSet() & b_conn->GetLayerSet() & LSET::AllCuMask();
2498 int a_netcode = a_conn->GetNetCode();
2499 int b_netcode = b_conn->GetNetCode();
2500
2501 if( overlap.count() > 0 )
2502 {
2503 PCB_LAYER_ID layer = overlap.CuStack().front();
2504
2505 if( a_netcode != b_netcode || a_netcode < 0 || b_netcode < 0 )
2506 {
2507 constraint = drcEngine->EvalRules( CLEARANCE_CONSTRAINT, a, b, layer );
2508 msgItems.emplace_back( _( "Resolved Clearance" ),
2509 m_frame->MessageTextFromValue( constraint.m_Value.Min() ) );
2510 }
2511
2512 std::shared_ptr<SHAPE> a_shape( a_conn->GetEffectiveShape( layer ) );
2513 std::shared_ptr<SHAPE> b_shape( b_conn->GetEffectiveShape( layer ) );
2514
2515 int actual_clearance = a_shape->GetClearance( b_shape.get() );
2516
2517 if( actual_clearance > -1 && actual_clearance < std::numeric_limits<int>::max() )
2518 {
2519 msgItems.emplace_back( _( "Actual Clearance" ),
2520 m_frame->MessageTextFromValue( actual_clearance ) );
2521 }
2522 }
2523 }
2524
2525 if( a && b && ( a->HasHole() || b->HasHole() ) )
2526 {
2527 PCB_LAYER_ID active = m_frame->GetActiveLayer();
2529
2530 if( b->IsOnLayer( active ) && IsCopperLayer( active ) )
2531 layer = active;
2532 else if( b->HasHole() && a->IsOnLayer( active ) && IsCopperLayer( active ) )
2533 layer = active;
2534 else if( a->HasHole() && b->IsOnCopperLayer() )
2535 layer = b->GetLayer();
2536 else if( b->HasHole() && a->IsOnCopperLayer() )
2537 layer = a->GetLayer();
2538
2539 if( IsCopperLayer( layer ) )
2540 {
2541 int actual = std::numeric_limits<int>::max();
2542
2543 if( a->HasHole() && b->IsOnCopperLayer() )
2544 {
2545 std::shared_ptr<SHAPE_SEGMENT> hole = a->GetEffectiveHoleShape();
2546 std::shared_ptr<SHAPE> other( b->GetEffectiveShape( layer ) );
2547
2548 actual = std::min( actual, hole->GetClearance( other.get() ) );
2549 }
2550
2551 if( b->HasHole() && a->IsOnCopperLayer() )
2552 {
2553 std::shared_ptr<SHAPE_SEGMENT> hole = b->GetEffectiveHoleShape();
2554 std::shared_ptr<SHAPE> other( a->GetEffectiveShape( layer ) );
2555
2556 actual = std::min( actual, hole->GetClearance( other.get() ) );
2557 }
2558
2559 if( actual < std::numeric_limits<int>::max() )
2560 {
2561 constraint = drcEngine->EvalRules( HOLE_CLEARANCE_CONSTRAINT, a, b, layer );
2562 msgItems.emplace_back( _( "Resolved Hole Clearance" ),
2563 m_frame->MessageTextFromValue( constraint.m_Value.Min() ) );
2564
2565 if( actual > -1 && actual < std::numeric_limits<int>::max() )
2566 {
2567 msgItems.emplace_back( _( "Actual Hole Clearance" ),
2568 m_frame->MessageTextFromValue( actual ) );
2569 }
2570 }
2571 }
2572 }
2573
2574 if( a && b )
2575 {
2576 for( PCB_LAYER_ID edgeLayer : { Edge_Cuts, Margin } )
2577 {
2578 PCB_LAYER_ID active = m_frame->GetActiveLayer();
2580
2581 if( a->IsOnLayer( edgeLayer ) && b->Type() != PCB_FOOTPRINT_T )
2582 {
2583 if( b->IsOnLayer( active ) && IsCopperLayer( active ) )
2584 layer = active;
2585 else if( IsCopperLayer( b->GetLayer() ) )
2586 layer = b->GetLayer();
2587 }
2588 else if( b->IsOnLayer( edgeLayer ) && a->Type() != PCB_FOOTPRINT_T )
2589 {
2590 if( a->IsOnLayer( active ) && IsCopperLayer( active ) )
2591 layer = active;
2592 else if( IsCopperLayer( a->GetLayer() ) )
2593 layer = a->GetLayer();
2594 }
2595
2596 if( layer >= 0 )
2597 {
2598 constraint = drcEngine->EvalRules( EDGE_CLEARANCE_CONSTRAINT, a, b, layer );
2599
2600 if( edgeLayer == Edge_Cuts )
2601 {
2602 msgItems.emplace_back( _( "Resolved Edge Clearance" ),
2603 m_frame->MessageTextFromValue( constraint.m_Value.Min() ) );
2604 }
2605 else
2606 {
2607 msgItems.emplace_back( _( "Resolved Margin Clearance" ),
2608 m_frame->MessageTextFromValue( constraint.m_Value.Min() ) );
2609 }
2610 }
2611 }
2612 }
2613 }
2614
2615 if( selection.GetSize() )
2616 {
2617 if( msgItems.empty() )
2618 {
2619 // Count items by type
2620 std::map<KICAD_T, int> typeCounts;
2621
2622 for( EDA_ITEM* item : selection )
2623 typeCounts[item->Type()]++;
2624
2625 // Check if all items are the same type
2626 bool allSameType = ( typeCounts.size() == 1 );
2627 KICAD_T commonType = allSameType ? typeCounts.begin()->first : NOT_USED;
2628
2629 if( allSameType )
2630 {
2631 // Show "Type: N" for homogeneous selections
2632 wxString typeName = selection.Front()->GetFriendlyName();
2633 msgItems.emplace_back( typeName,
2634 wxString::Format( wxT( "%d" ), selection.GetSize() ) );
2635
2636 // For pads, show common properties
2637 if( commonType == PCB_PAD_T )
2638 {
2639 std::set<wxString> layers;
2640 std::set<PAD_SHAPE> shapes;
2641 std::set<VECTOR2I> sizes;
2642
2643 for( EDA_ITEM* item : selection )
2644 {
2645 PAD* pad = static_cast<PAD*>( item );
2646 layers.insert( pad->LayerMaskDescribe() );
2647 shapes.insert( pad->GetShape( PADSTACK::ALL_LAYERS ) );
2648 sizes.insert( pad->GetSize( PADSTACK::ALL_LAYERS ) );
2649 }
2650
2651 if( layers.size() == 1 )
2652 msgItems.emplace_back( _( "Layer" ), *layers.begin() );
2653
2654 if( shapes.size() == 1 )
2655 {
2656 PAD* firstPad = static_cast<PAD*>( selection.Front() );
2657 msgItems.emplace_back( _( "Pad Shape" ),
2658 firstPad->ShowPadShape( PADSTACK::ALL_LAYERS ) );
2659 }
2660
2661 if( sizes.size() == 1 )
2662 {
2663 VECTOR2I size = *sizes.begin();
2664 msgItems.emplace_back( _( "Pad Size" ),
2665 wxString::Format( wxT( "%s x %s" ),
2666 m_frame->MessageTextFromValue( size.x ),
2667 m_frame->MessageTextFromValue( size.y ) ) );
2668 }
2669 }
2670 }
2671 else
2672 {
2673 // Show type breakdown for mixed selections
2674 wxString breakdown;
2675
2676 for( const auto& [type, count] : typeCounts )
2677 {
2678 if( !breakdown.IsEmpty() )
2679 breakdown += wxT( ", " );
2680
2681 // Get friendly name from first item of this type
2682 wxString typeName;
2683
2684 for( EDA_ITEM* item : selection )
2685 {
2686 if( item->Type() == type )
2687 {
2688 typeName = item->GetFriendlyName();
2689 break;
2690 }
2691 }
2692
2693 breakdown += wxString::Format( wxT( "%s: %d" ), typeName, count );
2694 }
2695
2696 msgItems.emplace_back( _( "Selected Items" ),
2697 wxString::Format( wxT( "%d (%s)" ),
2698 selection.GetSize(), breakdown ) );
2699 }
2700
2701 if( m_isBoardEditor )
2702 {
2703 std::set<wxString> netNames;
2704 std::set<wxString> netClasses;
2705
2706 for( EDA_ITEM* item : selection )
2707 {
2708 if( BOARD_CONNECTED_ITEM* bci = dynamic_cast<BOARD_CONNECTED_ITEM*>( item ) )
2709 {
2710 if( !bci->GetNet() || bci->GetNetCode() <= NETINFO_LIST::UNCONNECTED )
2711 continue;
2712
2713 netNames.insert( UnescapeString( bci->GetNetname() ) );
2714 netClasses.insert( UnescapeString( bci->GetEffectiveNetClass()->GetHumanReadableName() ) );
2715
2716 if( netNames.size() > 1 && netClasses.size() > 1 )
2717 break;
2718 }
2719 }
2720
2721 if( netNames.size() == 1 )
2722 msgItems.emplace_back( _( "Net" ), *netNames.begin() );
2723
2724 if( netClasses.size() == 1 )
2725 msgItems.emplace_back( _( "Resolved Netclass" ), *netClasses.begin() );
2726 }
2727 }
2728
2729 if( selection.GetSize() >= 2 )
2730 {
2731 bool lengthValid = true;
2732 double selectedLength = 0;
2733
2734 // Lambda to accumulate track length if item is a track or arc, otherwise mark invalid
2735 std::function<void( EDA_ITEM* )> accumulateTrackLength;
2736
2737 accumulateTrackLength =
2738 [&]( EDA_ITEM* aItem )
2739 {
2740 if( aItem->Type() == PCB_TRACE_T || aItem->Type() == PCB_ARC_T )
2741 {
2742 selectedLength += static_cast<PCB_TRACK*>( aItem )->GetLength();
2743 }
2744 else if( aItem->Type() == PCB_VIA_T )
2745 {
2746 // zero 2D length
2747 }
2748 else if( aItem->Type() == PCB_SHAPE_T )
2749 {
2750 PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( aItem );
2751
2752 if( shape->GetShape() == SHAPE_T::SEGMENT
2753 || shape->GetShape() == SHAPE_T::ARC
2754 || shape->GetShape() == SHAPE_T::BEZIER )
2755 {
2756 selectedLength += shape->GetLength();
2757 }
2758 else
2759 {
2760 lengthValid = false;
2761 }
2762 }
2763 // Use dynamic_cast to include PCB_GENERATORs.
2764 else if( PCB_GROUP* group = dynamic_cast<PCB_GROUP*>( aItem ) )
2765 {
2766 group->RunOnChildren( accumulateTrackLength, RECURSE_MODE::RECURSE );
2767 }
2768 else
2769 {
2770 lengthValid = false;
2771 }
2772 };
2773
2774 for( EDA_ITEM* item : selection )
2775 {
2776 if( lengthValid )
2777 accumulateTrackLength( item );
2778 }
2779
2780 if( lengthValid )
2781 {
2782 msgItems.emplace_back( _( "Selected 2D Length" ),
2783 m_frame->MessageTextFromValue( selectedLength ) );
2784 }
2785 }
2786
2787 if( selection.GetSize() >= 2 && selection.GetSize() < 100 )
2788 {
2789 LSET enabledLayers = m_frame->GetBoard()->GetEnabledLayers();
2790 LSET enabledCopper = LSET::AllCuMask( m_frame->GetBoard()->GetCopperLayerCount() );
2791 bool areaValid = true;
2792 bool hasCopper = false;
2793 bool hasNonCopper = false;
2794
2795 std::map<PCB_LAYER_ID, SHAPE_POLY_SET> layerPolys;
2796 SHAPE_POLY_SET holes;
2797
2798 std::function<void( EDA_ITEM* )> accumulateArea;
2799
2800 accumulateArea =
2801 [&]( EDA_ITEM* aItem )
2802 {
2803 if( aItem->Type() == PCB_FOOTPRINT_T || aItem->Type() == PCB_MARKER_T )
2804 {
2805 areaValid = false;
2806 return;
2807 }
2808
2809 if( PCB_GROUP* group = dynamic_cast<PCB_GROUP*>( aItem ) )
2810 {
2811 group->RunOnChildren( accumulateArea, RECURSE_MODE::RECURSE );
2812 return;
2813 }
2814
2815 if( BOARD_ITEM* boardItem = dynamic_cast<BOARD_ITEM*>( aItem ) )
2816 {
2817 boardItem->RunOnChildren( accumulateArea, RECURSE_MODE::NO_RECURSE );
2818
2819 LSET itemLayers = boardItem->GetLayerSet() & enabledLayers;
2820
2821 for( PCB_LAYER_ID layer : itemLayers )
2822 {
2823 boardItem->TransformShapeToPolySet( layerPolys[layer], layer, 0,
2825
2826 if( enabledCopper.Contains( layer ) )
2827 hasCopper = true;
2828 else
2829 hasNonCopper = true;
2830 }
2831
2832 if( aItem->Type() == PCB_PAD_T && static_cast<PAD*>( aItem )->HasHole() )
2833 {
2834 static_cast<PAD*>( aItem )->TransformHoleToPolygon( holes, 0, ARC_LOW_DEF,
2835 ERROR_OUTSIDE );
2836 }
2837 else if( aItem->Type() == PCB_VIA_T )
2838 {
2839 PCB_VIA* via = static_cast<PCB_VIA*>( aItem );
2840 VECTOR2I center = via->GetPosition();
2841 int R = via->GetDrillValue() / 2;
2842
2844 }
2845 }
2846 };
2847
2848 for( EDA_ITEM* item : selection )
2849 {
2850 if( areaValid )
2851 accumulateArea( item );
2852 }
2853
2854 if( areaValid )
2855 {
2856 double area = 0.0;
2857
2858 for( auto& [layer, layerPoly] : layerPolys )
2859 {
2860 // Only subtract holes from copper layers
2861 if( enabledCopper.Contains( layer ) )
2862 layerPoly.BooleanSubtract( holes );
2863
2864 area += layerPoly.Area();
2865 }
2866
2867 // Choose appropriate label based on what layers are involved
2868 wxString areaLabel;
2869
2870 if( hasCopper && !hasNonCopper )
2871 areaLabel = _( "Selected 2D Copper Area" );
2872 else if( !hasCopper && hasNonCopper )
2873 areaLabel = _( "Selected 2D Area" );
2874 else
2875 areaLabel = _( "Selected 2D Total Area" );
2876
2877 msgItems.emplace_back( areaLabel,
2878 m_frame->MessageTextFromValue( area, true, EDA_DATA_TYPE::AREA ) );
2879 }
2880 }
2881 }
2882 else
2883 {
2884 m_frame->GetBoard()->GetMsgPanelInfo( m_frame, msgItems );
2885 }
2886
2887 m_frame->SetMsgPanel( msgItems );
2888
2889 // Update vertex editor if it exists
2890 PCB_BASE_EDIT_FRAME* editFrame = dynamic_cast<PCB_BASE_EDIT_FRAME*>( m_frame );
2891 if( editFrame )
2892 {
2893 BOARD_ITEM* selectedItem = ( selection.GetSize() == 1 ) ? dynamic_cast<BOARD_ITEM*>( selection.Front() )
2894 : nullptr;
2895 editFrame->UpdateVertexEditorSelection( selectedItem );
2896 }
2897
2898 return 0;
2899}
2900
2901
2903{
2904 wxFileName fileName = wxFileName( *aEvent.Parameter<wxString*>() );
2905
2906 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
2907
2908 if( !editFrame )
2909 return 1;
2910
2911 wxString filePath = fileName.GetFullPath();
2913 IO_RELEASER<PCB_IO> pi( PCB_IO_MGR::FindPlugin( pluginType ) );
2914
2915 if( !pi )
2916 return 1;
2917
2918 return AppendBoard( *pi, filePath );
2919}
2920
2921
2923{
2924 BOARD_COMMIT commit( this );
2925 EDA_UNITS displayUnit = m_frame->GetUserUnits();
2926 PCB_TABLE* table = Build_Board_Characteristics_Table( m_frame->GetBoard(), displayUnit );
2927 table->SetLayer( m_frame->GetActiveLayer() );
2928
2929 std::vector<BOARD_ITEM*> items;
2930 items.push_back( table );
2931
2932 if( placeBoardItems( &commit, items, true, true, false, false ) )
2933 commit.Push( _( "Place Board Characteristics" ) );
2934 else
2935 delete table;
2936
2937 return 0;
2938}
2939
2940
2942{
2943 BOARD_COMMIT commit( this );
2944 EDA_UNITS displayUnit = m_frame->GetUserUnits();
2945
2946 PCB_TABLE* table = Build_Board_Stackup_Table( m_frame->GetBoard(), displayUnit );
2947 table->SetLayer( m_frame->GetActiveLayer() );
2948
2949 std::vector<BOARD_ITEM*> items;
2950 items.push_back( table );
2951
2952 if( placeBoardItems( &commit, items, true, true, false, false ) )
2953 commit.Push( _( "Place Board Stackup Table" ) );
2954 else
2955 delete table;
2956
2957 return 0;
2958}
2959
2960
2962{
2963 PCB_DISPLAY_OPTIONS opts = m_frame->GetDisplayOptions();
2964 opts.m_FlipBoardView = !opts.m_FlipBoardView;
2965 m_frame->SetDisplayOptions( opts );
2966
2967 return 0;
2968}
2969
2970
2972{
2973 if( aItem->Type() != PCB_SHAPE_T )
2974 return;
2975
2976 PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( aItem );
2977
2978 // Re-caching every non-hatched shape on each edit stalls commits on dense boards.
2979 if( !shape->IsHatchedFill() )
2980 return;
2981
2982 shape->UpdateHatching();
2983
2984 if( aView )
2985 aView->Update( aItem );
2986}
2987
2988
2990{
2991 KIGFX::VIEW* view = this->view();
2992
2993 for( FOOTPRINT* footprint : board()->Footprints() )
2994 footprint->RunOnChildren( std::bind( &PCB_CONTROL::rehatchBoardItem, view, _1 ), NO_RECURSE );
2995
2996 for( BOARD_ITEM* item : board()->Drawings() )
2997 rehatchBoardItem( view, item );
2998
2999 return 0;
3000}
3001
3002
3004{
3005 BOARD* brd = board();
3006
3007 if( !brd )
3008 return 0;
3009
3010 PROJECT& prj = m_frame->Prj();
3012 FILENAME_RESOLVER* resolver = cache ? cache->GetResolver() : nullptr;
3013
3014 wxString workingPath = prj.GetProjectPath();
3015 std::vector<const EMBEDDED_FILES*> stack;
3016 stack.push_back( brd->GetEmbeddedFiles() );
3017
3018 BOARD_COMMIT commit( m_frame );
3019 int embeddedCount = 0;
3020
3021 for( FOOTPRINT* fp : brd->Footprints() )
3022 {
3023 bool fpModified = false;
3024
3025 for( FP_3DMODEL& model : fp->Models() )
3026 {
3027 if( model.m_Filename.StartsWith( FILEEXT::KiCadUriPrefix ) )
3028 continue;
3029
3030 wxString fullPath =
3031 resolver ? resolver->ResolvePath( model.m_Filename, workingPath, stack )
3032 : model.m_Filename;
3033
3034 wxFileName fname( fullPath );
3035 wxString ext = fname.GetExt().Upper();
3036
3037 if( fname.Exists() )
3038 {
3040 brd->GetEmbeddedFiles()->AddFile( fname, false ) )
3041 {
3042 model.m_Filename = file->GetLink();
3043 fpModified = true;
3044 embeddedCount++;
3045
3046 // Store STEP along with WRL for the OCCT(STEP) exporter.
3047 if( ext == "WRL" || ext == "WRZ" )
3048 {
3049 wxArrayString alts;
3050
3051 // Step files
3052 alts.Add( wxT( "stp" ) );
3053 alts.Add( wxT( "step" ) );
3054 alts.Add( wxT( "STP" ) );
3055 alts.Add( wxT( "STEP" ) );
3056 alts.Add( wxT( "Stp" ) );
3057 alts.Add( wxT( "Step" ) );
3058 alts.Add( wxT( "stpz" ) );
3059 alts.Add( wxT( "stpZ" ) );
3060 alts.Add( wxT( "STPZ" ) );
3061
3062 for( const auto& alt : alts )
3063 {
3064 wxFileName altFile( fname.GetPath(),
3065 fname.GetName() + wxT( "." ) + alt );
3066
3067 if( altFile.IsOk() && altFile.FileExists() )
3068 {
3069 brd->GetEmbeddedFiles()->AddFile( altFile, false );
3070 break;
3071 }
3072 }
3073 }
3074 }
3075 }
3076 }
3077
3078 if( fpModified )
3079 commit.Modify( fp );
3080 }
3081
3082 if( embeddedCount > 0 )
3083 {
3084 commit.Push( _( "Embed 3D Models" ) );
3085 wxString msg = wxString::Format( _( "%d 3D model(s) successfully embedded." ), embeddedCount );
3086 m_frame->GetInfoBar()->ShowMessageFor( msg, 5000 );
3087 }
3088
3089 return 0;
3090}
3091
3092
3093// clang-format off
3095{
3098 Go( &PCB_CONTROL::Print, ACTIONS::print.MakeEvent() );
3099
3100 // Footprint library actions
3105
3106 // Display modes
3123
3124 // Layer control
3162
3165
3166 // Grid control
3169
3170 Go( &PCB_CONTROL::Undo, ACTIONS::undo.MakeEvent() );
3171 Go( &PCB_CONTROL::Redo, ACTIONS::redo.MakeEvent() );
3172
3173 // Snapping control
3178
3179 // Miscellaneous
3182
3183 // Append control
3192
3193 Go( &PCB_CONTROL::Paste, ACTIONS::paste.MakeEvent() );
3195
3202
3203 // Add library by dropping file
3206}
3207// clang-format on
const char * name
@ ERROR_OUTSIDE
@ ERROR_INSIDE
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:357
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:918
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:986
static TOOL_ACTION paste
Definition actions.h:76
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:81
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition board_item.h:265
virtual bool IsConnected() const
Returns information if the object is derived from BOARD_CONNECTED_ITEM.
Definition board_item.h:155
virtual bool IsOnLayer(PCB_LAYER_ID aLayer) const
Test to see if this object is on the given layer.
Definition board_item.h:347
virtual std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING aFlash=FLASHING::DEFAULT) const
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
FOOTPRINT * GetParentFootprint() const
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition board_item.h:285
void ResetUuid()
Definition board_item.h:245
virtual bool IsOnCopperLayer() const
Definition board_item.h:172
virtual std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape() const
virtual bool HasHole() const
Definition board_item.h:177
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:373
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:2557
EMBEDDED_FILES * GetEmbeddedFiles() override
Definition board.cpp:3464
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:1066
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:3568
void BuildListOfNets()
Definition board.h:1057
const std::vector< BOARD_CONNECTED_ITEM * > AllConnectedItems()
Definition board.cpp:3533
const PAGE_INFO & GetPageSettings() const
Definition board.h:897
void SetProperties(const std::map< wxString, wxString > &aProps)
Definition board.h:466
const GROUPS & Groups() const
The groups must maintain the following invariants.
Definition board.h:461
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:201
void SynchronizeNetsAndNetClasses(bool aResetTrackAndViaSizes)
Copy NETCLASS info to each NET, based on NET membership in a NETCLASS.
Definition board.cpp:3055
FOOTPRINT * GetFirstFootprint() const
Get the first footprint on the board or nullptr.
Definition board.h:595
TITLE_BLOCK & GetTitleBlock()
Definition board.h:903
int GetCopperLayerCount() const
Definition board.cpp:985
const std::map< wxString, wxString > & GetProperties() const
Definition board.h:465
const FOOTPRINTS & Footprints() const
Definition board.h:421
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:1589
const BOARD_ITEM_SET GetItemSet()
Collect every owned item (tracks, zones, generators, footprints, drawings, markers,...
Definition board.cpp:3945
void SetPageSettings(const PAGE_INFO &aPageSettings)
Definition board.h:898
void SetCopperLayerCount(int aCount)
Definition board.cpp:991
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:1040
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition board.cpp:1149
const LSET & GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition board.cpp:1034
void Remove(BOARD_ITEM *aBoardItem, REMOVE_MODE aMode=REMOVE_MODE::NORMAL) override
Removes an item from the container.
Definition board.cpp:1493
void SetEnabledLayers(const LSET &aLayerMask)
A proxy function that calls the correspondent function in m_BoardSettings.
Definition board.cpp:1054
void SetTitleBlock(const TITLE_BLOCK &aTitleBlock)
Definition board.h:905
const DRAWINGS & Drawings() const
Definition board.h:423
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:232
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)
Load design block from design block library table.
const LIB_ID & GetLibId() const
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.
int ShowModal() override
wxString GetName() const
Definition drc_rule.h:204
MINOPTMAX< int > & Value()
Definition drc_rule.h:197
MINOPTMAX< int > m_Value
Definition drc_rule.h:240
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:42
bool HasDesignBlockLink() const
Definition eda_group.h:71
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:96
virtual void SetPosition(const VECTOR2I &aPos)
Definition eda_item.h:283
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition eda_item.h:152
virtual wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const
Return a user-visible description string of this item.
Definition eda_item.cpp:169
const KIID m_Uuid
Definition eda_item.h:531
virtual EDA_GROUP * GetParentGroup() const
Definition eda_item.h:114
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:108
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition eda_item.h:154
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:230
bool HasFlag(EDA_ITEM_FLAGS aFlag) const
Definition eda_item.h:156
virtual void SetParent(EDA_ITEM *aParent)
Definition eda_item.cpp:89
SHAPE_T GetShape() const
Definition eda_shape.h:185
bool IsHatchedFill() const
Definition eda_shape.h:140
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:52
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:343
static const TOOL_EVENT SelectedEvent
Definition actions.h:341
static const TOOL_EVENT SelectedItemsModified
Selected items were moved, this can be very high frequency on the canvas, use with care.
Definition actions.h:348
static const TOOL_EVENT PointSelectedEvent
Definition actions.h:340
static const TOOL_EVENT ContrastModeChangedByKeyEvent
Definition actions.h:362
static const TOOL_EVENT ConnectivityChangedEvent
Selected item had a property changed (except movement)
Definition actions.h:345
static const TOOL_EVENT UnselectedEvent
Definition actions.h:342
Provide an extensible class to resolve 3D model paths.
Component library viewer main window.
EDA_ANGLE GetOrientation() const
Definition footprint.h:406
ZONES & Zones()
Definition footprint.h:381
std::deque< PAD * > & Pads()
Definition footprint.h:375
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:1354
void SetReference(const wxString &aReference)
Definition footprint.h:847
bool IsLocked() const override
Definition footprint.h:634
void ClearTransientComponentClassNames()
Remove the transient component class names.
Definition footprint.h:1360
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:384
void GetFields(std::vector< PCB_FIELD * > &aVector, bool aVisibleOnly) const
Populate a std::vector with PCB_TEXTs.
DRAWINGS & GraphicalItems()
Definition footprint.h:378
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:65
static const std::vector< KICAD_T > AllBoardItems
A scan list for all editable board items.
Definition collectors.h:37
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:103
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:392
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:300
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition view.cpp:404
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:1835
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:677
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
wxString GetUniStringLibId() const
Definition lib_id.h:144
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
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:34
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:46
static const int UNCONNECTED
Constant that holds the "unconnected net" number (typically 0) all items "connected" to this net are ...
Definition netinfo.h:256
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:264
static constexpr PCB_LAYER_ID ALL_LAYERS
! Temporary layer identifier to identify code that is not padstack-aware
Definition padstack.h:177
Definition pad.h:61
static wxString ShowPadShape(PAD_SHAPE aShape)
Definition pad.cpp:2500
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 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 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.
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 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)
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 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.
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:49
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:75
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:105
virtual BOARD * LoadBoard(const wxString &aFileName, BOARD *aAppendToMe, const std::map< std::string, UTF8 > *aProperties=nullptr, PROJECT *aProject=nullptr)
Load information from some input file format that this PCB_IO implementation knows about into either ...
Definition pcb_io.cpp:70
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.
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
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:553
void SetMotionHandler(MOTION_HANDLER aHandler)
Set a handler for mouse motion.
Definition picker_tool.h:88
void SetClickHandler(CLICK_HANDLER aHandler)
Set a handler for mouse click event.
Definition picker_tool.h:77
void SetSnapping(bool aSnap)
Definition picker_tool.h:62
void SetCursor(KICURSOR aCursor)
Definition picker_tool.h:60
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:62
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:541
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)
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:37
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:77
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 AddButton(wxButton *aButton)
Add an already created button 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:832
void AddPolygon(std::vector< VECTOR2I > &aPolygon)
Add a polygon to the zone outline.
Definition zone.cpp:1393
void SetPlacementAreaSource(const wxString &aSource)
Definition zone.h:819
void SetPlacementAreaSourceType(PLACEMENT_SOURCE_T aType)
Definition zone.h:821
SHAPE_POLY_SET * Outline()
Definition zone.h:418
void SetHatchStyle(ZONE_BORDER_DISPLAY_STYLE aStyle)
Definition zone.h:686
void SetIsRuleArea(bool aEnable)
Definition zone.h:814
void SetDoNotAllowTracks(bool aEnable)
Definition zone.h:831
const wxString & GetZoneName() const
Definition zone.h:160
void SetLayerSet(const LSET &aLayerSet) override
Definition zone.cpp:644
void SetDoNotAllowVias(bool aEnable)
Definition zone.h:830
void SetDoNotAllowFootprints(bool aEnable)
Definition zone.h:833
void SetDoNotAllowZoneFills(bool aEnable)
Definition zone.h:829
void SetZoneName(const wxString &aName)
Definition zone.h:161
void SetPlacementAreaEnabled(bool aEnabled)
Definition zone.h:816
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
#define _(s)
Declaration of the eda_3d_viewer class.
@ RECURSE
Definition eda_item.h:49
@ NO_RECURSE
Definition eda_item.h:50
#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:46
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:852
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition layer_ids.h:675
@ 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:366
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:766
constexpr char APPEND_PRESERVE_DESTINATION_STACKUP[]
Definition pcb_io.h:43
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
#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
std::vector< std::vector< std::string > > table
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:256
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition typeinfo.h:71
@ PCB_T
Definition typeinfo.h:75
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition typeinfo.h:81
@ PCB_DIM_ORTHOGONAL_T
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
Definition typeinfo.h:99
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition typeinfo.h:96
@ PCB_GENERATOR_T
class PCB_GENERATOR, generator on a layer
Definition typeinfo.h:84
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:90
@ PCB_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
Definition typeinfo.h:97
@ PCB_GROUP_T
class PCB_GROUP, a set of BOARD_ITEMs
Definition typeinfo.h:104
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
Definition typeinfo.h:86
@ PCB_ZONE_T
class ZONE, a copper pour area
Definition typeinfo.h:101
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition typeinfo.h:85
@ NOT_USED
the 3d code uses this value
Definition typeinfo.h:72
@ PCB_MARKER_T
class PCB_MARKER, a marker used to show something
Definition typeinfo.h:92
@ PCB_BARCODE_T
class PCB_BARCODE, a barcode (graphic item)
Definition typeinfo.h:94
@ PCB_TABLECELL_T
class PCB_TABLECELL, PCB_TEXTBOX for use in tables
Definition typeinfo.h:88
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
Definition typeinfo.h:79
@ PCB_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
Definition typeinfo.h:95
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition typeinfo.h:80
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition typeinfo.h:91
@ PCB_DIMENSION_T
class PCB_DIMENSION_BASE: abstract dimension meta-type
Definition typeinfo.h:93
@ PCB_TABLE_T
class PCB_TABLE, table of PCB_TABLECELLs
Definition typeinfo.h:87
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition typeinfo.h:89
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
Definition typeinfo.h:98
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