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