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 <layer_pairs.h>
54#include <pcb_group.h>
56#include <pcb_reference_image.h>
57#include <pcb_textbox.h>
58#include <pcb_table.h>
59#include <pcb_tablecell.h>
60#include <pcb_track.h>
61#include <pcb_generator.h>
63#include <project_pcb.h>
65#include <filename_resolver.h>
66#include <3d_cache/3d_cache.h>
67#include <embedded_files.h>
68#include <wx/filename.h>
69#include <zone.h>
70#include <confirm.h>
71#include <kidialog.h>
73#include <core/kicad_algo.h>
77#include <kicad_clipboard.h>
78#include <origin_viewitem.h>
79#include <pcb_edit_frame.h>
80#include <pcb_painter.h>
82#include <string>
83#include <tool/tool_manager.h>
91#include <widgets/wx_infobar.h>
92#include <pcb_io/pcb_io.h>
93#include <wx/hyperlink.h>
94
95
96using namespace std::placeholders;
97
98
99// files.cpp
100extern bool AskLoadBoardFileName( PCB_EDIT_FRAME* aParent, wxString* aFileName, int aCtl = 0 );
101
102// board_tables/board_stackup_table.cpp
103extern PCB_TABLE* Build_Board_Stackup_Table( BOARD* aBoard, EDA_UNITS aDisplayUnits );
104// board_tables/board_characteristics_table.cpp
105extern PCB_TABLE* Build_Board_Characteristics_Table( BOARD* aBoard, EDA_UNITS aDisplayUnits );
106
107
109 PCB_TOOL_BASE( "pcbnew.Control" ),
110 m_frame( nullptr ),
111 m_pickerItem( nullptr )
112{
114}
115
116
120
121
123{
125
126 if( aReason == MODEL_RELOAD || aReason == GAL_SWITCH || aReason == REDRAW )
127 {
128 m_gridOrigin->SetPosition( board()->GetDesignSettings().GetGridOrigin() );
129
130 double backgroundBrightness = m_frame->GetCanvas()->GetGAL()->GetClearColor().GetBrightness();
131 COLOR4D color = m_frame->GetGridColor();
132
133 if( backgroundBrightness > 0.5 )
134 color.Darken( 0.25 );
135 else
136 color.Brighten( 0.25 );
137
138 m_gridOrigin->SetColor( color );
139
140 getView()->Remove( m_gridOrigin.get() );
141 getView()->Add( m_gridOrigin.get() );
142 }
143}
144
145
147{
148 if( m_frame->IsType( FRAME_FOOTPRINT_EDITOR ) || m_frame->IsType( FRAME_PCB_EDITOR ) )
149 {
150 if( aEvent.IsAction( &ACTIONS::newLibrary ) )
151 static_cast<PCB_BASE_EDIT_FRAME*>( m_frame )->CreateNewLibrary( _( "New Footprint Library" ) );
152 else if( aEvent.IsAction( &ACTIONS::addLibrary ) )
153 static_cast<PCB_BASE_EDIT_FRAME*>( m_frame )->AddLibrary( _( "Add Footprint Library" ) );
154 }
155
156 return 0;
157}
158
159
161{
162 if( m_frame->IsType( FRAME_FOOTPRINT_EDITOR ) )
163 static_cast<FOOTPRINT_EDIT_FRAME*>( m_frame )->LoadFootprintFromBoard( nullptr );
164
165 return 0;
166}
167
168
170{
171 if( m_frame->IsType( FRAME_FOOTPRINT_EDITOR ) )
172 static_cast<FOOTPRINT_EDIT_FRAME*>( m_frame )->SaveFootprintToBoard( true );
173 else if( m_frame->IsType( FRAME_FOOTPRINT_VIEWER ) )
174 static_cast<FOOTPRINT_VIEWER_FRAME*>( m_frame )->AddFootprintToPCB();
175
176 return 0;
177}
178
179
181{
182 const wxString fn = *aEvent.Parameter<wxString*>();
183 static_cast<PCB_BASE_EDIT_FRAME*>( m_frame )->AddLibrary( _( "Add Footprint Library" ), fn,
185 return 0;
186}
187
188
190{
191 const wxString fn = *aEvent.Parameter<wxString*>();
192 static_cast<FOOTPRINT_EDIT_FRAME*>( m_frame )->ImportFootprint( fn );
193 m_frame->Zoom_Automatique( false );
194 return 0;
195}
196
197
199{
200 if( m_frame->IsType( FRAME_FOOTPRINT_VIEWER ) )
201 static_cast<FOOTPRINT_VIEWER_FRAME*>( m_frame )->SelectAndViewFootprint( aEvent.Parameter<FPVIEWER_CONSTANTS>() );
202
203 return 0;
204}
205
206
207template<class T>
208void Flip( T& aValue )
209{
210 aValue = !aValue;
211}
212
213
215{
216 Flip( displayOptions().m_DisplayPcbTrackFill );
217
218 for( PCB_TRACK* track : board()->Tracks() )
219 {
220 if( track->Type() == PCB_TRACE_T || track->Type() == PCB_ARC_T )
221 view()->Update( track, KIGFX::REPAINT );
222 }
223
224 for( BOARD_ITEM* shape : board()->Drawings() )
225 {
226 if( shape->Type() == PCB_SHAPE_T && static_cast<PCB_SHAPE*>( shape )->IsOnCopperLayer() )
227 view()->Update( shape, KIGFX::REPAINT );
228 }
229
230 canvas()->Refresh();
231
232 return 0;
233}
234
235
237{
238 if( PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame ) )
239 {
240 if( aEvent.IsAction( &PCB_ACTIONS::showRatsnest ) )
241 {
242 // N.B. Do not disable the Ratsnest layer here. We use it for local ratsnest
243 Flip( displayOptions().m_ShowGlobalRatsnest );
244 editFrame->SetElementVisibility( LAYER_RATSNEST, displayOptions().m_ShowGlobalRatsnest );
245 }
246 else if( aEvent.IsAction( &PCB_ACTIONS::ratsnestLineMode ) )
247 {
248 Flip( displayOptions().m_DisplayRatsnestLinesCurved );
249 }
250
251 editFrame->OnDisplayOptionsChanged();
252
254 canvas()->Refresh();
255 }
256
257 return 0;
258}
259
260
262{
263 Flip( displayOptions().m_DisplayViaFill );
264
265 for( PCB_TRACK* track : board()->Tracks() )
266 {
267 if( track->Type() == PCB_VIA_T )
268 view()->Update( track, KIGFX::REPAINT );
269 }
270
271 canvas()->Refresh();
272 return 0;
273}
274
275
282{
283 if( Pgm().GetCommonSettings()->m_DoNotShowAgain.zone_fill_warning )
284 return;
285
286 bool unfilledZones = false;
287
288 for( const ZONE* zone : board()->Zones() )
289 {
290 if( !zone->GetIsRuleArea() && !zone->IsFilled() )
291 {
292 unfilledZones = true;
293 break;
294 }
295 }
296
297 if( unfilledZones )
298 {
299 WX_INFOBAR* infobar = m_frame->GetInfoBar();
300 wxHyperlinkCtrl* button = new wxHyperlinkCtrl( infobar, wxID_ANY, _( "Don't show again" ), wxEmptyString );
301
302 button->Bind( wxEVT_COMMAND_HYPERLINK, std::function<void( wxHyperlinkEvent& aEvent )>(
303 [&]( wxHyperlinkEvent& aEvent )
304 {
306 m_frame->GetInfoBar()->Dismiss();
307 } ) );
308
309 infobar->RemoveAllButtons();
310 infobar->AddButton( button );
311
312 wxString msg;
313 msg.Printf( _( "Not all zones are filled. Use Edit > Fill All Zones (%s) "
314 "if you wish to see all fills." ),
316
317 infobar->ShowMessageFor( msg, 5000, wxICON_WARNING );
318 }
319}
320
321
323{
324 PCB_DISPLAY_OPTIONS opts = m_frame->GetDisplayOptions();
325
326 // Apply new display options to the GAL canvas
328 {
330
332 }
333 else if( aEvent.IsAction( &PCB_ACTIONS::zoneDisplayOutline ) )
334 {
336 }
337 else if( aEvent.IsAction( &PCB_ACTIONS::zoneDisplayFractured ) )
338 {
340 }
342 {
344 }
345 else if( aEvent.IsAction( &PCB_ACTIONS::zoneDisplayToggle ) )
346 {
349 else
351 }
352 else
353 {
354 wxFAIL;
355 }
356
357 m_frame->SetDisplayOptions( opts );
358
359 for( ZONE* zone : board()->Zones() )
360 view()->Update( zone, KIGFX::REPAINT );
361
362 canvas()->Refresh();
363
364 return 0;
365}
366
367
369{
370 PCB_DISPLAY_OPTIONS opts = m_frame->GetDisplayOptions();
371
374
375 m_frame->SetDisplayOptions( opts );
376 return 0;
377}
378
379
381{
382 PCB_DISPLAY_OPTIONS opts = m_frame->GetDisplayOptions();
383
384 switch( opts.m_ContrastModeDisplay )
385 {
389 }
390
391 m_frame->SetDisplayOptions( opts );
392
394 return 0;
395}
396
397
399{
400 if( !Pgm().GetCommonSettings()->m_Input.hotkey_feedback )
401 return 0;
402
403 PCB_DISPLAY_OPTIONS opts = m_frame->GetDisplayOptions();
404
405 wxArrayString labels;
406 labels.Add( _( "Normal" ) );
407 labels.Add( _( "Dimmed" ) );
408 labels.Add( _( "Hidden" ) );
409
410 if( !m_frame->GetHotkeyPopup() )
411 m_frame->CreateHotkeyPopup();
412
413 HOTKEY_CYCLE_POPUP* popup = m_frame->GetHotkeyPopup();
414
415 if( popup )
416 {
417 popup->Popup( _( "Inactive Layer Display" ), labels, static_cast<int>( opts.m_ContrastModeDisplay ) );
418 }
419
420 return 0;
421}
422
423
425{
426 PCB_DISPLAY_OPTIONS opts = m_frame->GetDisplayOptions();
427
428 switch( opts.m_NetColorMode )
429 {
433 }
434
435 m_frame->SetDisplayOptions( opts );
436 return 0;
437}
438
439
441{
442 if( PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame ) )
443 {
444 if( !displayOptions().m_ShowGlobalRatsnest )
445 {
448 }
449 else if( displayOptions().m_RatsnestMode == RATSNEST_MODE::ALL )
450 {
452 }
453 else
454 {
456 }
457
458 editFrame->SetElementVisibility( LAYER_RATSNEST, displayOptions().m_ShowGlobalRatsnest );
459
460 editFrame->OnDisplayOptionsChanged();
461
463 canvas()->Refresh();
464 }
465
466 return 0;
467}
468
469
471{
472 m_frame->SwitchLayer( aEvent.Parameter<PCB_LAYER_ID>() );
473
474 return 0;
475}
476
477
479{
480 BOARD* brd = board();
481 PCB_LAYER_ID layer = m_frame->GetActiveLayer();
482 bool wraparound = false;
483
484 if( !IsCopperLayer( layer ) )
485 {
486 m_frame->SwitchLayer( B_Cu );
487 return 0;
488 }
489
490 LSET cuMask = LSET::AllCuMask( brd->GetCopperLayerCount() );
491 LSEQ layerStack = cuMask.UIOrder();
492
493 int ii = 0;
494
495 // Find the active layer in list
496 for( ; ii < (int) layerStack.size(); ii++ )
497 {
498 if( layer == layerStack[ii] )
499 break;
500 }
501
502 // Find the next visible layer in list
503 for( ; ii < (int) layerStack.size(); ii++ )
504 {
505 int jj = ii + 1;
506
507 if( jj >= (int) layerStack.size() )
508 jj = 0;
509
510 layer = layerStack[jj];
511
512 if( brd->IsLayerVisible( layer ) )
513 break;
514
515 if( jj == 0 ) // the end of list is reached. Try from the beginning
516 {
517 if( wraparound )
518 {
519 wxBell();
520 return 0;
521 }
522 else
523 {
524 wraparound = true;
525 ii = -1;
526 }
527 }
528 }
529
530 wxCHECK( IsCopperLayer( layer ), 0 );
531 m_frame->SwitchLayer( layer );
532
533 return 0;
534}
535
536
538{
539 BOARD* brd = board();
540 PCB_LAYER_ID layer = m_frame->GetActiveLayer();
541 bool wraparound = false;
542
543 if( !IsCopperLayer( layer ) )
544 {
545 m_frame->SwitchLayer( F_Cu );
546 return 0;
547 }
548
549 LSET cuMask = LSET::AllCuMask( brd->GetCopperLayerCount() );
550 LSEQ layerStack = cuMask.UIOrder();
551
552 int ii = 0;
553
554 // Find the active layer in list
555 for( ; ii < (int) layerStack.size(); ii++ )
556 {
557 if( layer == layerStack[ii] )
558 break;
559 }
560
561 // Find the previous visible layer in list
562 for( ; ii >= 0; ii-- )
563 {
564 int jj = ii - 1;
565
566 if( jj < 0 )
567 jj = (int) layerStack.size() - 1;
568
569 layer = layerStack[jj];
570
571 if( brd->IsLayerVisible( layer ) )
572 break;
573
574 if( ii == 0 ) // the start of list is reached. Try from the last
575 {
576 if( wraparound )
577 {
578 wxBell();
579 return 0;
580 }
581 else
582 {
583 wraparound = true;
584 ii = 1;
585 }
586 }
587 }
588
589 wxCHECK( IsCopperLayer( layer ), 0 );
590 m_frame->SwitchLayer( layer );
591
592 return 0;
593}
594
595
597{
598 int currentLayer = m_frame->GetActiveLayer();
599 PCB_SCREEN* screen = m_frame->GetScreen();
600
601 if( currentLayer == screen->m_Route_Layer_TOP )
602 m_frame->SwitchLayer( screen->m_Route_Layer_BOTTOM );
603 else
604 m_frame->SwitchLayer( screen->m_Route_Layer_TOP );
605
606 return 0;
607}
608
609
610// It'd be nice to share the min/max with the DIALOG_COLOR_PICKER, but those are
611// set in wxFormBuilder.
612#define ALPHA_MIN 0.20
613#define ALPHA_MAX 1.00
614#define ALPHA_STEP 0.05
615
616
618{
619 COLOR_SETTINGS* settings = m_frame->GetColorSettings();
620 int currentLayer = m_frame->GetActiveLayer();
621 KIGFX::COLOR4D currentColor = settings->GetColor( currentLayer );
622
623 if( currentColor.a <= ALPHA_MAX - ALPHA_STEP )
624 {
625 currentColor.a += ALPHA_STEP;
626 settings->SetColor( currentLayer, currentColor );
627 m_frame->GetCanvas()->UpdateColors();
628
629 KIGFX::VIEW* view = m_frame->GetCanvas()->GetView();
630 view->UpdateLayerColor( currentLayer );
631 view->UpdateLayerColor( GetNetnameLayer( currentLayer ) );
632
633 if( IsCopperLayer( currentLayer ) )
634 view->UpdateLayerColor( ZONE_LAYER_FOR( currentLayer ) );
635
636 m_frame->GetCanvas()->ForceRefresh();
637 }
638 else
639 {
640 wxBell();
641 }
642
643 return 0;
644}
645
646
648{
649 COLOR_SETTINGS* settings = m_frame->GetColorSettings();
650 int currentLayer = m_frame->GetActiveLayer();
651 KIGFX::COLOR4D currentColor = settings->GetColor( currentLayer );
652
653 if( currentColor.a >= ALPHA_MIN + ALPHA_STEP )
654 {
655 currentColor.a -= ALPHA_STEP;
656 settings->SetColor( currentLayer, currentColor );
657 m_frame->GetCanvas()->UpdateColors();
658
659 KIGFX::VIEW* view = m_frame->GetCanvas()->GetView();
660 view->UpdateLayerColor( currentLayer );
661 view->UpdateLayerColor( GetNetnameLayer( currentLayer ) );
662
663 if( IsCopperLayer( currentLayer ) )
664 view->UpdateLayerColor( ZONE_LAYER_FOR( currentLayer ) );
665
666 m_frame->GetCanvas()->ForceRefresh();
667 }
668 else
669 {
670 wxBell();
671 }
672
673 return 0;
674}
675
676
678{
679 if( PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame ) )
680 {
681 LAYER_PAIR_SETTINGS* settings = editFrame->GetLayerPairSettings();
682
683 if( !settings )
684 return 0;
685
686 int currentIndex;
687 std::vector<LAYER_PAIR_INFO> presets = settings->GetEnabledLayerPairs( currentIndex );
688
689 if( presets.size() < 2 )
690 return 0;
691
692 if( currentIndex < 0 )
693 {
694 wxASSERT_MSG( false, "Current layer pair not found in layer settings" );
695 currentIndex = 0;
696 }
697
698 const int nextIndex = ( currentIndex + 1 ) % presets.size();
699 const LAYER_PAIR& nextPair = presets[nextIndex].GetLayerPair();
700
701 settings->SetCurrentLayerPair( nextPair );
702
704 }
705
706 return 0;
707}
708
709
711{
712 if( !Pgm().GetCommonSettings()->m_Input.hotkey_feedback )
713 return 0;
714
715 if( PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame ) )
716 {
717 LAYER_PAIR_SETTINGS* settings = editFrame->GetLayerPairSettings();
718
719 if( !settings )
720 return 0;
721
722 PCB_LAYER_PRESENTATION layerPresentation( editFrame );
723
724 int currentIndex;
725 std::vector<LAYER_PAIR_INFO> presets = settings->GetEnabledLayerPairs( currentIndex );
726
727 wxArrayString labels;
728 for( const LAYER_PAIR_INFO& layerPairInfo : presets )
729 {
730 wxString label = layerPresentation.getLayerPairName( layerPairInfo.GetLayerPair() );
731
732 if( layerPairInfo.GetName() )
733 label += wxT( " (" ) + *layerPairInfo.GetName() + wxT( ")" );
734
735 labels.Add( label );
736 }
737
738 if( !editFrame->GetHotkeyPopup() )
739 editFrame->CreateHotkeyPopup();
740
741 HOTKEY_CYCLE_POPUP* popup = editFrame->GetHotkeyPopup();
742
743 if( popup )
744 {
745 int selection = currentIndex;
746 popup->Popup( _( "Preset Layer Pairs" ), labels, selection );
747 }
748 }
749
750 return 0;
751}
752
753
755 const VECTOR2D& aPoint )
756{
757 aFrame->GetDesignSettings().SetGridOrigin( VECTOR2I( aPoint ) );
758 aView->GetGAL()->SetGridOrigin( aPoint );
759 originViewItem->SetPosition( aPoint );
760 aView->MarkDirty();
761 aFrame->OnModify();
762}
763
764
766{
767 VECTOR2D* origin = aEvent.Parameter<VECTOR2D*>();
768
769 if( origin )
770 {
771 // We can't undo the other grid dialog settings, so no sense undoing just the origin
772 DoSetGridOrigin( getView(), m_frame, m_gridOrigin.get(), *origin );
773 delete origin;
774 }
775 else
776 {
778 return 0;
779
780 PCB_PICKER_TOOL* picker = m_toolMgr->GetTool<PCB_PICKER_TOOL>();
781
782 if( !picker ) // Happens in footprint wizard
783 return 0;
784
785 // Deactivate other tools; particularly important if another PICKER is currently running
786 Activate();
787
788 picker->SetCursor( KICURSOR::PLACE );
789 picker->ClearHandlers();
790
791 picker->SetClickHandler(
792 [this]( const VECTOR2D& pt ) -> bool
793 {
794 m_frame->SaveCopyInUndoList( m_gridOrigin.get(), UNDO_REDO::GRIDORIGIN );
796 return false; // drill origin is a one-shot; don't continue with tool
797 } );
798
799 m_toolMgr->RunAction( ACTIONS::pickerTool, &aEvent );
800 }
801
802 return 0;
803}
804
805
807{
808 m_frame->SaveCopyInUndoList( m_gridOrigin.get(), UNDO_REDO::GRIDORIGIN );
810 return 0;
811}
812
813
814#define HITTEST_THRESHOLD_PIXELS 5
815
816
818{
819 if( m_isFootprintEditor && !m_frame->GetBoard()->GetFirstFootprint() )
820 return 0;
821
822 PCB_PICKER_TOOL* picker = m_toolMgr->GetTool<PCB_PICKER_TOOL>();
823
824 m_pickerItem = nullptr;
826
827 // Deactivate other tools; particularly important if another PICKER is currently running
828 Activate();
829
830 picker->SetCursor( KICURSOR::REMOVE );
831 picker->SetSnapping( false );
832 picker->ClearHandlers();
833
834 picker->SetClickHandler(
835 [this]( const VECTOR2D& aPosition ) -> bool
836 {
837 if( m_pickerItem )
838 {
839 if( m_pickerItem && m_pickerItem->IsLocked() )
840 {
842 m_statusPopup->SetText( _( "Item locked." ) );
843 m_statusPopup->PopupFor( 2000 );
844 m_statusPopup->Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, 20 ) );
845 return true;
846 }
847
848 PCB_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
849 selectionTool->UnbrightenItem( m_pickerItem );
850
851 PCB_SELECTION items;
852 items.Add( m_pickerItem );
853
854 EDIT_TOOL* editTool = m_toolMgr->GetTool<EDIT_TOOL>();
855 editTool->DeleteItems( items, false );
856
857 m_pickerItem = nullptr;
858 }
859
860 return true;
861 } );
862
863 picker->SetMotionHandler(
864 [this]( const VECTOR2D& aPos )
865 {
866 BOARD* board = m_frame->GetBoard();
867 PCB_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
868 GENERAL_COLLECTORS_GUIDE guide = m_frame->GetCollectorsGuide();
869 GENERAL_COLLECTOR collector;
870 collector.m_Threshold = KiROUND( getView()->ToWorld( HITTEST_THRESHOLD_PIXELS ) );
871
873 collector.Collect( board, GENERAL_COLLECTOR::FootprintItems, aPos, guide );
874 else
875 collector.Collect( board, GENERAL_COLLECTOR::BoardLevelItems, aPos, guide );
876
877 // Remove unselectable items
878 for( int i = collector.GetCount() - 1; i >= 0; --i )
879 {
880 if( !selectionTool->Selectable( collector[i] ) )
881 collector.Remove( i );
882 }
883
884 selectionTool->FilterCollectorForHierarchy( collector, false );
885 selectionTool->FilterCollectedItems( collector, false, nullptr );
886
887 if( collector.GetCount() > 1 )
888 selectionTool->GuessSelectionCandidates( collector, aPos );
889
890 BOARD_ITEM* item = collector.GetCount() == 1 ? collector[0] : nullptr;
891
892 if( m_pickerItem != item )
893 {
894 if( m_pickerItem )
895 selectionTool->UnbrightenItem( m_pickerItem );
896
897 m_pickerItem = item;
898
899 if( m_pickerItem )
900 selectionTool->BrightenItem( m_pickerItem );
901 }
902 } );
903
904 picker->SetFinalizeHandler(
905 [this]( const int& aFinalState )
906 {
907 if( m_pickerItem )
908 m_toolMgr->GetTool<PCB_SELECTION_TOOL>()->UnbrightenItem( m_pickerItem );
909
910 m_statusPopup.reset();
911
912 // Ensure the cursor gets changed&updated
913 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
914 m_frame->GetCanvas()->Refresh();
915 } );
916
917 m_toolMgr->RunAction( ACTIONS::pickerTool, &aEvent );
918
919 return 0;
920}
921
922
923static void pasteFootprintItemsToFootprintEditor( FOOTPRINT* aClipFootprint, BOARD* aBoard,
924 std::vector<BOARD_ITEM*>& aPastedItems )
925{
926 FOOTPRINT* editorFootprint = aBoard->GetFirstFootprint();
927
928 aClipFootprint->SetParent( aBoard );
929
930 for( PAD* pad : aClipFootprint->Pads() )
931 {
932 pad->SetParent( editorFootprint );
933 aPastedItems.push_back( pad );
934 }
935
936 aClipFootprint->Pads().clear();
937
938 // Not all items can be added to the current footprint: mandatory fields are already existing
939 // in the current footprint.
940 //
941 for( PCB_FIELD* field : aClipFootprint->GetFields() )
942 {
943 wxCHECK2( field, continue );
944
945 if( field->IsMandatory() )
946 {
947 if( EDA_GROUP* parentGroup = field->GetParentGroup() )
948 parentGroup->RemoveItem( field );
949 }
950 else
951 {
952 PCB_TEXT* text = static_cast<PCB_TEXT*>( field );
953
954 text->SetTextAngle( text->GetTextAngle() - aClipFootprint->GetOrientation() );
955 text->SetTextAngle( text->GetTextAngle() + editorFootprint->GetOrientation() );
956
957 VECTOR2I pos = field->GetFPRelativePosition();
958 field->SetParent( editorFootprint );
959 field->SetFPRelativePosition( pos );
960
961 aPastedItems.push_back( field );
962 }
963 }
964
965 aClipFootprint->GetFields().clear();
966
967 for( BOARD_ITEM* item : aClipFootprint->GraphicalItems() )
968 {
969 if( item->Type() == PCB_TEXT_T )
970 {
971 PCB_TEXT* text = static_cast<PCB_TEXT*>( item );
972
973 text->SetTextAngle( text->GetTextAngle() - aClipFootprint->GetOrientation() );
974 text->SetTextAngle( text->GetTextAngle() + editorFootprint->GetOrientation() );
975 }
976
977 item->Rotate( item->GetPosition(), -aClipFootprint->GetOrientation() );
978 item->Rotate( item->GetPosition(), editorFootprint->GetOrientation() );
979
980 VECTOR2I pos = item->GetFPRelativePosition();
981 item->SetParent( editorFootprint );
982 item->SetFPRelativePosition( pos );
983
984 aPastedItems.push_back( item );
985 }
986
987 aClipFootprint->GraphicalItems().clear();
988
989 for( ZONE* zone : aClipFootprint->Zones() )
990 {
991 zone->SetParent( editorFootprint );
992 aPastedItems.push_back( zone );
993 }
994
995 aClipFootprint->Zones().clear();
996
997 for( PCB_GROUP* group : aClipFootprint->Groups() )
998 {
999 group->SetParent( editorFootprint );
1000 aPastedItems.push_back( group );
1001 }
1002
1003 aClipFootprint->Groups().clear();
1004}
1005
1006
1007void PCB_CONTROL::pruneItemLayers( std::vector<BOARD_ITEM*>& aItems )
1008{
1009 // Do not prune items or layers when copying to the FP editor, because all
1010 // layers are accepted, even if they are not enabled in the dummy board
1011 // This is mainly true for internal copper layers: all are allowed but only one
1012 // (In1.cu) is enabled for the GUI.
1014 return;
1015
1016 LSET enabledLayers = board()->GetEnabledLayers();
1017 std::vector<BOARD_ITEM*> returnItems;
1018 bool fpItemDeleted = false;
1019
1020 for( BOARD_ITEM* item : aItems )
1021 {
1022 if( item->Type() == PCB_FOOTPRINT_T )
1023 {
1024 FOOTPRINT* fp = static_cast<FOOTPRINT*>( item );
1025
1026 // Items living in a parent footprint are never removed, even if their
1027 // layer does not exist in the board editor
1028 // Otherwise the parent footprint could be seriously broken especially
1029 // if some layers are later re-enabled.
1030 // Moreover a fp lives in a fp library, that does not know the enabled
1031 // layers of a given board, so fp items are just ignored when on not
1032 // enabled layers in board editor
1033 returnItems.push_back( fp );
1034 }
1035 else if( item->Type() == PCB_GROUP_T || item->Type() == PCB_GENERATOR_T )
1036 {
1037 returnItems.push_back( item );
1038 }
1039 else
1040 {
1041 LSET allowed = item->GetLayerSet() & enabledLayers;
1042 bool item_valid = true;
1043
1044 // Ensure, for vias, the top and bottom layers are compatible with
1045 // the current board copper layers.
1046 // Otherwise they must be skipped, even is one layer is valid
1047 if( item->Type() == PCB_VIA_T )
1048 item_valid = static_cast<PCB_VIA*>( item )->HasValidLayerPair( board()->GetCopperLayerCount() );
1049
1050 if( allowed.any() && item_valid )
1051 {
1052 item->SetLayerSet( allowed );
1053 returnItems.push_back( item );
1054 }
1055 else
1056 {
1057 if( EDA_GROUP* parentGroup = item->GetParentGroup() )
1058 parentGroup->RemoveItem( item );
1059 }
1060 }
1061 }
1062
1063 if( ( returnItems.size() < aItems.size() ) || fpItemDeleted )
1064 {
1065 DisplayError( m_frame, _( "Warning: some pasted items were on layers which are not "
1066 "present in the current board.\n"
1067 "These items could not be pasted.\n" ) );
1068 }
1069
1070 aItems = returnItems;
1071}
1072
1073
1074int PCB_CONTROL::Paste( const TOOL_EVENT& aEvent )
1075{
1076 // The viewer frames cannot paste
1077 if( !m_frame->IsType( FRAME_FOOTPRINT_EDITOR ) && !m_frame->IsType( FRAME_PCB_EDITOR ) )
1078 return 0;
1079
1080 bool isFootprintEditor = m_isFootprintEditor || m_frame->IsType( FRAME_FOOTPRINT_EDITOR );
1081
1082 // The clipboard can contain two different things, an entire kicad_pcb or a single footprint
1083 if( isFootprintEditor && ( !board() || !footprint() ) )
1084 return 0;
1085
1086 // We should never get here if a modal dialog is up... but we do on MacOS.
1087 // https://gitlab.com/kicad/code/kicad/-/issues/18912
1088#ifdef __WXMAC__
1089 if( wxDialog::OSXHasModalDialogsOpen() )
1090 {
1091 wxBell();
1092 return 0;
1093 }
1094#endif
1095
1096 BOARD_COMMIT commit( m_frame );
1097
1098 CLIPBOARD_IO pi;
1099 BOARD_ITEM* clipItem = pi.Parse();
1100
1101 PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
1102
1103 if( selTool && clipItem )
1104 {
1105 PCB_SELECTION& selection = selTool->GetSelection();
1106
1107 bool hasTableCells = false;
1108
1109 for( EDA_ITEM* item : selection )
1110 {
1111 if( item->Type() == PCB_TABLECELL_T )
1112 {
1113 hasTableCells = true;
1114 break;
1115 }
1116 }
1117
1118 if( hasTableCells )
1119 {
1120 PCB_TABLE* clipboardTable = nullptr;
1121
1122 if( clipItem->Type() == PCB_T )
1123 {
1124 BOARD* clipBoard = static_cast<BOARD*>( clipItem );
1125
1126 for( BOARD_ITEM* item : clipBoard->Drawings() )
1127 {
1128 if( item->Type() == PCB_TABLE_T )
1129 {
1130 clipboardTable = static_cast<PCB_TABLE*>( item );
1131 break;
1132 }
1133 }
1134 }
1135
1136 if( clipboardTable )
1137 {
1138 PCB_EDIT_TABLE_TOOL* tableEditTool = m_toolMgr->GetTool<PCB_EDIT_TABLE_TOOL>();
1139
1140 if( tableEditTool )
1141 {
1142 wxString errorMsg;
1143
1144 if( !tableEditTool->validatePasteIntoSelection( selection, errorMsg ) )
1145 {
1146 DisplayError( m_frame, errorMsg );
1147 return 0;
1148 }
1149
1150 if( tableEditTool->pasteCellsIntoSelection( selection, clipboardTable, commit ) )
1151 {
1152 commit.Push( _( "Paste Cells" ) );
1153 return 0;
1154 }
1155 else
1156 {
1157 DisplayError( m_frame, _( "Failed to paste cells" ) );
1158 return 0;
1159 }
1160 }
1161 }
1162 }
1163 }
1164
1165 if( !clipItem )
1166 {
1167 // When the clipboard doesn't parse, create a PCB item with the clipboard contents
1168 std::vector<BOARD_ITEM*> newItems;
1169
1170 if( std::unique_ptr<wxBitmap> clipImg = GetImageFromClipboard() )
1171 {
1172 auto refImg = std::make_unique<PCB_REFERENCE_IMAGE>( m_frame->GetModel() );
1173
1174 if( refImg->GetReferenceImage().SetImage( clipImg->ConvertToImage() ) )
1175 newItems.push_back( refImg.release() );
1176 }
1177 else
1178 {
1179 const wxString clipText = GetClipboardUTF8();
1180
1181 if( clipText.empty() )
1182 return 0;
1183
1184 // If it wasn't content, then paste as a text object.
1185 if( clipText.size() > static_cast<size_t>( ADVANCED_CFG::GetCfg().m_MaxPastedTextLength ) )
1186 {
1187 int result = IsOK( m_frame, _( "Pasting a long text text string may be very slow. "
1188 "Do you want to continue?" ) );
1189 if( !result )
1190 return 0;
1191 }
1192
1193 std::unique_ptr<PCB_TEXT> item = std::make_unique<PCB_TEXT>( m_frame->GetModel() );
1194 item->SetText( clipText );
1195 item->SetLayer( m_frame->GetActiveLayer() );
1196
1197 newItems.push_back( item.release() );
1198 }
1199
1200 bool cancelled = !placeBoardItems( &commit, newItems, true, false, false, false );
1201
1202 if( cancelled )
1203 commit.Revert();
1204 else
1205 commit.Push( _( "Paste Text" ) );
1206 return 0;
1207 }
1208
1209 // If we get here, we have a parsed board/FP to paste
1210
1212 bool clear_nets = false;
1213 const wxString defaultRef = wxT( "REF**" );
1214
1215 if( aEvent.IsAction( &ACTIONS::pasteSpecial ) )
1216 {
1217 DIALOG_PASTE_SPECIAL dlg( m_frame, &mode, defaultRef );
1218
1219 if( clipItem->Type() != PCB_T )
1220 dlg.HideClearNets();
1221
1222 if( dlg.ShowModal() == wxID_CANCEL )
1223 return 0;
1224
1225 clear_nets = dlg.GetClearNets();
1226 }
1227
1228 if( clipItem->Type() == PCB_T )
1229 {
1230 BOARD* clipBoard = static_cast<BOARD*>( clipItem );
1231
1232 if( isFootprintEditor || clear_nets )
1233 {
1234 for( BOARD_CONNECTED_ITEM* item : clipBoard->AllConnectedItems() )
1235 item->SetNet( NETINFO_LIST::OrphanedItem() );
1236 }
1237 else
1238 {
1239 clipBoard->MapNets( m_frame->GetBoard() );
1240 }
1241 }
1242
1243 bool cancelled = false;
1244
1245 switch( clipItem->Type() )
1246 {
1247 case PCB_T:
1248 {
1249 BOARD* clipBoard = static_cast<BOARD*>( clipItem );
1250
1251 if( isFootprintEditor )
1252 {
1253 FOOTPRINT* editorFootprint = board()->GetFirstFootprint();
1254 std::vector<BOARD_ITEM*> pastedItems;
1255
1256 for( PCB_GROUP* group : clipBoard->Groups() )
1257 {
1258 group->SetParent( editorFootprint );
1259 pastedItems.push_back( group );
1260 }
1261
1262 clipBoard->RemoveAll( { PCB_GROUP_T } );
1263
1264 for( FOOTPRINT* clipFootprint : clipBoard->Footprints() )
1265 pasteFootprintItemsToFootprintEditor( clipFootprint, board(), pastedItems );
1266
1267 for( BOARD_ITEM* clipDrawItem : clipBoard->Drawings() )
1268 {
1269 switch( clipDrawItem->Type() )
1270 {
1271 case PCB_TEXT_T:
1272 case PCB_TEXTBOX_T:
1273 case PCB_TABLE_T:
1274 case PCB_SHAPE_T:
1275 case PCB_BARCODE_T:
1276 case PCB_DIM_ALIGNED_T:
1277 case PCB_DIM_CENTER_T:
1278 case PCB_DIM_LEADER_T:
1280 case PCB_DIM_RADIAL_T:
1281 clipDrawItem->SetParent( editorFootprint );
1282 pastedItems.push_back( clipDrawItem );
1283 break;
1284
1285 default:
1286 // Everything we *didn't* put into pastedItems is going to get nuked, so
1287 // make sure it's not still included in its parent group.
1288 if( EDA_GROUP* parentGroup = clipDrawItem->GetParentGroup() )
1289 parentGroup->RemoveItem( clipDrawItem );
1290
1291 break;
1292 }
1293 }
1294
1295 // NB: PCB_SHAPE_T actually removes everything in Drawings() (including PCB_TEXTs,
1296 // PCB_TABLEs, PCB_BARCODEs, dimensions, etc.), not just PCB_SHAPEs.)
1297 clipBoard->RemoveAll( { PCB_SHAPE_T } );
1298
1299 clipBoard->Visit(
1300 [&]( EDA_ITEM* item, void* testData )
1301 {
1302 if( item->IsBOARD_ITEM() )
1303 {
1304 // Anything still on the clipboard didn't get copied and needs to be
1305 // removed from the pasted groups.
1306 BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( item );
1307 EDA_GROUP* parentGroup = boardItem->GetParentGroup();
1308
1309 if( parentGroup )
1310 parentGroup->RemoveItem( boardItem );
1311 }
1312
1314 },
1316
1317 delete clipBoard;
1318
1319 pruneItemLayers( pastedItems );
1320
1321 cancelled = !placeBoardItems( &commit, pastedItems, true, true, mode == PASTE_MODE::UNIQUE_ANNOTATIONS,
1322 false );
1323 }
1324 else // isBoardEditor
1325 {
1326 // Fixup footprint component classes
1327 for( FOOTPRINT* fp : clipBoard->Footprints() )
1328 {
1329 fp->ResolveComponentClassNames( board(), fp->GetTransientComponentClassNames() );
1330 fp->ClearTransientComponentClassNames();
1331 }
1332
1333 if( mode == PASTE_MODE::REMOVE_ANNOTATIONS )
1334 {
1335 for( FOOTPRINT* fp : clipBoard->Footprints() )
1336 fp->SetReference( defaultRef );
1337 }
1338
1339 cancelled = !placeBoardItems( &commit, clipBoard, true, mode == PASTE_MODE::UNIQUE_ANNOTATIONS, false );
1340 }
1341
1342 break;
1343 }
1344
1345 case PCB_FOOTPRINT_T:
1346 {
1347 FOOTPRINT* clipFootprint = static_cast<FOOTPRINT*>( clipItem );
1348 std::vector<BOARD_ITEM*> pastedItems;
1349
1350 if( isFootprintEditor )
1351 {
1352 pasteFootprintItemsToFootprintEditor( clipFootprint, board(), pastedItems );
1353 delete clipFootprint;
1354 }
1355 else
1356 {
1357 if( mode == PASTE_MODE::REMOVE_ANNOTATIONS )
1358 clipFootprint->SetReference( defaultRef );
1359
1360 clipFootprint->SetParent( board() );
1361 clipFootprint->ResolveComponentClassNames( board(), clipFootprint->GetTransientComponentClassNames() );
1362 clipFootprint->ClearTransientComponentClassNames();
1363 pastedItems.push_back( clipFootprint );
1364 }
1365
1366 pruneItemLayers( pastedItems );
1367
1368 cancelled = !placeBoardItems( &commit, pastedItems, true, true, mode == PASTE_MODE::UNIQUE_ANNOTATIONS, false );
1369 break;
1370 }
1371
1372 default:
1373 m_frame->DisplayToolMsg( _( "Invalid clipboard contents" ) );
1374 break;
1375 }
1376
1377 if( cancelled )
1378 commit.Revert();
1379 else
1380 commit.Push( _( "Paste" ) );
1381
1382 return 1;
1383}
1384
1385
1387{
1388 wxString fileName;
1389
1390 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
1391
1392 if( !editFrame )
1393 return 1;
1394
1395 // Pick a file to append
1396 if( !AskLoadBoardFileName( editFrame, &fileName, KICTL_KICAD_ONLY ) )
1397 return 1;
1398
1400 IO_RELEASER<PCB_IO> pi( PCB_IO_MGR::FindPlugin( pluginType ) );
1401
1402 if( !pi )
1403 return 1;
1404
1405 return AppendBoard( *pi, fileName );
1406}
1407
1408
1410{
1411 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
1412
1413 if( !editFrame )
1414 return 1;
1415
1416 if( !editFrame->GetDesignBlockPane()->GetSelectedLibId().IsValid() )
1417 return 1;
1418
1419 DESIGN_BLOCK_PANE* designBlockPane = editFrame->GetDesignBlockPane();
1420 const LIB_ID selectedLibId = designBlockPane->GetSelectedLibId();
1421 std::unique_ptr<DESIGN_BLOCK> designBlock( designBlockPane->GetDesignBlock( selectedLibId, true, true ) );
1422
1423 if( !designBlock )
1424 {
1425 wxString msg;
1426 msg.Printf( _( "Could not find design block %s." ), selectedLibId.GetUniStringLibId() );
1427 editFrame->ShowInfoBarError( msg, true );
1428 return 1;
1429 }
1430
1431 if( designBlock->GetBoardFile().IsEmpty() || !wxFileName::FileExists( designBlock->GetBoardFile() ) )
1432 {
1433 editFrame->ShowInfoBarError( _( "Design block has no layout to place." ), true );
1434 return 1;
1435 }
1436
1438 IO_RELEASER<PCB_IO> pi( PCB_IO_MGR::FindPlugin( pluginType ) );
1439
1440 if( !pi )
1441 return 1;
1442
1443 bool repeatPlacement = false;
1444
1445 if( APP_SETTINGS_BASE* cfg = editFrame->config() )
1446 repeatPlacement = cfg->m_DesignBlockChooserPanel.repeated_placement;
1447
1448 int ret = 0;
1449
1450 do
1451 {
1452 ret = AppendBoard( *pi, designBlock->GetBoardFile(), designBlock.get() );
1453 } while( repeatPlacement && ret == 0 );
1454
1455 return ret;
1456}
1457
1459{
1460 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
1461
1462 if( !editFrame )
1463 return 1;
1464
1465 BOARD* brd = board();
1466
1467 if( !brd )
1468 return 1;
1469
1470 PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
1472
1473 std::vector<PCB_GROUP*> linkedGroups;
1474 int skippedNoLink = 0;
1475
1476 for( EDA_ITEM* item : selection )
1477 {
1478 if( item->Type() != PCB_GROUP_T )
1479 continue;
1480
1481 PCB_GROUP* g = static_cast<PCB_GROUP*>( item );
1482
1483 if( g->HasDesignBlockLink() )
1484 linkedGroups.push_back( g );
1485 else
1486 skippedNoLink++;
1487 }
1488
1489 if( linkedGroups.empty() )
1490 {
1491 m_frame->ShowInfoBarError( _( "No groups with a linked design block are selected." ), true );
1492 return 1;
1493 }
1494
1495 if( !editFrame->GetOverrideLocks() )
1496 {
1497 bool hasLocked = false;
1498
1499 for( PCB_GROUP* g : linkedGroups )
1500 {
1501 for( EDA_ITEM* item : g->GetItems() )
1502 {
1503 if( item->Type() == PCB_FOOTPRINT_T && static_cast<FOOTPRINT*>( item )->IsLocked() )
1504 {
1505 hasLocked = true;
1506 break;
1507 }
1508 }
1509
1510 if( hasLocked )
1511 break;
1512 }
1513
1514 if( hasLocked )
1515 {
1516 m_frame->ShowInfoBarWarning( _( "Selection contains locked items. "
1517 "Enable 'Override locks' to operate on them." ),
1518 true );
1519 return 1;
1520 }
1521 }
1522
1524 BOARD_COMMIT sharedCommit( m_frame );
1525
1526 struct Failure
1527 {
1529 wxString reason;
1530 };
1531 std::vector<Failure> failures;
1532 int applied = 0;
1533 bool cancelled = false;
1534 bool netlessCopperPlaced = false;
1535
1536 std::unique_ptr<WX_PROGRESS_REPORTER> progress;
1537
1538 if( linkedGroups.size() > 1 && Pgm().IsGUI() )
1539 {
1540 progress = std::make_unique<WX_PROGRESS_REPORTER>( m_frame, _( "Applying Design Block Layouts" ),
1541 (int) linkedGroups.size(), PR_CAN_ABORT );
1542 }
1543
1544 auto generateBoundingBox = []( const std::unordered_set<EDA_ITEM*>& aItems )
1545 {
1546 std::vector<VECTOR2I> bbCorners;
1547 bbCorners.reserve( aItems.size() * 4 );
1548
1549 for( EDA_ITEM* item : aItems )
1550 {
1551 const BOX2I bb = item->GetBoundingBox().GetInflated( 100000 );
1552 KIGEOM::CollectBoxCorners( bb, bbCorners );
1553 }
1554
1555 std::vector<VECTOR2I> hullVertices;
1556 BuildConvexHull( hullVertices, bbCorners );
1557
1558 SHAPE_LINE_CHAIN hull( hullVertices );
1559 return KIGEOM::RectifyPolygon( hull );
1560 };
1561
1562 // Apply the linked design block's layout to a single group. Returns with a
1563 // human-readable reason on failure.
1564 auto applyOneGroup = [&]( PCB_GROUP* group, wxString& outErr ) -> bool
1565 {
1566 DESIGN_BLOCK_PANE* pane = editFrame->GetDesignBlockPane();
1567 std::unique_ptr<DESIGN_BLOCK> designBlock( pane->GetDesignBlock( group->GetDesignBlockLibId(), true, true ) );
1568
1569 if( !designBlock )
1570 {
1571 outErr = _( "design block is not in the loaded libraries" );
1572 return false;
1573 }
1574
1575 if( designBlock->GetBoardFile().IsEmpty() )
1576 {
1577 outErr = _( "design block has no saved PCB layout" );
1578 return false;
1579 }
1580
1581 brd->Visit(
1582 []( EDA_ITEM* item, void* )
1583 {
1584 item->SetFlags( MCT_SKIP_STRUCT );
1586 },
1588
1589 auto clearFlags = [&]()
1590 {
1591 brd->Visit(
1592 []( EDA_ITEM* item, void* )
1593 {
1594 item->ClearFlags( MCT_SKIP_STRUCT );
1596 },
1598 };
1599
1600 BOARD_COMMIT tempCommit( m_frame );
1601
1603 IO_RELEASER<PCB_IO> pi( PCB_IO_MGR::FindPlugin( pluginType ) );
1604
1605 if( !pi || AppendBoard( *pi, designBlock->GetBoardFile(), designBlock.get(), &tempCommit, true ) != 0 )
1606 {
1607 clearFlags();
1608 outErr = _( "could not load the design block's layout" );
1609 return false;
1610 }
1611
1612 RULE_AREA dbRA;
1614 dbRA.m_generateEnabled = true;
1615
1616 brd->Visit(
1617 [&]( EDA_ITEM* item, void* )
1618 {
1619 if( !item->HasFlag( MCT_SKIP_STRUCT ) )
1620 {
1621 dbRA.m_designBlockItems.insert( item );
1622
1623 if( item->Type() == PCB_FOOTPRINT_T )
1624 dbRA.m_components.insert( static_cast<FOOTPRINT*>( item ) );
1625 }
1626
1628 },
1630
1631 if( dbRA.m_designBlockItems.empty() )
1632 {
1633 tempCommit.Revert();
1634 clearFlags();
1635 outErr = _( "design block contains no items to apply" );
1636 return false;
1637 }
1638
1639 // Footprint-free copper has no matched pads to map nets through, so it is copied as no-net.
1640 bool blockHasNetlessCopper = false;
1641
1642 if( dbRA.m_components.empty() )
1643 {
1644 for( EDA_ITEM* item : dbRA.m_designBlockItems )
1645 {
1646 if( BOARD_ITEM* bi = dynamic_cast<BOARD_ITEM*>( item ); bi && bi->IsConnected() )
1647 {
1648 blockHasNetlessCopper = true;
1649 break;
1650 }
1651 }
1652 }
1653
1654 dbRA.m_zone = new ZONE( brd );
1655 dbRA.m_zone->SetIsRuleArea( true );
1657 dbRA.m_zone->SetPlacementAreaEnabled( true );
1658 dbRA.m_zone->SetDoNotAllowZoneFills( false );
1659 dbRA.m_zone->SetDoNotAllowVias( false );
1660 dbRA.m_zone->SetDoNotAllowTracks( false );
1661 dbRA.m_zone->SetDoNotAllowPads( false );
1662 dbRA.m_zone->SetDoNotAllowFootprints( false );
1664 dbRA.m_zone->SetPlacementAreaSource( group->GetDesignBlockLibId().GetUniStringLibId() );
1666 dbRA.m_zone->AddPolygon( generateBoundingBox( dbRA.m_designBlockItems ) );
1667 dbRA.m_center = dbRA.m_zone->Outline()->COutline( 0 ).Centre();
1668
1669 RULE_AREA destRA;
1671
1672 for( EDA_ITEM* item : group->GetItems() )
1673 {
1674 if( item->Type() == PCB_FOOTPRINT_T )
1675 destRA.m_components.insert( static_cast<FOOTPRINT*>( item ) );
1676 }
1677
1678 destRA.m_group = group;
1679
1680 if( group->GetItems().empty() )
1681 {
1682 tempCommit.Revert();
1683 clearFlags();
1684 delete dbRA.m_zone;
1685 outErr = _( "group is empty" );
1686 return false;
1687 }
1688
1689 destRA.m_zone = new ZONE( brd );
1690 destRA.m_zone->SetZoneName( wxString::Format( wxT( "design-block-dest-%s" ),
1691 group->GetDesignBlockLibId().GetUniStringLibId() ) );
1692 destRA.m_zone->SetIsRuleArea( true );
1693 destRA.m_zone->SetLayerSet( LSET::AllCuMask() );
1694 destRA.m_zone->SetPlacementAreaEnabled( true );
1695 destRA.m_zone->SetDoNotAllowZoneFills( false );
1696 destRA.m_zone->SetDoNotAllowVias( false );
1697 destRA.m_zone->SetDoNotAllowTracks( false );
1698 destRA.m_zone->SetDoNotAllowPads( false );
1699 destRA.m_zone->SetDoNotAllowFootprints( false );
1701 destRA.m_zone->SetPlacementAreaSource( group->GetName() );
1703 destRA.m_zone->AddPolygon( generateBoundingBox( group->GetItems() ) );
1704 destRA.m_center = destRA.m_zone->Outline()->COutline( 0 ).Centre();
1705
1706 REPEAT_LAYOUT_OPTIONS options = { .m_copyRouting = true,
1707 .m_connectedRoutingOnly = false,
1708 .m_copyPlacement = true,
1709 .m_copyOtherItems = true,
1710 .m_groupItems = false,
1711 .m_includeLockedItems = true,
1712 .m_anchorFp = nullptr };
1713
1714 wxString repeatErr;
1715 int result = mct->RepeatLayout( aEvent, dbRA, destRA, options, &sharedCommit, &repeatErr );
1716
1717 tempCommit.Revert();
1718 clearFlags();
1719 delete dbRA.m_zone;
1720 delete destRA.m_zone;
1721
1722 if( result != 0 )
1723 {
1724 outErr = repeatErr.IsEmpty() ? _( "layout copy failed" ) : repeatErr;
1725 return false;
1726 }
1727
1728 if( blockHasNetlessCopper )
1729 netlessCopperPlaced = true;
1730
1731 return true;
1732 };
1733
1734 for( size_t i = 0; i < linkedGroups.size(); ++i )
1735 {
1736 PCB_GROUP* g = linkedGroups[i];
1737
1738 if( progress )
1739 {
1740 progress->SetCurrentProgress( static_cast<double>( i ) / linkedGroups.size() );
1741 progress->Report(
1742 wxString::Format( _( "Applying layout to group %zu of %zu..." ), i + 1, linkedGroups.size() ) );
1743
1744 if( !progress->KeepRefreshing() )
1745 {
1746 cancelled = true;
1747 break;
1748 }
1749 }
1750
1751 wxString err;
1752
1753 if( applyOneGroup( g, err ) )
1754 applied++;
1755 else
1756 failures.push_back( { g, err } );
1757 }
1758
1759 if( progress )
1760 progress->SetCurrentProgress( 1.0 );
1761
1762 if( cancelled )
1763 {
1764 sharedCommit.Revert();
1765 m_frame->ShowInfoBarMsg( _( "Apply design block layout cancelled." ), true );
1766 return 1;
1767 }
1768
1769 if( applied > 0 )
1770 {
1771 sharedCommit.Push( wxString::Format( _( "Apply design block layout to %d group(s)" ), applied ) );
1772
1773 if( netlessCopperPlaced )
1774 m_frame->ShowInfoBarMsg( _( "Copied copper has no net assigned. Assign nets to connect it." ), true );
1775 }
1776 else
1777 {
1778 sharedCommit.Revert();
1779 }
1780
1781 if( skippedNoLink > 0 || !failures.empty() || linkedGroups.size() > 1 )
1782 {
1783 wxString html;
1784
1785 html << wxT( "<p>" )
1786 << wxString::Format( _( "Applied design block layout to %d of %d group(s)." ), applied,
1787 (int) linkedGroups.size() )
1788 << wxT( "</p>" );
1789
1790 if( skippedNoLink > 0 )
1791 {
1792 html << wxT( "<p>" )
1793 << wxString::Format( _( "Skipped %d selected item(s) that are not groups linked to a "
1794 "design block." ),
1795 skippedNoLink )
1796 << wxT( "</p>" );
1797 }
1798
1799 if( !failures.empty() )
1800 {
1801 html << wxT( "<p>" ) << _( "The following groups could not be processed:" ) << wxT( "</p><ul>" );
1802
1803 for( const Failure& f : failures )
1804 {
1805 wxString name = f.group->GetName().IsEmpty() ? _( "(unnamed group)" ) : f.group->GetName();
1806 html << wxString::Format( wxT( "<li><b>%s</b>: %s</li>" ), name, f.reason );
1807 }
1808
1809 html << wxT( "</ul>" );
1810 }
1811
1812 HTML_MESSAGE_BOX dlg( m_frame, _( "Apply Design Block Layout" ) );
1813 dlg.SetDialogSizeInDU( 360, 220 );
1814 dlg.AddHTML_Text( html );
1815 dlg.ShowModal();
1816 }
1817
1818 return applied > 0 ? 0 : 1;
1819}
1820
1822{
1823 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
1824
1825 if( !editFrame )
1826 return 1;
1827
1828 // Need to have a group selected and it needs to have a linked design block
1829 PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
1831
1832 if( selection.Size() != 1 || selection[0]->Type() != PCB_GROUP_T )
1833 return 1;
1834
1835 PCB_GROUP* group = static_cast<PCB_GROUP*>( selection[0] );
1836
1837 if( !group->HasDesignBlockLink() )
1838 return 1;
1839
1840 // Get the associated design block
1841 DESIGN_BLOCK_PANE* designBlockPane = editFrame->GetDesignBlockPane();
1842 std::unique_ptr<DESIGN_BLOCK> designBlock( designBlockPane->GetDesignBlock( group->GetDesignBlockLibId(),
1843 true, true ) );
1844
1845 if( !designBlock )
1846 {
1847 wxString msg;
1848 msg.Printf( _( "Could not find design block %s." ), group->GetDesignBlockLibId().GetUniStringLibId() );
1849 m_frame->GetInfoBar()->ShowMessageFor( msg, 5000, wxICON_WARNING );
1850 return 1;
1851 }
1852
1853 if( designBlock->GetBoardFile().IsEmpty() )
1854 {
1855 wxString msg;
1856 msg.Printf( _( "Design block %s does not have a board file." ),
1857 group->GetDesignBlockLibId().GetUniStringLibId() );
1858 m_frame->GetInfoBar()->ShowMessageFor( msg, 5000, wxICON_WARNING );
1859 return 1;
1860 }
1861
1862
1864 IO_RELEASER<PCB_IO> pi( PCB_IO_MGR::FindPlugin( pluginType ) );
1865
1866 if( !pi )
1867 return 1;
1868
1869 if( aEvent.Parameter<bool*>() != nullptr )
1870 return AppendBoard( *pi, designBlock->GetBoardFile(), designBlock.get(),
1871 static_cast<BOARD_COMMIT*>( aEvent.Commit() ), *aEvent.Parameter<bool*>() );
1872 else
1873 return AppendBoard( *pi, designBlock->GetBoardFile(), designBlock.get() );
1874}
1875
1876
1878{
1879 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
1880
1881 if( !editFrame )
1882 return 1;
1883
1884 // Need to have a group selected and it needs to have a linked design block
1885 PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
1887
1888 if( selection.Size() != 1 || selection[0]->Type() != PCB_GROUP_T )
1889 return 1;
1890
1891 PCB_GROUP* group = static_cast<PCB_GROUP*>( selection[0] );
1892
1893 if( !group->HasDesignBlockLink() )
1894 return 1;
1895
1896 // Get the associated design block
1897 DESIGN_BLOCK_PANE* designBlockPane = editFrame->GetDesignBlockPane();
1898 std::unique_ptr<DESIGN_BLOCK> designBlock( designBlockPane->GetDesignBlock( group->GetDesignBlockLibId(),
1899 true, true ) );
1900
1901 if( !designBlock )
1902 {
1903 wxString msg;
1904 msg.Printf( _( "Could not find design block %s." ), group->GetDesignBlockLibId().GetUniStringLibId() );
1905 m_frame->GetInfoBar()->ShowMessageFor( msg, 5000, wxICON_WARNING );
1906 return 1;
1907 }
1908
1909 editFrame->GetDesignBlockPane()->SelectLibId( group->GetDesignBlockLibId() );
1910
1911 return m_toolMgr->RunAction( PCB_ACTIONS::updateDesignBlockFromSelection ) ? 1 : 0;
1912}
1913
1914
1915bool PCB_CONTROL::placeBoardItems( BOARD_COMMIT* aCommit, BOARD* aBoard, bool aAnchorAtOrigin,
1916 bool aReannotateDuplicates, bool aSkipMove )
1917{
1918 // items are new if the current board is not the board source
1919 bool isNew = board() != aBoard;
1920 std::vector<BOARD_ITEM*> items;
1921
1922 for( BOARD_ITEM* item : aBoard->GetItemSet() )
1923 {
1924 // Marker transfer is intentionally not part of append/paste item placement.
1925 if( item->Type() == PCB_MARKER_T )
1926 continue;
1927
1928 bool doCopy = ( item->GetFlags() & SKIP_STRUCT ) == 0;
1929
1930 item->ClearFlags( SKIP_STRUCT );
1931 item->SetFlags( isNew ? IS_NEW : 0 );
1932
1933 if( doCopy )
1934 items.push_back( item );
1935 }
1936
1937 if( isNew )
1938 aBoard->RemoveAll();
1939
1940 // Reparent before calling pruneItemLayers, as SetLayer can have a dependence on the
1941 // item's parent board being set correctly.
1942 if( isNew )
1943 {
1944 for( BOARD_ITEM* item : items )
1945 item->SetParent( board() );
1946 }
1947
1948 pruneItemLayers( items );
1949
1950 return placeBoardItems( aCommit, items, isNew, aAnchorAtOrigin, aReannotateDuplicates, aSkipMove );
1951}
1952
1953
1954bool PCB_CONTROL::placeBoardItems( BOARD_COMMIT* aCommit, std::vector<BOARD_ITEM*>& aItems, bool aIsNew,
1955 bool aAnchorAtOrigin, bool aReannotateDuplicates, bool aSkipMove )
1956{
1957 m_toolMgr->RunAction( ACTIONS::selectionClear );
1958
1959 PCB_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
1960
1961 std::vector<BOARD_ITEM*> itemsToSel;
1962 itemsToSel.reserve( aItems.size() );
1963
1964 for( BOARD_ITEM* item : aItems )
1965 {
1966 if( aIsNew )
1967 {
1968 item->ResetUuid();
1969
1970 item->RunOnChildren(
1971 []( BOARD_ITEM* aChild )
1972 {
1973 aChild->ResetUuid();
1974 },
1976
1977 // While BOARD_COMMIT::Push() will add any new items to the entered group,
1978 // we need to do it earlier so that the previews while moving are correct.
1979 if( PCB_GROUP* enteredGroup = selectionTool->GetEnteredGroup() )
1980 {
1981 if( item->IsGroupableType() && !item->GetParentGroup() )
1982 {
1983 aCommit->Modify( enteredGroup, nullptr, RECURSE_MODE::NO_RECURSE );
1984 enteredGroup->AddItem( item );
1985 }
1986 }
1987
1988 item->SetParent( board() );
1989 }
1990
1991 // Update item attributes if needed
1992 if( BaseType( item->Type() ) == PCB_DIMENSION_T )
1993 {
1994 static_cast<PCB_DIMENSION_BASE*>( item )->UpdateUnits();
1995 }
1996 else if( item->Type() == PCB_FOOTPRINT_T )
1997 {
1998 FOOTPRINT* footprint = static_cast<FOOTPRINT*>( item );
1999
2000 // Update the footprint path with the new KIID path if the footprint is new
2001 if( aIsNew )
2002 footprint->SetPath( KIID_PATH() );
2003
2004 for( BOARD_ITEM* dwg : footprint->GraphicalItems() )
2005 {
2006 if( BaseType( dwg->Type() ) == PCB_DIMENSION_T )
2007 static_cast<PCB_DIMENSION_BASE*>( dwg )->UpdateUnits();
2008 }
2009 }
2010
2011 // We only need to add the items that aren't inside a group currently selected
2012 // to the selection. If an item is inside a group and that group is selected,
2013 // then the selection tool will select it for us.
2014 if( !item->GetParentGroup() || !alg::contains( aItems, item->GetParentGroup()->AsEdaItem() ) )
2015 itemsToSel.push_back( item );
2016 }
2017
2018 // Select the items that should be selected
2019 EDA_ITEMS toSel( itemsToSel.begin(), itemsToSel.end() );
2020 m_toolMgr->RunAction<EDA_ITEMS*>( ACTIONS::selectItems, &toSel );
2021
2022 // Reannotate duplicate footprints (make sense only in board editor )
2023 if( aReannotateDuplicates && m_isBoardEditor )
2024 m_toolMgr->GetTool<BOARD_REANNOTATE_TOOL>()->ReannotateDuplicatesInSelection();
2025
2026 for( BOARD_ITEM* item : aItems )
2027 {
2028 if( aIsNew )
2029 aCommit->Add( item );
2030 else
2031 aCommit->Added( item );
2032 }
2033
2034 PCB_SELECTION& selection = selectionTool->GetSelection();
2035
2036 if( selection.Size() > 0 )
2037 {
2038 if( aAnchorAtOrigin )
2039 {
2040 selection.SetReferencePoint( VECTOR2I( 0, 0 ) );
2041 }
2042 else if( BOARD_ITEM* item = dynamic_cast<BOARD_ITEM*>( selection.GetTopLeftItem() ) )
2043 {
2044 selection.SetReferencePoint( item->GetPosition() );
2045 }
2046
2047 getViewControls()->SetCursorPosition( getViewControls()->GetMousePosition(), false );
2048
2049 m_toolMgr->ProcessEvent( EVENTS::SelectedEvent );
2050
2051 if( !aSkipMove )
2052 return m_toolMgr->RunSynchronousAction( PCB_ACTIONS::move, aCommit );
2053 }
2054
2055 return true;
2056}
2057
2058
2059int PCB_CONTROL::AppendBoard( PCB_IO& pi, const wxString& fileName, DESIGN_BLOCK* aDesignBlock, BOARD_COMMIT* aCommit,
2060 bool aSkipMove )
2061{
2062 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
2063
2064 if( !editFrame )
2065 return 1;
2066
2067 BOARD* brd = board();
2068
2069 if( !brd )
2070 return 1;
2071
2072 // Give ourselves a commit to work with if we weren't provided one
2073 std::unique_ptr<BOARD_COMMIT> tempCommit;
2074 BOARD_COMMIT* commit = aCommit;
2075
2076 if( !commit )
2077 {
2078 tempCommit = std::make_unique<BOARD_COMMIT>( editFrame );
2079 commit = tempCommit.get();
2080 }
2081
2082 // Mark existing items, in order to know what are the new items so we can select only
2083 // the new items after loading
2084 BOARD_ITEM_SET existingItems = brd->GetItemSet();
2085
2086 for( BOARD_ITEM* item : existingItems )
2087 item->SetFlags( SKIP_STRUCT );
2088
2089 auto clearSkipStructOnExistingItems =
2090 [&existingItems]()
2091 {
2092 for( BOARD_ITEM* item : existingItems )
2093 item->ClearFlags( SKIP_STRUCT );
2094 };
2095
2096 std::map<wxString, wxString> oldProperties = brd->GetProperties();
2097 std::map<wxString, wxString> newProperties;
2098
2099 PAGE_INFO oldPageInfo = brd->GetPageSettings();
2100 TITLE_BLOCK oldTitleBlock = brd->GetTitleBlock();
2101
2102 // Keep also the count of copper layers, to adjust if necessary
2103 int initialCopperLayerCount = brd->GetCopperLayerCount();
2104 LSET initialEnabledLayers = brd->GetEnabledLayers();
2105
2106 // Load the data
2107 try
2108 {
2109 std::map<std::string, UTF8> props;
2110
2111 // PCB_IO_EAGLE can use this info to center the BOARD, but it does not yet.
2112
2113 props["page_width"] = std::to_string( editFrame->GetPageSizeIU().x );
2114 props["page_height"] = std::to_string( editFrame->GetPageSizeIU().y );
2116
2118 [&]( wxString aTitle, int aIcon, wxString aMessage, wxString aAction ) -> bool
2119 {
2120 KIDIALOG dlg( editFrame, aMessage, aTitle, wxOK | wxCANCEL | aIcon );
2121
2122 if( !aAction.IsEmpty() )
2123 dlg.SetOKLabel( aAction );
2124
2125 dlg.DoNotShowCheckbox( aMessage, 0 );
2126
2127 return dlg.ShowModal() == wxID_OK;
2128 } );
2129
2130 // Let the user remap the appended board's layers onto this board when they do not match
2131 if( LAYER_MAPPABLE_PLUGIN* mappable = dynamic_cast<LAYER_MAPPABLE_PLUGIN*>( &pi ) )
2132 {
2133 mappable->RegisterCallback(
2134 [editFrame]( const std::vector<INPUT_LAYER_DESC>& aLayerDescs )
2135 {
2136 return DIALOG_MAP_LAYERS::RunModal( editFrame, aLayerDescs );
2137 } );
2138 }
2139
2140 WX_PROGRESS_REPORTER progressReporter( editFrame, _( "Load PCB" ), 1, PR_CAN_ABORT );
2141
2142 pi.SetProgressReporter( &progressReporter );
2143 pi.LoadBoard( fileName, brd, &props, nullptr );
2144 }
2145 catch( const IO_ERROR& ioe )
2146 {
2147 DisplayErrorMessage( editFrame, _( "Error loading board." ), ioe.What() );
2148 clearSkipStructOnExistingItems();
2149
2150 return 0;
2151 }
2152
2153 newProperties = brd->GetProperties();
2154
2155 for( const std::pair<const wxString, wxString>& prop : oldProperties )
2156 newProperties[prop.first] = prop.second;
2157
2158 brd->SetProperties( newProperties );
2159
2160 brd->SetPageSettings( oldPageInfo );
2161 brd->SetTitleBlock( oldTitleBlock );
2162
2163 // rebuild nets and ratsnest before any use of nets
2164 brd->BuildListOfNets();
2165 brd->SynchronizeNetsAndNetClasses( true );
2166 brd->BuildConnectivity();
2167
2168 // New appended items need to inherit the current global ratsnest state.
2169 // Existing items are marked SKIP_STRUCT and are handled elsewhere.
2170 const bool showGlobalRatsnest = displayOptions().m_ShowGlobalRatsnest;
2171
2172 for( BOARD_ITEM* item : brd->GetItemSet() )
2173 {
2174 if( item->GetFlags() & SKIP_STRUCT )
2175 continue;
2176
2177 if( BOARD_CONNECTED_ITEM* connectedItem = dynamic_cast<BOARD_CONNECTED_ITEM*>( item ) )
2178 connectedItem->SetLocalRatsnestVisible( showGlobalRatsnest );
2179
2180 if( item->Type() == PCB_FOOTPRINT_T )
2181 {
2182 for( PAD* pad : static_cast<FOOTPRINT*>( item )->Pads() )
2183 pad->SetLocalRatsnestVisible( showGlobalRatsnest );
2184 }
2185 }
2186
2187 // Synchronize layers
2188 // we should not ask PLUGINs to do these items:
2189 int copperLayerCount = brd->GetCopperLayerCount();
2190
2191 if( copperLayerCount > initialCopperLayerCount )
2192 brd->SetCopperLayerCount( copperLayerCount );
2193
2194 // Enable all used layers, and make them visible:
2195 LSET enabledLayers = brd->GetEnabledLayers();
2196 enabledLayers |= initialEnabledLayers;
2197 brd->SetEnabledLayers( enabledLayers );
2198 brd->SetVisibleLayers( enabledLayers );
2200
2201 if( brd->GetCopperLayerCount() != initialCopperLayerCount )
2202 {
2203 editFrame->GetInfoBar()->ShowMessageFor(
2204 wxString::Format( _( "Board changed from %d to %d copper layers, stackup updated." ),
2205 initialCopperLayerCount, brd->GetCopperLayerCount() ),
2206 6000, wxICON_INFORMATION );
2207 }
2208
2209 int ret = 0;
2210
2211 bool placeAsGroup = false;
2212
2213 if( APP_SETTINGS_BASE* cfg = editFrame->config() )
2214 placeAsGroup = cfg->m_DesignBlockChooserPanel.place_as_group;
2215
2216 if( placeBoardItems( commit, brd, false, false /* Don't reannotate dupes on Append Board */, aSkipMove ) )
2217 {
2218 if( placeAsGroup )
2219 {
2220 PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
2222
2223 // Count items that would be added to the group
2224 int groupableCount = 0;
2225
2226 for( EDA_ITEM* eda_item : selection )
2227 {
2228 if( eda_item->IsBOARD_ITEM()
2229 && !static_cast<BOARD_ITEM*>( eda_item )->GetParentFootprint() )
2230 {
2231 groupableCount++;
2232 }
2233 }
2234
2235 if( groupableCount >= 2 )
2236 {
2237 PCB_GROUP* group = new PCB_GROUP( brd );
2238
2239 if( aDesignBlock )
2240 {
2241 group->SetName( aDesignBlock->GetLibId().GetLibItemName() );
2242 group->SetDesignBlockLibId( aDesignBlock->GetLibId() );
2243 }
2244 else
2245 {
2246 group->SetName( wxFileName( fileName ).GetName() );
2247 }
2248
2249 for( EDA_ITEM* eda_item : selection )
2250 {
2251 if( eda_item->IsBOARD_ITEM() )
2252 {
2253 if( static_cast<BOARD_ITEM*>( eda_item )->IsLocked() )
2254 group->SetLocked( true );
2255 }
2256 }
2257
2258 commit->Add( group );
2259
2260 for( EDA_ITEM* eda_item : selection )
2261 {
2262 if( eda_item->IsBOARD_ITEM()
2263 && !static_cast<BOARD_ITEM*>( eda_item )->GetParentFootprint() )
2264 {
2265 commit->Modify( eda_item );
2266 group->AddItem( eda_item );
2267 }
2268 }
2269
2270 selTool->ClearSelection();
2271 selTool->select( group );
2272
2274 m_frame->OnModify();
2275 m_frame->Refresh();
2276 }
2277 }
2278
2279 // If we were provided a commit, let the caller control when to push it
2280 if( !aCommit )
2281 commit->Push( aDesignBlock ? _( "Place Design Block" ) : _( "Append Board" ) );
2282
2283 editFrame->GetBoard()->BuildConnectivity();
2284 ret = 0;
2285 }
2286 else
2287 {
2288 // If we were provided a commit, let the caller control when to revert it
2289 if( !aCommit )
2290 commit->Revert();
2291
2292 ret = 1;
2293 }
2294
2295 // Refresh the UI for the updated board properties
2296 editFrame->GetAppearancePanel()->OnBoardChanged();
2297 clearSkipStructOnExistingItems();
2298
2299 return ret;
2300}
2301
2302
2303int PCB_CONTROL::Undo( const TOOL_EVENT& aEvent )
2304{
2305 PCB_BASE_EDIT_FRAME* editFrame = dynamic_cast<PCB_BASE_EDIT_FRAME*>( m_frame );
2306 wxCommandEvent dummy;
2307
2308 if( editFrame )
2309 editFrame->RestoreCopyFromUndoList( dummy );
2310
2311 return 0;
2312}
2313
2314
2315int PCB_CONTROL::Redo( const TOOL_EVENT& aEvent )
2316{
2317 PCB_BASE_EDIT_FRAME* editFrame = dynamic_cast<PCB_BASE_EDIT_FRAME*>( m_frame );
2318 wxCommandEvent dummy;
2319
2320 if( editFrame )
2321 editFrame->RestoreCopyFromRedoList( dummy );
2322
2323 return 0;
2324}
2325
2326
2328{
2329 MAGNETIC_SETTINGS& settings = m_isFootprintEditor ? m_frame->GetFootprintEditorSettings()->m_MagneticItems
2330 : m_frame->GetPcbNewSettings()->m_MagneticItems;
2331 bool& snapMode = settings.allLayers;
2332
2334 snapMode = false;
2335 else if( aEvent.IsAction( &PCB_ACTIONS::magneticSnapAllLayers ) )
2336 snapMode = true;
2337 else
2338 snapMode = !snapMode;
2339
2341
2342 return 0;
2343}
2344
2345
2347{
2348 if( !Pgm().GetCommonSettings()->m_Input.hotkey_feedback )
2349 return 0;
2350
2351 wxArrayString labels;
2352 labels.Add( _( "Active Layer" ) );
2353 labels.Add( _( "All Layers" ) );
2354
2355 if( !m_frame->GetHotkeyPopup() )
2356 m_frame->CreateHotkeyPopup();
2357
2358 HOTKEY_CYCLE_POPUP* popup = m_frame->GetHotkeyPopup();
2359
2360 MAGNETIC_SETTINGS& settings = m_isFootprintEditor ? m_frame->GetFootprintEditorSettings()->m_MagneticItems
2361 : m_frame->GetPcbNewSettings()->m_MagneticItems;
2362
2363 if( popup )
2364 popup->Popup( _( "Object Snapping" ), labels, static_cast<int>( settings.allLayers ) );
2365
2366 return 0;
2367}
2368
2369
2371{
2372 PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
2373 ROUTER_TOOL* routerTool = m_toolMgr->GetTool<ROUTER_TOOL>();
2374 PCB_SELECTION& selection = selTool->GetSelection();
2375 PCB_EDIT_FRAME* pcbFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
2376 std::shared_ptr<DRC_ENGINE> drcEngine = m_frame->GetBoard()->GetDesignSettings().m_DRCEngine;
2377 DRC_CONSTRAINT constraint;
2378
2379 std::vector<MSG_PANEL_ITEM> msgItems;
2380
2381 if( routerTool && routerTool->RoutingInProgress() )
2382 {
2383 routerTool->UpdateMessagePanel();
2384 return 0;
2385 }
2386
2387 if( !pcbFrame && !m_frame->GetModel() )
2388 return 0;
2389
2390 if( selection.Empty() )
2391 {
2392 if( !pcbFrame )
2393 {
2394 FOOTPRINT* fp = static_cast<FOOTPRINT*>( m_frame->GetModel() );
2395 fp->GetMsgPanelInfo( m_frame, msgItems );
2396 }
2397 else
2398 {
2399 m_frame->SetMsgPanel( m_frame->GetBoard() );
2400 }
2401 }
2402 else if( selection.GetSize() == 1 )
2403 {
2404 EDA_ITEM* item = selection.Front();
2405
2406 if( std::optional<wxString> uuid = GetMsgPanelDisplayUuid( item->m_Uuid ) )
2407 msgItems.emplace_back( _( "UUID" ), *uuid );
2408
2409 item->GetMsgPanelInfo( m_frame, msgItems );
2410
2411 PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( item );
2412 NETINFO_ITEM* net = track ? track->GetNet() : nullptr;
2413 NETINFO_ITEM* coupledNet = net ? m_frame->GetBoard()->DpCoupledNet( net ) : nullptr;
2414
2415 if( coupledNet )
2416 {
2417 SEG trackSeg( track->GetStart(), track->GetEnd() );
2418 PCB_TRACK* coupledItem = nullptr;
2419 SEG::ecoord closestDist_sq = VECTOR2I::ECOORD_MAX;
2420
2421 for( PCB_TRACK* candidate : m_frame->GetBoard()->Tracks() )
2422 {
2423 if( candidate->GetNet() != coupledNet )
2424 continue;
2425
2426 SEG::ecoord dist_sq = trackSeg.SquaredDistance( SEG( candidate->GetStart(), candidate->GetEnd() ) );
2427
2428 if( !coupledItem || dist_sq < closestDist_sq )
2429 {
2430 coupledItem = candidate;
2431 closestDist_sq = dist_sq;
2432 }
2433 }
2434
2435 constraint = drcEngine->EvalRules( DIFF_PAIR_GAP_CONSTRAINT, track, coupledItem, track->GetLayer() );
2436
2437 wxString msg = m_frame->MessageTextFromMinOptMax( constraint.Value() );
2438
2439 if( !msg.IsEmpty() )
2440 {
2441 msgItems.emplace_back( wxString::Format( _( "DP Gap Constraints: %s" ), msg ),
2442 wxString::Format( _( "(from %s)" ), constraint.GetName() ) );
2443 }
2444
2445 constraint = drcEngine->EvalRules( MAX_UNCOUPLED_CONSTRAINT, track, coupledItem, track->GetLayer() );
2446
2447 if( constraint.Value().HasMax() )
2448 {
2449 msg = m_frame->MessageTextFromValue( constraint.Value().Max() );
2450 msgItems.emplace_back( wxString::Format( _( "DP Max Uncoupled-length: %s" ), msg ),
2451 wxString::Format( _( "(from %s)" ), constraint.GetName() ) );
2452 }
2453 }
2454 }
2455 else if( pcbFrame && selection.GetSize() == 2 )
2456 {
2457 // Pair selection broken into multiple, optional data, starting with the selected item
2458 // names
2459
2460 BOARD_ITEM* a = dynamic_cast<BOARD_ITEM*>( selection[0] );
2461 BOARD_ITEM* b = dynamic_cast<BOARD_ITEM*>( selection[1] );
2462
2463 if( a && b )
2464 {
2465 msgItems.emplace_back( MSG_PANEL_ITEM( a->GetItemDescription( m_frame, false ),
2466 b->GetItemDescription( m_frame, false ) ) );
2467 }
2468
2469 BOARD_CONNECTED_ITEM* a_conn = dynamic_cast<BOARD_CONNECTED_ITEM*>( a );
2470 BOARD_CONNECTED_ITEM* b_conn = dynamic_cast<BOARD_CONNECTED_ITEM*>( b );
2471
2472 if( a_conn && b_conn )
2473 {
2474 LSET overlap = a_conn->GetLayerSet() & b_conn->GetLayerSet() & LSET::AllCuMask();
2475 int a_netcode = a_conn->GetNetCode();
2476 int b_netcode = b_conn->GetNetCode();
2477
2478 if( overlap.count() > 0 )
2479 {
2480 PCB_LAYER_ID layer = overlap.CuStack().front();
2481
2482 if( a_netcode != b_netcode || a_netcode < 0 || b_netcode < 0 )
2483 {
2484 constraint = drcEngine->EvalRules( CLEARANCE_CONSTRAINT, a, b, layer );
2485 msgItems.emplace_back( _( "Resolved Clearance" ),
2486 m_frame->MessageTextFromValue( constraint.m_Value.Min() ) );
2487 }
2488
2489 std::shared_ptr<SHAPE> a_shape( a_conn->GetEffectiveShape( layer ) );
2490 std::shared_ptr<SHAPE> b_shape( b_conn->GetEffectiveShape( layer ) );
2491
2492 int actual_clearance = a_shape->GetClearance( b_shape.get() );
2493
2494 if( actual_clearance > -1 && actual_clearance < std::numeric_limits<int>::max() )
2495 {
2496 msgItems.emplace_back( _( "Actual Clearance" ),
2497 m_frame->MessageTextFromValue( actual_clearance ) );
2498 }
2499 }
2500 }
2501
2502 if( a && b && ( a->HasHole() || b->HasHole() ) )
2503 {
2504 PCB_LAYER_ID active = m_frame->GetActiveLayer();
2506
2507 if( b->IsOnLayer( active ) && IsCopperLayer( active ) )
2508 layer = active;
2509 else if( b->HasHole() && a->IsOnLayer( active ) && IsCopperLayer( active ) )
2510 layer = active;
2511 else if( a->HasHole() && b->IsOnCopperLayer() )
2512 layer = b->GetLayer();
2513 else if( b->HasHole() && a->IsOnCopperLayer() )
2514 layer = a->GetLayer();
2515
2516 if( IsCopperLayer( layer ) )
2517 {
2518 int actual = std::numeric_limits<int>::max();
2519
2520 if( a->HasHole() && b->IsOnCopperLayer() )
2521 {
2522 std::shared_ptr<SHAPE_SEGMENT> hole = a->GetEffectiveHoleShape();
2523 std::shared_ptr<SHAPE> other( b->GetEffectiveShape( layer ) );
2524
2525 actual = std::min( actual, hole->GetClearance( other.get() ) );
2526 }
2527
2528 if( b->HasHole() && a->IsOnCopperLayer() )
2529 {
2530 std::shared_ptr<SHAPE_SEGMENT> hole = b->GetEffectiveHoleShape();
2531 std::shared_ptr<SHAPE> other( a->GetEffectiveShape( layer ) );
2532
2533 actual = std::min( actual, hole->GetClearance( other.get() ) );
2534 }
2535
2536 if( actual < std::numeric_limits<int>::max() )
2537 {
2538 constraint = drcEngine->EvalRules( HOLE_CLEARANCE_CONSTRAINT, a, b, layer );
2539 msgItems.emplace_back( _( "Resolved Hole Clearance" ),
2540 m_frame->MessageTextFromValue( constraint.m_Value.Min() ) );
2541
2542 if( actual > -1 && actual < std::numeric_limits<int>::max() )
2543 {
2544 msgItems.emplace_back( _( "Actual Hole Clearance" ),
2545 m_frame->MessageTextFromValue( actual ) );
2546 }
2547 }
2548 }
2549 }
2550
2551 if( a && b )
2552 {
2553 for( PCB_LAYER_ID edgeLayer : { Edge_Cuts, Margin } )
2554 {
2555 PCB_LAYER_ID active = m_frame->GetActiveLayer();
2557
2558 if( a->IsOnLayer( edgeLayer ) && b->Type() != PCB_FOOTPRINT_T )
2559 {
2560 if( b->IsOnLayer( active ) && IsCopperLayer( active ) )
2561 layer = active;
2562 else if( IsCopperLayer( b->GetLayer() ) )
2563 layer = b->GetLayer();
2564 }
2565 else if( b->IsOnLayer( edgeLayer ) && a->Type() != PCB_FOOTPRINT_T )
2566 {
2567 if( a->IsOnLayer( active ) && IsCopperLayer( active ) )
2568 layer = active;
2569 else if( IsCopperLayer( a->GetLayer() ) )
2570 layer = a->GetLayer();
2571 }
2572
2573 if( layer >= 0 )
2574 {
2575 constraint = drcEngine->EvalRules( EDGE_CLEARANCE_CONSTRAINT, a, b, layer );
2576
2577 if( edgeLayer == Edge_Cuts )
2578 {
2579 msgItems.emplace_back( _( "Resolved Edge Clearance" ),
2580 m_frame->MessageTextFromValue( constraint.m_Value.Min() ) );
2581 }
2582 else
2583 {
2584 msgItems.emplace_back( _( "Resolved Margin Clearance" ),
2585 m_frame->MessageTextFromValue( constraint.m_Value.Min() ) );
2586 }
2587 }
2588 }
2589 }
2590 }
2591
2592 if( selection.GetSize() )
2593 {
2594 if( msgItems.empty() )
2595 {
2596 // Count items by type
2597 std::map<KICAD_T, int> typeCounts;
2598
2599 for( EDA_ITEM* item : selection )
2600 typeCounts[item->Type()]++;
2601
2602 // Check if all items are the same type
2603 bool allSameType = ( typeCounts.size() == 1 );
2604 KICAD_T commonType = allSameType ? typeCounts.begin()->first : NOT_USED;
2605
2606 if( allSameType )
2607 {
2608 // Show "Type: N" for homogeneous selections
2609 wxString typeName = selection.Front()->GetFriendlyName();
2610 msgItems.emplace_back( typeName,
2611 wxString::Format( wxT( "%d" ), selection.GetSize() ) );
2612
2613 // For pads, show common properties
2614 if( commonType == PCB_PAD_T )
2615 {
2616 std::set<wxString> layers;
2617 std::set<PAD_SHAPE> shapes;
2618 std::set<VECTOR2I> sizes;
2619
2620 for( EDA_ITEM* item : selection )
2621 {
2622 PAD* pad = static_cast<PAD*>( item );
2623 layers.insert( pad->LayerMaskDescribe() );
2624 shapes.insert( pad->GetShape( PADSTACK::ALL_LAYERS ) );
2625 sizes.insert( pad->GetSize( PADSTACK::ALL_LAYERS ) );
2626 }
2627
2628 if( layers.size() == 1 )
2629 msgItems.emplace_back( _( "Layer" ), *layers.begin() );
2630
2631 if( shapes.size() == 1 )
2632 {
2633 PAD* firstPad = static_cast<PAD*>( selection.Front() );
2634 msgItems.emplace_back( _( "Pad Shape" ),
2635 firstPad->ShowPadShape( PADSTACK::ALL_LAYERS ) );
2636 }
2637
2638 if( sizes.size() == 1 )
2639 {
2640 VECTOR2I size = *sizes.begin();
2641 msgItems.emplace_back( _( "Pad Size" ),
2642 wxString::Format( wxT( "%s x %s" ),
2643 m_frame->MessageTextFromValue( size.x ),
2644 m_frame->MessageTextFromValue( size.y ) ) );
2645 }
2646 }
2647 }
2648 else
2649 {
2650 // Show type breakdown for mixed selections
2651 wxString breakdown;
2652
2653 for( const auto& [type, count] : typeCounts )
2654 {
2655 if( !breakdown.IsEmpty() )
2656 breakdown += wxT( ", " );
2657
2658 // Get friendly name from first item of this type
2659 wxString typeName;
2660
2661 for( EDA_ITEM* item : selection )
2662 {
2663 if( item->Type() == type )
2664 {
2665 typeName = item->GetFriendlyName();
2666 break;
2667 }
2668 }
2669
2670 breakdown += wxString::Format( wxT( "%s: %d" ), typeName, count );
2671 }
2672
2673 msgItems.emplace_back( _( "Selected Items" ),
2674 wxString::Format( wxT( "%d (%s)" ),
2675 selection.GetSize(), breakdown ) );
2676 }
2677
2678 if( m_isBoardEditor )
2679 {
2680 std::set<wxString> netNames;
2681 std::set<wxString> netClasses;
2682
2683 for( EDA_ITEM* item : selection )
2684 {
2685 if( BOARD_CONNECTED_ITEM* bci = dynamic_cast<BOARD_CONNECTED_ITEM*>( item ) )
2686 {
2687 if( !bci->GetNet() || bci->GetNetCode() <= NETINFO_LIST::UNCONNECTED )
2688 continue;
2689
2690 netNames.insert( UnescapeString( bci->GetNetname() ) );
2691 netClasses.insert( UnescapeString( bci->GetEffectiveNetClass()->GetHumanReadableName() ) );
2692
2693 if( netNames.size() > 1 && netClasses.size() > 1 )
2694 break;
2695 }
2696 }
2697
2698 if( netNames.size() == 1 )
2699 msgItems.emplace_back( _( "Net" ), *netNames.begin() );
2700
2701 if( netClasses.size() == 1 )
2702 msgItems.emplace_back( _( "Resolved Netclass" ), *netClasses.begin() );
2703 }
2704 }
2705
2706 if( selection.GetSize() >= 2 )
2707 {
2708 bool lengthValid = true;
2709 double selectedLength = 0;
2710
2711 // Lambda to accumulate track length if item is a track or arc, otherwise mark invalid
2712 std::function<void( EDA_ITEM* )> accumulateTrackLength;
2713
2714 accumulateTrackLength =
2715 [&]( EDA_ITEM* aItem )
2716 {
2717 if( aItem->Type() == PCB_TRACE_T || aItem->Type() == PCB_ARC_T )
2718 {
2719 selectedLength += static_cast<PCB_TRACK*>( aItem )->GetLength();
2720 }
2721 else if( aItem->Type() == PCB_VIA_T )
2722 {
2723 // zero 2D length
2724 }
2725 else if( aItem->Type() == PCB_SHAPE_T )
2726 {
2727 PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( aItem );
2728
2729 if( shape->GetShape() == SHAPE_T::SEGMENT
2730 || shape->GetShape() == SHAPE_T::ARC
2731 || shape->GetShape() == SHAPE_T::BEZIER )
2732 {
2733 selectedLength += shape->GetLength();
2734 }
2735 else
2736 {
2737 lengthValid = false;
2738 }
2739 }
2740 // Use dynamic_cast to include PCB_GENERATORs.
2741 else if( PCB_GROUP* group = dynamic_cast<PCB_GROUP*>( aItem ) )
2742 {
2743 group->RunOnChildren( accumulateTrackLength, RECURSE_MODE::RECURSE );
2744 }
2745 else
2746 {
2747 lengthValid = false;
2748 }
2749 };
2750
2751 for( EDA_ITEM* item : selection )
2752 {
2753 if( lengthValid )
2754 accumulateTrackLength( item );
2755 }
2756
2757 if( lengthValid )
2758 {
2759 msgItems.emplace_back( _( "Selected 2D Length" ),
2760 m_frame->MessageTextFromValue( selectedLength ) );
2761 }
2762 }
2763
2764 if( selection.GetSize() >= 2 && selection.GetSize() < 100 )
2765 {
2766 LSET enabledLayers = m_frame->GetBoard()->GetEnabledLayers();
2767 LSET enabledCopper = LSET::AllCuMask( m_frame->GetBoard()->GetCopperLayerCount() );
2768 bool areaValid = true;
2769 bool hasCopper = false;
2770 bool hasNonCopper = false;
2771
2772 std::map<PCB_LAYER_ID, SHAPE_POLY_SET> layerPolys;
2773 SHAPE_POLY_SET holes;
2774
2775 std::function<void( EDA_ITEM* )> accumulateArea;
2776
2777 accumulateArea =
2778 [&]( EDA_ITEM* aItem )
2779 {
2780 if( aItem->Type() == PCB_FOOTPRINT_T || aItem->Type() == PCB_MARKER_T )
2781 {
2782 areaValid = false;
2783 return;
2784 }
2785
2786 if( PCB_GROUP* group = dynamic_cast<PCB_GROUP*>( aItem ) )
2787 {
2788 group->RunOnChildren( accumulateArea, RECURSE_MODE::RECURSE );
2789 return;
2790 }
2791
2792 if( BOARD_ITEM* boardItem = dynamic_cast<BOARD_ITEM*>( aItem ) )
2793 {
2794 boardItem->RunOnChildren( accumulateArea, RECURSE_MODE::NO_RECURSE );
2795
2796 LSET itemLayers = boardItem->GetLayerSet() & enabledLayers;
2797
2798 for( PCB_LAYER_ID layer : itemLayers )
2799 {
2800 boardItem->TransformShapeToPolySet( layerPolys[layer], layer, 0,
2802
2803 if( enabledCopper.Contains( layer ) )
2804 hasCopper = true;
2805 else
2806 hasNonCopper = true;
2807 }
2808
2809 if( aItem->Type() == PCB_PAD_T && static_cast<PAD*>( aItem )->HasHole() )
2810 {
2811 static_cast<PAD*>( aItem )->TransformHoleToPolygon( holes, 0, ARC_LOW_DEF,
2812 ERROR_OUTSIDE );
2813 }
2814 else if( aItem->Type() == PCB_VIA_T )
2815 {
2816 PCB_VIA* via = static_cast<PCB_VIA*>( aItem );
2817 VECTOR2I center = via->GetPosition();
2818 int R = via->GetDrillValue() / 2;
2819
2821 }
2822 }
2823 };
2824
2825 for( EDA_ITEM* item : selection )
2826 {
2827 if( areaValid )
2828 accumulateArea( item );
2829 }
2830
2831 if( areaValid )
2832 {
2833 double area = 0.0;
2834
2835 for( auto& [layer, layerPoly] : layerPolys )
2836 {
2837 // Only subtract holes from copper layers
2838 if( enabledCopper.Contains( layer ) )
2839 layerPoly.BooleanSubtract( holes );
2840
2841 area += layerPoly.Area();
2842 }
2843
2844 // Choose appropriate label based on what layers are involved
2845 wxString areaLabel;
2846
2847 if( hasCopper && !hasNonCopper )
2848 areaLabel = _( "Selected 2D Copper Area" );
2849 else if( !hasCopper && hasNonCopper )
2850 areaLabel = _( "Selected 2D Area" );
2851 else
2852 areaLabel = _( "Selected 2D Total Area" );
2853
2854 msgItems.emplace_back( areaLabel,
2855 m_frame->MessageTextFromValue( area, true, EDA_DATA_TYPE::AREA ) );
2856 }
2857 }
2858 }
2859 else
2860 {
2861 m_frame->GetBoard()->GetMsgPanelInfo( m_frame, msgItems );
2862 }
2863
2864 m_frame->SetMsgPanel( msgItems );
2865
2866 // Update vertex editor if it exists
2867 PCB_BASE_EDIT_FRAME* editFrame = dynamic_cast<PCB_BASE_EDIT_FRAME*>( m_frame );
2868 if( editFrame )
2869 {
2870 BOARD_ITEM* selectedItem = ( selection.GetSize() == 1 ) ? dynamic_cast<BOARD_ITEM*>( selection.Front() )
2871 : nullptr;
2872 editFrame->UpdateVertexEditorSelection( selectedItem );
2873 }
2874
2875 return 0;
2876}
2877
2878
2880{
2881 wxFileName fileName = wxFileName( *aEvent.Parameter<wxString*>() );
2882
2883 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
2884
2885 if( !editFrame )
2886 return 1;
2887
2888 wxString filePath = fileName.GetFullPath();
2890 IO_RELEASER<PCB_IO> pi( PCB_IO_MGR::FindPlugin( pluginType ) );
2891
2892 if( !pi )
2893 return 1;
2894
2895 return AppendBoard( *pi, filePath );
2896}
2897
2898
2900{
2901 BOARD_COMMIT commit( this );
2902 EDA_UNITS displayUnit = m_frame->GetUserUnits();
2903 PCB_TABLE* table = Build_Board_Characteristics_Table( m_frame->GetBoard(), displayUnit );
2904 table->SetLayer( m_frame->GetActiveLayer() );
2905
2906 std::vector<BOARD_ITEM*> items;
2907 items.push_back( table );
2908
2909 if( placeBoardItems( &commit, items, true, true, false, false ) )
2910 commit.Push( _( "Place Board Characteristics" ) );
2911 else
2912 delete table;
2913
2914 return 0;
2915}
2916
2917
2919{
2920 BOARD_COMMIT commit( this );
2921 EDA_UNITS displayUnit = m_frame->GetUserUnits();
2922
2923 PCB_TABLE* table = Build_Board_Stackup_Table( m_frame->GetBoard(), displayUnit );
2924 table->SetLayer( m_frame->GetActiveLayer() );
2925
2926 std::vector<BOARD_ITEM*> items;
2927 items.push_back( table );
2928
2929 if( placeBoardItems( &commit, items, true, true, false, false ) )
2930 commit.Push( _( "Place Board Stackup Table" ) );
2931 else
2932 delete table;
2933
2934 return 0;
2935}
2936
2937
2939{
2940 PCB_DISPLAY_OPTIONS opts = m_frame->GetDisplayOptions();
2941 opts.m_FlipBoardView = !opts.m_FlipBoardView;
2942 m_frame->SetDisplayOptions( opts );
2943
2944 return 0;
2945}
2946
2947
2949{
2950 if( aItem->Type() != PCB_SHAPE_T )
2951 return;
2952
2953 PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( aItem );
2954
2955 // Re-caching every non-hatched shape on each edit stalls commits on dense boards.
2956 if( !shape->IsHatchedFill() )
2957 return;
2958
2959 shape->UpdateHatching();
2960
2961 if( aView )
2962 aView->Update( aItem );
2963}
2964
2965
2967{
2968 KIGFX::VIEW* view = this->view();
2969
2970 for( FOOTPRINT* footprint : board()->Footprints() )
2971 footprint->RunOnChildren( std::bind( &PCB_CONTROL::rehatchBoardItem, view, _1 ), NO_RECURSE );
2972
2973 for( BOARD_ITEM* item : board()->Drawings() )
2974 rehatchBoardItem( view, item );
2975
2976 return 0;
2977}
2978
2979
2981{
2982 BOARD* brd = board();
2983
2984 if( !brd )
2985 return 0;
2986
2987 PROJECT& prj = m_frame->Prj();
2989 FILENAME_RESOLVER* resolver = cache ? cache->GetResolver() : nullptr;
2990
2991 wxString workingPath = prj.GetProjectPath();
2992 std::vector<const EMBEDDED_FILES*> stack;
2993 stack.push_back( brd->GetEmbeddedFiles() );
2994
2995 BOARD_COMMIT commit( m_frame );
2996 int embeddedCount = 0;
2997
2998 for( FOOTPRINT* fp : brd->Footprints() )
2999 {
3000 bool fpModified = false;
3001
3002 for( FP_3DMODEL& model : fp->Models() )
3003 {
3004 if( model.m_Filename.StartsWith( FILEEXT::KiCadUriPrefix ) )
3005 continue;
3006
3007 wxString fullPath =
3008 resolver ? resolver->ResolvePath( model.m_Filename, workingPath, stack )
3009 : model.m_Filename;
3010
3011 wxFileName fname( fullPath );
3012 wxString ext = fname.GetExt().Upper();
3013
3014 if( fname.Exists() )
3015 {
3017 brd->GetEmbeddedFiles()->AddFile( fname, false ) )
3018 {
3019 model.m_Filename = file->GetLink();
3020 fpModified = true;
3021 embeddedCount++;
3022
3023 // Store STEP along with WRL for the OCCT(STEP) exporter.
3024 if( ext == "WRL" || ext == "WRZ" )
3025 {
3026 wxArrayString alts;
3027
3028 // Step files
3029 alts.Add( wxT( "stp" ) );
3030 alts.Add( wxT( "step" ) );
3031 alts.Add( wxT( "STP" ) );
3032 alts.Add( wxT( "STEP" ) );
3033 alts.Add( wxT( "Stp" ) );
3034 alts.Add( wxT( "Step" ) );
3035 alts.Add( wxT( "stpz" ) );
3036 alts.Add( wxT( "stpZ" ) );
3037 alts.Add( wxT( "STPZ" ) );
3038
3039 for( const auto& alt : alts )
3040 {
3041 wxFileName altFile( fname.GetPath(),
3042 fname.GetName() + wxT( "." ) + alt );
3043
3044 if( altFile.IsOk() && altFile.FileExists() )
3045 {
3046 brd->GetEmbeddedFiles()->AddFile( altFile, false );
3047 break;
3048 }
3049 }
3050 }
3051 }
3052 }
3053 }
3054
3055 if( fpModified )
3056 commit.Modify( fp );
3057 }
3058
3059 if( embeddedCount > 0 )
3060 {
3061 commit.Push( _( "Embed 3D Models" ) );
3062 wxString msg = wxString::Format( _( "%d 3D model(s) successfully embedded." ), embeddedCount );
3063 m_frame->GetInfoBar()->ShowMessageFor( msg, 5000 );
3064 }
3065
3066 return 0;
3067}
3068
3069
3070// clang-format off
3072{
3075 Go( &PCB_CONTROL::Print, ACTIONS::print.MakeEvent() );
3076
3077 // Footprint library actions
3082
3083 // Display modes
3100
3101 // Layer control
3139
3142
3143 // Grid control
3146
3147 Go( &PCB_CONTROL::Undo, ACTIONS::undo.MakeEvent() );
3148 Go( &PCB_CONTROL::Redo, ACTIONS::redo.MakeEvent() );
3149
3150 // Snapping control
3155
3156 // Miscellaneous
3159
3160 // Append control
3169
3170 Go( &PCB_CONTROL::Paste, ACTIONS::paste.MakeEvent() );
3172
3179
3180 // Add library by dropping file
3183}
3184// 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:356
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:372
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:2506
EMBEDDED_FILES * GetEmbeddedFiles() override
Definition board.cpp:3413
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:3517
void BuildListOfNets()
Definition board.h:1049
const std::vector< BOARD_CONNECTED_ITEM * > AllConnectedItems()
Definition board.cpp:3482
const PAGE_INFO & GetPageSettings() const
Definition board.h:889
void SetProperties(const std::map< wxString, wxString > &aProps)
Definition board.h:458
const GROUPS & Groups() const
The groups must maintain the following invariants.
Definition board.h:453
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:3004
FOOTPRINT * GetFirstFootprint() const
Get the first footprint on the board or nullptr.
Definition board.h:587
TITLE_BLOCK & GetTitleBlock()
Definition board.h:895
int GetCopperLayerCount() const
Definition board.cpp:985
const std::map< wxString, wxString > & GetProperties() const
Definition board.h:457
const FOOTPRINTS & Footprints() const
Definition board.h:420
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:1538
const BOARD_ITEM_SET GetItemSet()
Collect every owned item (tracks, zones, generators, footprints, drawings, markers,...
Definition board.cpp:3894
void SetPageSettings(const PAGE_INFO &aPageSettings)
Definition board.h:890
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 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:897
const DRAWINGS & Drawings() const
Definition board.h:422
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
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:89
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:528
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:830
void AddPolygon(std::vector< VECTOR2I > &aPolygon)
Add a polygon to the zone outline.
Definition zone.cpp:1350
void SetPlacementAreaSource(const wxString &aSource)
Definition zone.h:817
void SetPlacementAreaSourceType(PLACEMENT_SOURCE_T aType)
Definition zone.h:819
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:812
void SetDoNotAllowTracks(bool aEnable)
Definition zone.h:829
void SetLayerSet(const LSET &aLayerSet) override
Definition zone.cpp:624
void SetDoNotAllowVias(bool aEnable)
Definition zone.h:828
void SetDoNotAllowFootprints(bool aEnable)
Definition zone.h:831
void SetDoNotAllowZoneFills(bool aEnable)
Definition zone.h:827
void SetZoneName(const wxString &aName)
Definition zone.h:161
void SetPlacementAreaEnabled(bool aEnabled)
Definition zone.h:814
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_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