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, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
26#include "pcb_control.h"
28
29#include <advanced_config.h>
30#include <collectors.h>
31#include <kiplatform/ui.h>
32#include <kiway.h>
33#include <tools/edit_tool.h>
35#include <router/router_tool.h>
36#include <pgm_base.h>
37#include <tools/pcb_actions.h>
42#include <board_commit.h>
43#include <board.h>
45#include <board_item.h>
47#include <clipboard.h>
48#include <design_block.h>
51#include <pcb_dimension.h>
55#include <footprint.h>
56#include <pad.h>
57#include <layer_pairs.h>
58#include <pcb_group.h>
60#include <pcb_reference_image.h>
61#include <pcb_textbox.h>
62#include <pcb_table.h>
63#include <pcb_tablecell.h>
64#include <pcb_track.h>
65#include <pcb_generator.h>
67#include <project_pcb.h>
69#include <filename_resolver.h>
70#include <3d_cache/3d_cache.h>
71#include <embedded_files.h>
72#include <wx/filename.h>
73#include <zone.h>
74#include <confirm.h>
75#include <kidialog.h>
77#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
1008
1009void PCB_CONTROL::pruneItemLayers( std::vector<BOARD_ITEM*>& aItems )
1010{
1011 // Do not prune items or layers when copying to the FP editor, because all
1012 // layers are accepted, even if they are not enabled in the dummy board
1013 // This is mainly true for internal copper layers: all are allowed but only one
1014 // (In1.cu) is enabled for the GUI.
1016 return;
1017
1018 LSET enabledLayers = board()->GetEnabledLayers();
1019 std::vector<BOARD_ITEM*> returnItems;
1020 bool fpItemDeleted = false;
1021
1022 for( BOARD_ITEM* item : aItems )
1023 {
1024 if( item->Type() == PCB_FOOTPRINT_T )
1025 {
1026 FOOTPRINT* fp = static_cast<FOOTPRINT*>( item );
1027
1028 // Items living in a parent footprint are never removed, even if their
1029 // layer does not exist in the board editor
1030 // Otherwise the parent footprint could be seriously broken especially
1031 // if some layers are later re-enabled.
1032 // Moreover a fp lives in a fp library, that does not know the enabled
1033 // layers of a given board, so fp items are just ignored when on not
1034 // enabled layers in board editor
1035 returnItems.push_back( fp );
1036 }
1037 else if( item->Type() == PCB_GROUP_T || item->Type() == PCB_GENERATOR_T )
1038 {
1039 returnItems.push_back( item );
1040 }
1041 else
1042 {
1043 LSET allowed = item->GetLayerSet() & enabledLayers;
1044 bool item_valid = true;
1045
1046 // Ensure, for vias, the top and bottom layers are compatible with
1047 // the current board copper layers.
1048 // Otherwise they must be skipped, even is one layer is valid
1049 if( item->Type() == PCB_VIA_T )
1050 item_valid = static_cast<PCB_VIA*>( item )->HasValidLayerPair( board()->GetCopperLayerCount() );
1051
1052 if( allowed.any() && item_valid )
1053 {
1054 item->SetLayerSet( allowed );
1055 returnItems.push_back( item );
1056 }
1057 else
1058 {
1059 if( EDA_GROUP* parentGroup = item->GetParentGroup() )
1060 parentGroup->RemoveItem( item );
1061 }
1062 }
1063 }
1064
1065 if( ( returnItems.size() < aItems.size() ) || fpItemDeleted )
1066 {
1067 DisplayError( m_frame, _( "Warning: some pasted items were on layers which are not "
1068 "present in the current board.\n"
1069 "These items could not be pasted.\n" ) );
1070 }
1071
1072 aItems = returnItems;
1073}
1074
1075
1076int PCB_CONTROL::Paste( const TOOL_EVENT& aEvent )
1077{
1078 // The viewer frames cannot paste
1079 if( !m_frame->IsType( FRAME_FOOTPRINT_EDITOR ) && !m_frame->IsType( FRAME_PCB_EDITOR ) )
1080 return 0;
1081
1082 bool isFootprintEditor = m_isFootprintEditor || m_frame->IsType( FRAME_FOOTPRINT_EDITOR );
1083
1084 // The clipboard can contain two different things, an entire kicad_pcb or a single footprint
1085 if( isFootprintEditor && ( !board() || !footprint() ) )
1086 return 0;
1087
1088 // We should never get here if a modal dialog is up... but we do on MacOS.
1089 // https://gitlab.com/kicad/code/kicad/-/issues/18912
1090#ifdef __WXMAC__
1091 if( wxDialog::OSXHasModalDialogsOpen() )
1092 {
1093 wxBell();
1094 return 0;
1095 }
1096#endif
1097
1098 BOARD_COMMIT commit( m_frame );
1099
1100 CLIPBOARD_IO pi;
1101 BOARD_ITEM* clipItem = pi.Parse();
1102
1103 PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
1104
1105 if( selTool && clipItem )
1106 {
1107 PCB_SELECTION& selection = selTool->GetSelection();
1108
1109 bool hasTableCells = false;
1110
1111 for( EDA_ITEM* item : selection )
1112 {
1113 if( item->Type() == PCB_TABLECELL_T )
1114 {
1115 hasTableCells = true;
1116 break;
1117 }
1118 }
1119
1120 if( hasTableCells )
1121 {
1122 PCB_TABLE* clipboardTable = nullptr;
1123
1124 if( clipItem->Type() == PCB_T )
1125 {
1126 BOARD* clipBoard = static_cast<BOARD*>( clipItem );
1127
1128 for( BOARD_ITEM* item : clipBoard->Drawings() )
1129 {
1130 if( item->Type() == PCB_TABLE_T )
1131 {
1132 clipboardTable = static_cast<PCB_TABLE*>( item );
1133 break;
1134 }
1135 }
1136 }
1137
1138 if( clipboardTable )
1139 {
1140 PCB_EDIT_TABLE_TOOL* tableEditTool = m_toolMgr->GetTool<PCB_EDIT_TABLE_TOOL>();
1141
1142 if( tableEditTool )
1143 {
1144 wxString errorMsg;
1145
1146 if( !tableEditTool->validatePasteIntoSelection( selection, errorMsg ) )
1147 {
1148 DisplayError( m_frame, errorMsg );
1149 return 0;
1150 }
1151
1152 if( tableEditTool->pasteCellsIntoSelection( selection, clipboardTable, commit ) )
1153 {
1154 commit.Push( _( "Paste Cells" ) );
1155 return 0;
1156 }
1157 else
1158 {
1159 DisplayError( m_frame, _( "Failed to paste cells" ) );
1160 return 0;
1161 }
1162 }
1163 }
1164 }
1165 }
1166
1167 if( !clipItem )
1168 {
1169 // When the clipboard doesn't parse, create a PCB item with the clipboard contents
1170 std::vector<BOARD_ITEM*> newItems;
1171
1172 if( std::unique_ptr<wxBitmap> clipImg = GetImageFromClipboard() )
1173 {
1174 auto refImg = std::make_unique<PCB_REFERENCE_IMAGE>( m_frame->GetModel() );
1175
1176 if( refImg->GetReferenceImage().SetImage( clipImg->ConvertToImage() ) )
1177 newItems.push_back( refImg.release() );
1178 }
1179 else
1180 {
1181 const wxString clipText = GetClipboardUTF8();
1182
1183 if( clipText.empty() )
1184 return 0;
1185
1186 // If it wasn't content, then paste as a text object.
1187 if( clipText.size() > static_cast<size_t>( ADVANCED_CFG::GetCfg().m_MaxPastedTextLength ) )
1188 {
1189 int result = IsOK( m_frame, _( "Pasting a long text text string may be very slow. "
1190 "Do you want to continue?" ) );
1191 if( !result )
1192 return 0;
1193 }
1194
1195 std::unique_ptr<PCB_TEXT> item = std::make_unique<PCB_TEXT>( m_frame->GetModel() );
1196 item->SetText( clipText );
1197 item->SetLayer( m_frame->GetActiveLayer() );
1198
1199 newItems.push_back( item.release() );
1200 }
1201
1202 bool cancelled = !placeBoardItems( &commit, newItems, true, false, false, false );
1203
1204 if( cancelled )
1205 commit.Revert();
1206 else
1207 commit.Push( _( "Paste Text" ) );
1208 return 0;
1209 }
1210
1211 // If we get here, we have a parsed board/FP to paste
1212
1214 bool clear_nets = false;
1215 const wxString defaultRef = wxT( "REF**" );
1216
1217 if( aEvent.IsAction( &ACTIONS::pasteSpecial ) )
1218 {
1219 DIALOG_PASTE_SPECIAL dlg( m_frame, &mode, defaultRef );
1220
1221 if( clipItem->Type() != PCB_T )
1222 dlg.HideClearNets();
1223
1224 if( dlg.ShowModal() == wxID_CANCEL )
1225 return 0;
1226
1227 clear_nets = dlg.GetClearNets();
1228 }
1229
1230 if( clipItem->Type() == PCB_T )
1231 {
1232 BOARD* clipBoard = static_cast<BOARD*>( clipItem );
1233
1234 if( isFootprintEditor || clear_nets )
1235 {
1236 for( BOARD_CONNECTED_ITEM* item : clipBoard->AllConnectedItems() )
1237 item->SetNet( NETINFO_LIST::OrphanedItem() );
1238 }
1239 else
1240 {
1241 clipBoard->MapNets( m_frame->GetBoard() );
1242 }
1243 }
1244
1245 bool cancelled = false;
1246
1247 switch( clipItem->Type() )
1248 {
1249 case PCB_T:
1250 {
1251 BOARD* clipBoard = static_cast<BOARD*>( clipItem );
1252
1253 if( isFootprintEditor )
1254 {
1255 FOOTPRINT* editorFootprint = board()->GetFirstFootprint();
1256 std::vector<BOARD_ITEM*> pastedItems;
1257
1258 for( PCB_GROUP* group : clipBoard->Groups() )
1259 {
1260 group->SetParent( editorFootprint );
1261 pastedItems.push_back( group );
1262 }
1263
1264 clipBoard->RemoveAll( { PCB_GROUP_T } );
1265
1266 for( FOOTPRINT* clipFootprint : clipBoard->Footprints() )
1267 pasteFootprintItemsToFootprintEditor( clipFootprint, board(), pastedItems );
1268
1269 for( BOARD_ITEM* clipDrawItem : clipBoard->Drawings() )
1270 {
1271 switch( clipDrawItem->Type() )
1272 {
1273 case PCB_TEXT_T:
1274 case PCB_TEXTBOX_T:
1275 case PCB_TABLE_T:
1276 case PCB_SHAPE_T:
1277 case PCB_BARCODE_T:
1278 case PCB_DIM_ALIGNED_T:
1279 case PCB_DIM_CENTER_T:
1280 case PCB_DIM_LEADER_T:
1282 case PCB_DIM_RADIAL_T:
1283 clipDrawItem->SetParent( editorFootprint );
1284 pastedItems.push_back( clipDrawItem );
1285 break;
1286
1287 default:
1288 // Everything we *didn't* put into pastedItems is going to get nuked, so
1289 // make sure it's not still included in its parent group.
1290 if( EDA_GROUP* parentGroup = clipDrawItem->GetParentGroup() )
1291 parentGroup->RemoveItem( clipDrawItem );
1292
1293 break;
1294 }
1295 }
1296
1297 // NB: PCB_SHAPE_T actually removes everything in Drawings() (including PCB_TEXTs,
1298 // PCB_TABLEs, PCB_BARCODEs, dimensions, etc.), not just PCB_SHAPEs.)
1299 clipBoard->RemoveAll( { PCB_SHAPE_T } );
1300
1301 clipBoard->Visit(
1302 [&]( EDA_ITEM* item, void* testData )
1303 {
1304 if( item->IsBOARD_ITEM() )
1305 {
1306 // Anything still on the clipboard didn't get copied and needs to be
1307 // removed from the pasted groups.
1308 BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( item );
1309 EDA_GROUP* parentGroup = boardItem->GetParentGroup();
1310
1311 if( parentGroup )
1312 parentGroup->RemoveItem( boardItem );
1313 }
1314
1316 },
1318
1319 delete clipBoard;
1320
1321 pruneItemLayers( pastedItems );
1322
1323 cancelled = !placeBoardItems( &commit, pastedItems, true, true, mode == PASTE_MODE::UNIQUE_ANNOTATIONS,
1324 false );
1325 }
1326 else // isBoardEditor
1327 {
1328 // Fixup footprint component classes
1329 for( FOOTPRINT* fp : clipBoard->Footprints() )
1330 {
1331 fp->ResolveComponentClassNames( board(), fp->GetTransientComponentClassNames() );
1332 fp->ClearTransientComponentClassNames();
1333 }
1334
1335 if( mode == PASTE_MODE::REMOVE_ANNOTATIONS )
1336 {
1337 for( FOOTPRINT* fp : clipBoard->Footprints() )
1338 fp->SetReference( defaultRef );
1339 }
1340
1341 cancelled = !placeBoardItems( &commit, clipBoard, true, mode == PASTE_MODE::UNIQUE_ANNOTATIONS, false );
1342 }
1343
1344 break;
1345 }
1346
1347 case PCB_FOOTPRINT_T:
1348 {
1349 FOOTPRINT* clipFootprint = static_cast<FOOTPRINT*>( clipItem );
1350 std::vector<BOARD_ITEM*> pastedItems;
1351
1352 if( isFootprintEditor )
1353 {
1354 pasteFootprintItemsToFootprintEditor( clipFootprint, board(), pastedItems );
1355 delete clipFootprint;
1356 }
1357 else
1358 {
1359 if( mode == PASTE_MODE::REMOVE_ANNOTATIONS )
1360 clipFootprint->SetReference( defaultRef );
1361
1362 clipFootprint->SetParent( board() );
1363 clipFootprint->ResolveComponentClassNames( board(), clipFootprint->GetTransientComponentClassNames() );
1364 clipFootprint->ClearTransientComponentClassNames();
1365 pastedItems.push_back( clipFootprint );
1366 }
1367
1368 pruneItemLayers( pastedItems );
1369
1370 cancelled = !placeBoardItems( &commit, pastedItems, true, true, mode == PASTE_MODE::UNIQUE_ANNOTATIONS, false );
1371 break;
1372 }
1373
1374 default:
1375 m_frame->DisplayToolMsg( _( "Invalid clipboard contents" ) );
1376 break;
1377 }
1378
1379 if( cancelled )
1380 commit.Revert();
1381 else
1382 commit.Push( _( "Paste" ) );
1383
1384 return 1;
1385}
1386
1387
1389{
1390 wxString fileName;
1391
1392 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
1393
1394 if( !editFrame )
1395 return 1;
1396
1397 // Pick a file to append
1398 if( !AskLoadBoardFileName( editFrame, &fileName, KICTL_KICAD_ONLY ) )
1399 return 1;
1400
1402 IO_RELEASER<PCB_IO> pi( PCB_IO_MGR::FindPlugin( pluginType ) );
1403
1404 if( !pi )
1405 return 1;
1406
1407 return AppendBoard( *pi, fileName );
1408}
1409
1410
1412{
1413 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
1414
1415 if( !editFrame )
1416 return 1;
1417
1418 if( !editFrame->GetDesignBlockPane()->GetSelectedLibId().IsValid() )
1419 return 1;
1420
1421 DESIGN_BLOCK_PANE* designBlockPane = editFrame->GetDesignBlockPane();
1422 const LIB_ID selectedLibId = designBlockPane->GetSelectedLibId();
1423 std::unique_ptr<DESIGN_BLOCK> designBlock( designBlockPane->GetDesignBlock( selectedLibId, true, true ) );
1424
1425 if( !designBlock )
1426 {
1427 wxString msg;
1428 msg.Printf( _( "Could not find design block %s." ), selectedLibId.GetUniStringLibId() );
1429 editFrame->ShowInfoBarError( msg, true );
1430 return 1;
1431 }
1432
1433 if( designBlock->GetBoardFile().IsEmpty() || !wxFileName::FileExists( designBlock->GetBoardFile() ) )
1434 {
1435 editFrame->ShowInfoBarError( _( "Design block has no layout to place." ), true );
1436 return 1;
1437 }
1438
1440 IO_RELEASER<PCB_IO> pi( PCB_IO_MGR::FindPlugin( pluginType ) );
1441
1442 if( !pi )
1443 return 1;
1444
1445 bool repeatPlacement = false;
1446
1447 if( APP_SETTINGS_BASE* cfg = editFrame->config() )
1448 repeatPlacement = cfg->m_DesignBlockChooserPanel.repeated_placement;
1449
1450 int ret = 0;
1451
1452 do
1453 {
1454 ret = AppendBoard( *pi, designBlock->GetBoardFile(), designBlock.get() );
1455 } while( repeatPlacement && ret == 0 );
1456
1457 return ret;
1458}
1459
1461{
1462 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
1463
1464 if( !editFrame )
1465 return 1;
1466
1467 BOARD* brd = board();
1468
1469 if( !brd )
1470 return 1;
1471
1472 PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
1474
1475 std::vector<PCB_GROUP*> linkedGroups;
1476 int skippedNoLink = 0;
1477
1478 for( EDA_ITEM* item : selection )
1479 {
1480 if( item->Type() != PCB_GROUP_T )
1481 continue;
1482
1483 PCB_GROUP* g = static_cast<PCB_GROUP*>( item );
1484
1485 if( g->HasDesignBlockLink() )
1486 linkedGroups.push_back( g );
1487 else
1488 skippedNoLink++;
1489 }
1490
1491 if( linkedGroups.empty() )
1492 {
1493 m_frame->ShowInfoBarError( _( "No groups with a linked design block are selected." ), true );
1494 return 1;
1495 }
1496
1497 if( !editFrame->GetOverrideLocks() )
1498 {
1499 bool hasLocked = false;
1500
1501 for( PCB_GROUP* g : linkedGroups )
1502 {
1503 for( EDA_ITEM* item : g->GetItems() )
1504 {
1505 if( item->Type() == PCB_FOOTPRINT_T && static_cast<FOOTPRINT*>( item )->IsLocked() )
1506 {
1507 hasLocked = true;
1508 break;
1509 }
1510 }
1511
1512 if( hasLocked )
1513 break;
1514 }
1515
1516 if( hasLocked )
1517 {
1518 m_frame->ShowInfoBarWarning( _( "Selection contains locked items. "
1519 "Enable 'Override locks' to operate on them." ),
1520 true );
1521 return 1;
1522 }
1523 }
1524
1526 BOARD_COMMIT sharedCommit( m_frame );
1527
1528 struct Failure
1529 {
1531 wxString reason;
1532 };
1533 std::vector<Failure> failures;
1534 int applied = 0;
1535 bool cancelled = false;
1536
1537 std::unique_ptr<WX_PROGRESS_REPORTER> progress;
1538
1539 if( linkedGroups.size() > 1 && Pgm().IsGUI() )
1540 {
1541 progress = std::make_unique<WX_PROGRESS_REPORTER>( m_frame, _( "Applying Design Block Layouts" ),
1542 (int) linkedGroups.size(), PR_CAN_ABORT );
1543 }
1544
1545 auto generateBoundingBox = []( const std::unordered_set<EDA_ITEM*>& aItems )
1546 {
1547 std::vector<VECTOR2I> bbCorners;
1548 bbCorners.reserve( aItems.size() * 4 );
1549
1550 for( EDA_ITEM* item : aItems )
1551 {
1552 const BOX2I bb = item->GetBoundingBox().GetInflated( 100000 );
1553 KIGEOM::CollectBoxCorners( bb, bbCorners );
1554 }
1555
1556 std::vector<VECTOR2I> hullVertices;
1557 BuildConvexHull( hullVertices, bbCorners );
1558
1559 SHAPE_LINE_CHAIN hull( hullVertices );
1560 return KIGEOM::RectifyPolygon( hull );
1561 };
1562
1563 // Apply the linked design block's layout to a single group. Returns with a
1564 // human-readable reason on failure.
1565 auto applyOneGroup = [&]( PCB_GROUP* group, wxString& outErr ) -> bool
1566 {
1567 DESIGN_BLOCK_PANE* pane = editFrame->GetDesignBlockPane();
1568 std::unique_ptr<DESIGN_BLOCK> designBlock( pane->GetDesignBlock( group->GetDesignBlockLibId(), true, true ) );
1569
1570 if( !designBlock )
1571 {
1572 outErr = _( "design block is not in the loaded libraries" );
1573 return false;
1574 }
1575
1576 if( designBlock->GetBoardFile().IsEmpty() )
1577 {
1578 outErr = _( "design block has no saved PCB layout" );
1579 return false;
1580 }
1581
1582 brd->Visit(
1583 []( EDA_ITEM* item, void* )
1584 {
1585 item->SetFlags( MCT_SKIP_STRUCT );
1587 },
1589
1590 auto clearFlags = [&]()
1591 {
1592 brd->Visit(
1593 []( EDA_ITEM* item, void* )
1594 {
1595 item->ClearFlags( MCT_SKIP_STRUCT );
1597 },
1599 };
1600
1601 BOARD_COMMIT tempCommit( m_frame );
1602
1604 IO_RELEASER<PCB_IO> pi( PCB_IO_MGR::FindPlugin( pluginType ) );
1605
1606 if( !pi || AppendBoard( *pi, designBlock->GetBoardFile(), designBlock.get(), &tempCommit, true ) != 0 )
1607 {
1608 clearFlags();
1609 outErr = _( "could not load the design block's layout" );
1610 return false;
1611 }
1612
1613 RULE_AREA dbRA;
1615 dbRA.m_generateEnabled = true;
1616
1617 brd->Visit(
1618 [&]( EDA_ITEM* item, void* )
1619 {
1620 if( !item->HasFlag( MCT_SKIP_STRUCT ) )
1621 {
1622 dbRA.m_designBlockItems.insert( item );
1623
1624 if( item->Type() == PCB_FOOTPRINT_T )
1625 dbRA.m_components.insert( static_cast<FOOTPRINT*>( item ) );
1626 }
1627
1629 },
1631
1632 if( dbRA.m_designBlockItems.empty() || dbRA.m_components.empty() )
1633 {
1634 tempCommit.Revert();
1635 clearFlags();
1636 outErr = _( "design block layout could not be loaded" );
1637 return false;
1638 }
1639
1640 dbRA.m_zone = new ZONE( brd );
1641 dbRA.m_zone->SetIsRuleArea( true );
1643 dbRA.m_zone->SetPlacementAreaEnabled( true );
1644 dbRA.m_zone->SetDoNotAllowZoneFills( false );
1645 dbRA.m_zone->SetDoNotAllowVias( false );
1646 dbRA.m_zone->SetDoNotAllowTracks( false );
1647 dbRA.m_zone->SetDoNotAllowPads( false );
1648 dbRA.m_zone->SetDoNotAllowFootprints( false );
1650 dbRA.m_zone->SetPlacementAreaSource( group->GetDesignBlockLibId().GetUniStringLibId() );
1652 dbRA.m_zone->AddPolygon( generateBoundingBox( dbRA.m_designBlockItems ) );
1653 dbRA.m_center = dbRA.m_zone->Outline()->COutline( 0 ).Centre();
1654
1655 RULE_AREA destRA;
1657
1658 for( EDA_ITEM* item : group->GetItems() )
1659 {
1660 if( item->Type() == PCB_FOOTPRINT_T )
1661 destRA.m_components.insert( static_cast<FOOTPRINT*>( item ) );
1662 }
1663
1664 if( destRA.m_components.empty() )
1665 {
1666 tempCommit.Revert();
1667 clearFlags();
1668 delete dbRA.m_zone;
1669 outErr = _( "group has no footprints" );
1670 return false;
1671 }
1672
1673 destRA.m_zone = new ZONE( brd );
1674 destRA.m_zone->SetZoneName( wxString::Format( wxT( "design-block-dest-%s" ),
1675 group->GetDesignBlockLibId().GetUniStringLibId() ) );
1676 destRA.m_zone->SetIsRuleArea( true );
1677 destRA.m_zone->SetLayerSet( LSET::AllCuMask() );
1678 destRA.m_zone->SetPlacementAreaEnabled( true );
1679 destRA.m_zone->SetDoNotAllowZoneFills( false );
1680 destRA.m_zone->SetDoNotAllowVias( false );
1681 destRA.m_zone->SetDoNotAllowTracks( false );
1682 destRA.m_zone->SetDoNotAllowPads( false );
1683 destRA.m_zone->SetDoNotAllowFootprints( false );
1685 destRA.m_zone->SetPlacementAreaSource( group->GetName() );
1687 destRA.m_zone->AddPolygon( generateBoundingBox( group->GetItems() ) );
1688 destRA.m_center = destRA.m_zone->Outline()->COutline( 0 ).Centre();
1689
1690 REPEAT_LAYOUT_OPTIONS options = { .m_copyRouting = true,
1691 .m_connectedRoutingOnly = false,
1692 .m_copyPlacement = true,
1693 .m_copyOtherItems = true,
1694 .m_groupItems = false,
1695 .m_includeLockedItems = true,
1696 .m_anchorFp = nullptr };
1697
1698 wxString repeatErr;
1699 int result = mct->RepeatLayout( aEvent, dbRA, destRA, options, &sharedCommit, &repeatErr );
1700
1701 tempCommit.Revert();
1702 clearFlags();
1703 delete dbRA.m_zone;
1704 delete destRA.m_zone;
1705
1706 if( result != 0 )
1707 {
1708 outErr = repeatErr.IsEmpty() ? _( "layout copy failed" ) : repeatErr;
1709 return false;
1710 }
1711
1712 return true;
1713 };
1714
1715 for( size_t i = 0; i < linkedGroups.size(); ++i )
1716 {
1717 PCB_GROUP* g = linkedGroups[i];
1718
1719 if( progress )
1720 {
1721 progress->SetCurrentProgress( static_cast<double>( i ) / linkedGroups.size() );
1722 progress->Report(
1723 wxString::Format( _( "Applying layout to group %zu of %zu..." ), i + 1, linkedGroups.size() ) );
1724
1725 if( !progress->KeepRefreshing() )
1726 {
1727 cancelled = true;
1728 break;
1729 }
1730 }
1731
1732 wxString err;
1733
1734 if( applyOneGroup( g, err ) )
1735 applied++;
1736 else
1737 failures.push_back( { g, err } );
1738 }
1739
1740 if( progress )
1741 progress->SetCurrentProgress( 1.0 );
1742
1743 if( cancelled )
1744 {
1745 sharedCommit.Revert();
1746 m_frame->ShowInfoBarMsg( _( "Apply design block layout cancelled." ), true );
1747 return 1;
1748 }
1749
1750 if( applied > 0 )
1751 {
1752 sharedCommit.Push( wxString::Format( _( "Apply design block layout to %d group(s)" ), applied ) );
1753 }
1754 else
1755 {
1756 sharedCommit.Revert();
1757 }
1758
1759 if( skippedNoLink > 0 || !failures.empty() || linkedGroups.size() > 1 )
1760 {
1761 wxString html;
1762
1763 html << wxT( "<p>" )
1764 << wxString::Format( _( "Applied design block layout to %d of %d group(s)." ), applied,
1765 (int) linkedGroups.size() )
1766 << wxT( "</p>" );
1767
1768 if( skippedNoLink > 0 )
1769 {
1770 html << wxT( "<p>" )
1771 << wxString::Format( _( "Skipped %d selected item(s) that are not groups linked to a "
1772 "design block." ),
1773 skippedNoLink )
1774 << wxT( "</p>" );
1775 }
1776
1777 if( !failures.empty() )
1778 {
1779 html << wxT( "<p>" ) << _( "The following groups could not be processed:" ) << wxT( "</p><ul>" );
1780
1781 for( const Failure& f : failures )
1782 {
1783 wxString name = f.group->GetName().IsEmpty() ? _( "(unnamed group)" ) : f.group->GetName();
1784 html << wxString::Format( wxT( "<li><b>%s</b>: %s</li>" ), name, f.reason );
1785 }
1786
1787 html << wxT( "</ul>" );
1788 }
1789
1790 HTML_MESSAGE_BOX dlg( m_frame, _( "Apply Design Block Layout" ) );
1791 dlg.SetDialogSizeInDU( 360, 220 );
1792 dlg.AddHTML_Text( html );
1793 dlg.ShowModal();
1794 }
1795
1796 return applied > 0 ? 0 : 1;
1797}
1798
1800{
1801 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
1802
1803 if( !editFrame )
1804 return 1;
1805
1806 // Need to have a group selected and it needs to have a linked design block
1807 PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
1809
1810 if( selection.Size() != 1 || selection[0]->Type() != PCB_GROUP_T )
1811 return 1;
1812
1813 PCB_GROUP* group = static_cast<PCB_GROUP*>( selection[0] );
1814
1815 if( !group->HasDesignBlockLink() )
1816 return 1;
1817
1818 // Get the associated design block
1819 DESIGN_BLOCK_PANE* designBlockPane = editFrame->GetDesignBlockPane();
1820 std::unique_ptr<DESIGN_BLOCK> designBlock( designBlockPane->GetDesignBlock( group->GetDesignBlockLibId(),
1821 true, true ) );
1822
1823 if( !designBlock )
1824 {
1825 wxString msg;
1826 msg.Printf( _( "Could not find design block %s." ), group->GetDesignBlockLibId().GetUniStringLibId() );
1827 m_frame->GetInfoBar()->ShowMessageFor( msg, 5000, wxICON_WARNING );
1828 return 1;
1829 }
1830
1831 if( designBlock->GetBoardFile().IsEmpty() )
1832 {
1833 wxString msg;
1834 msg.Printf( _( "Design block %s does not have a board file." ),
1835 group->GetDesignBlockLibId().GetUniStringLibId() );
1836 m_frame->GetInfoBar()->ShowMessageFor( msg, 5000, wxICON_WARNING );
1837 return 1;
1838 }
1839
1840
1842 IO_RELEASER<PCB_IO> pi( PCB_IO_MGR::FindPlugin( pluginType ) );
1843
1844 if( !pi )
1845 return 1;
1846
1847 if( aEvent.Parameter<bool*>() != nullptr )
1848 return AppendBoard( *pi, designBlock->GetBoardFile(), designBlock.get(),
1849 static_cast<BOARD_COMMIT*>( aEvent.Commit() ), *aEvent.Parameter<bool*>() );
1850 else
1851 return AppendBoard( *pi, designBlock->GetBoardFile(), designBlock.get() );
1852}
1853
1854
1856{
1857 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
1858
1859 if( !editFrame )
1860 return 1;
1861
1862 // Need to have a group selected and it needs to have a linked design block
1863 PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
1865
1866 if( selection.Size() != 1 || selection[0]->Type() != PCB_GROUP_T )
1867 return 1;
1868
1869 PCB_GROUP* group = static_cast<PCB_GROUP*>( selection[0] );
1870
1871 if( !group->HasDesignBlockLink() )
1872 return 1;
1873
1874 // Get the associated design block
1875 DESIGN_BLOCK_PANE* designBlockPane = editFrame->GetDesignBlockPane();
1876 std::unique_ptr<DESIGN_BLOCK> designBlock( designBlockPane->GetDesignBlock( group->GetDesignBlockLibId(),
1877 true, true ) );
1878
1879 if( !designBlock )
1880 {
1881 wxString msg;
1882 msg.Printf( _( "Could not find design block %s." ), group->GetDesignBlockLibId().GetUniStringLibId() );
1883 m_frame->GetInfoBar()->ShowMessageFor( msg, 5000, wxICON_WARNING );
1884 return 1;
1885 }
1886
1887 editFrame->GetDesignBlockPane()->SelectLibId( group->GetDesignBlockLibId() );
1888
1889 return m_toolMgr->RunAction( PCB_ACTIONS::updateDesignBlockFromSelection ) ? 1 : 0;
1890}
1891
1892
1893bool PCB_CONTROL::placeBoardItems( BOARD_COMMIT* aCommit, BOARD* aBoard, bool aAnchorAtOrigin,
1894 bool aReannotateDuplicates, bool aSkipMove )
1895{
1896 // items are new if the current board is not the board source
1897 bool isNew = board() != aBoard;
1898 std::vector<BOARD_ITEM*> items;
1899
1900 for( BOARD_ITEM* item : aBoard->GetItemSet() )
1901 {
1902 // Marker transfer is intentionally not part of append/paste item placement.
1903 if( item->Type() == PCB_MARKER_T )
1904 continue;
1905
1906 bool doCopy = ( item->GetFlags() & SKIP_STRUCT ) == 0;
1907
1908 item->ClearFlags( SKIP_STRUCT );
1909 item->SetFlags( isNew ? IS_NEW : 0 );
1910
1911 if( doCopy )
1912 items.push_back( item );
1913 }
1914
1915 if( isNew )
1916 aBoard->RemoveAll();
1917
1918 // Reparent before calling pruneItemLayers, as SetLayer can have a dependence on the
1919 // item's parent board being set correctly.
1920 if( isNew )
1921 {
1922 for( BOARD_ITEM* item : items )
1923 item->SetParent( board() );
1924 }
1925
1926 pruneItemLayers( items );
1927
1928 return placeBoardItems( aCommit, items, isNew, aAnchorAtOrigin, aReannotateDuplicates, aSkipMove );
1929}
1930
1931
1932bool PCB_CONTROL::placeBoardItems( BOARD_COMMIT* aCommit, std::vector<BOARD_ITEM*>& aItems, bool aIsNew,
1933 bool aAnchorAtOrigin, bool aReannotateDuplicates, bool aSkipMove )
1934{
1935 m_toolMgr->RunAction( ACTIONS::selectionClear );
1936
1937 PCB_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
1938
1939 std::vector<BOARD_ITEM*> itemsToSel;
1940 itemsToSel.reserve( aItems.size() );
1941
1942 for( BOARD_ITEM* item : aItems )
1943 {
1944 if( aIsNew )
1945 {
1946 item->ResetUuid();
1947
1948 item->RunOnChildren(
1949 []( BOARD_ITEM* aChild )
1950 {
1951 aChild->ResetUuid();
1952 },
1954
1955 // While BOARD_COMMIT::Push() will add any new items to the entered group,
1956 // we need to do it earlier so that the previews while moving are correct.
1957 if( PCB_GROUP* enteredGroup = selectionTool->GetEnteredGroup() )
1958 {
1959 if( item->IsGroupableType() && !item->GetParentGroup() )
1960 {
1961 aCommit->Modify( enteredGroup, nullptr, RECURSE_MODE::NO_RECURSE );
1962 enteredGroup->AddItem( item );
1963 }
1964 }
1965
1966 item->SetParent( board() );
1967 }
1968
1969 // Update item attributes if needed
1970 if( BaseType( item->Type() ) == PCB_DIMENSION_T )
1971 {
1972 static_cast<PCB_DIMENSION_BASE*>( item )->UpdateUnits();
1973 }
1974 else if( item->Type() == PCB_FOOTPRINT_T )
1975 {
1976 FOOTPRINT* footprint = static_cast<FOOTPRINT*>( item );
1977
1978 // Update the footprint path with the new KIID path if the footprint is new
1979 if( aIsNew )
1980 footprint->SetPath( KIID_PATH() );
1981
1982 for( BOARD_ITEM* dwg : footprint->GraphicalItems() )
1983 {
1984 if( BaseType( dwg->Type() ) == PCB_DIMENSION_T )
1985 static_cast<PCB_DIMENSION_BASE*>( dwg )->UpdateUnits();
1986 }
1987 }
1988
1989 // We only need to add the items that aren't inside a group currently selected
1990 // to the selection. If an item is inside a group and that group is selected,
1991 // then the selection tool will select it for us.
1992 if( !item->GetParentGroup() || !alg::contains( aItems, item->GetParentGroup()->AsEdaItem() ) )
1993 itemsToSel.push_back( item );
1994 }
1995
1996 // Select the items that should be selected
1997 EDA_ITEMS toSel( itemsToSel.begin(), itemsToSel.end() );
1998 m_toolMgr->RunAction<EDA_ITEMS*>( ACTIONS::selectItems, &toSel );
1999
2000 // Reannotate duplicate footprints (make sense only in board editor )
2001 if( aReannotateDuplicates && m_isBoardEditor )
2002 m_toolMgr->GetTool<BOARD_REANNOTATE_TOOL>()->ReannotateDuplicatesInSelection();
2003
2004 for( BOARD_ITEM* item : aItems )
2005 {
2006 if( aIsNew )
2007 aCommit->Add( item );
2008 else
2009 aCommit->Added( item );
2010 }
2011
2012 PCB_SELECTION& selection = selectionTool->GetSelection();
2013
2014 if( selection.Size() > 0 )
2015 {
2016 if( aAnchorAtOrigin )
2017 {
2018 selection.SetReferencePoint( VECTOR2I( 0, 0 ) );
2019 }
2020 else if( BOARD_ITEM* item = dynamic_cast<BOARD_ITEM*>( selection.GetTopLeftItem() ) )
2021 {
2022 selection.SetReferencePoint( item->GetPosition() );
2023 }
2024
2025 getViewControls()->SetCursorPosition( getViewControls()->GetMousePosition(), false );
2026
2027 m_toolMgr->ProcessEvent( EVENTS::SelectedEvent );
2028
2029 if( !aSkipMove )
2030 return m_toolMgr->RunSynchronousAction( PCB_ACTIONS::move, aCommit );
2031 }
2032
2033 return true;
2034}
2035
2036
2037int PCB_CONTROL::AppendBoard( PCB_IO& pi, const wxString& fileName, DESIGN_BLOCK* aDesignBlock, BOARD_COMMIT* aCommit,
2038 bool aSkipMove )
2039{
2040 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
2041
2042 if( !editFrame )
2043 return 1;
2044
2045 BOARD* brd = board();
2046
2047 if( !brd )
2048 return 1;
2049
2050 // Give ourselves a commit to work with if we weren't provided one
2051 std::unique_ptr<BOARD_COMMIT> tempCommit;
2052 BOARD_COMMIT* commit = aCommit;
2053
2054 if( !commit )
2055 {
2056 tempCommit = std::make_unique<BOARD_COMMIT>( editFrame );
2057 commit = tempCommit.get();
2058 }
2059
2060 // Mark existing items, in order to know what are the new items so we can select only
2061 // the new items after loading
2062 BOARD_ITEM_SET existingItems = brd->GetItemSet();
2063
2064 for( BOARD_ITEM* item : existingItems )
2065 item->SetFlags( SKIP_STRUCT );
2066
2067 auto clearSkipStructOnExistingItems =
2068 [&existingItems]()
2069 {
2070 for( BOARD_ITEM* item : existingItems )
2071 item->ClearFlags( SKIP_STRUCT );
2072 };
2073
2074 std::map<wxString, wxString> oldProperties = brd->GetProperties();
2075 std::map<wxString, wxString> newProperties;
2076
2077 PAGE_INFO oldPageInfo = brd->GetPageSettings();
2078 TITLE_BLOCK oldTitleBlock = brd->GetTitleBlock();
2079
2080 // Keep also the count of copper layers, to adjust if necessary
2081 int initialCopperLayerCount = brd->GetCopperLayerCount();
2082 LSET initialEnabledLayers = brd->GetEnabledLayers();
2083
2084 // Load the data
2085 try
2086 {
2087 std::map<std::string, UTF8> props;
2088
2089 // PCB_IO_EAGLE can use this info to center the BOARD, but it does not yet.
2090
2091 props["page_width"] = std::to_string( editFrame->GetPageSizeIU().x );
2092 props["page_height"] = std::to_string( editFrame->GetPageSizeIU().y );
2094
2096 [&]( wxString aTitle, int aIcon, wxString aMessage, wxString aAction ) -> bool
2097 {
2098 KIDIALOG dlg( editFrame, aMessage, aTitle, wxOK | wxCANCEL | aIcon );
2099
2100 if( !aAction.IsEmpty() )
2101 dlg.SetOKLabel( aAction );
2102
2103 dlg.DoNotShowCheckbox( aMessage, 0 );
2104
2105 return dlg.ShowModal() == wxID_OK;
2106 } );
2107
2108 WX_PROGRESS_REPORTER progressReporter( editFrame, _( "Load PCB" ), 1, PR_CAN_ABORT );
2109
2110 pi.SetProgressReporter( &progressReporter );
2111 pi.LoadBoard( fileName, brd, &props, nullptr );
2112 }
2113 catch( const IO_ERROR& ioe )
2114 {
2115 DisplayErrorMessage( editFrame, _( "Error loading board." ), ioe.What() );
2116 clearSkipStructOnExistingItems();
2117
2118 return 0;
2119 }
2120
2121 newProperties = brd->GetProperties();
2122
2123 for( const std::pair<const wxString, wxString>& prop : oldProperties )
2124 newProperties[prop.first] = prop.second;
2125
2126 brd->SetProperties( newProperties );
2127
2128 brd->SetPageSettings( oldPageInfo );
2129 brd->SetTitleBlock( oldTitleBlock );
2130
2131 // rebuild nets and ratsnest before any use of nets
2132 brd->BuildListOfNets();
2133 brd->SynchronizeNetsAndNetClasses( true );
2134 brd->BuildConnectivity();
2135
2136 // New appended items need to inherit the current global ratsnest state.
2137 // Existing items are marked SKIP_STRUCT and are handled elsewhere.
2138 const bool showGlobalRatsnest = displayOptions().m_ShowGlobalRatsnest;
2139
2140 for( BOARD_ITEM* item : brd->GetItemSet() )
2141 {
2142 if( item->GetFlags() & SKIP_STRUCT )
2143 continue;
2144
2145 if( BOARD_CONNECTED_ITEM* connectedItem = dynamic_cast<BOARD_CONNECTED_ITEM*>( item ) )
2146 connectedItem->SetLocalRatsnestVisible( showGlobalRatsnest );
2147
2148 if( item->Type() == PCB_FOOTPRINT_T )
2149 {
2150 for( PAD* pad : static_cast<FOOTPRINT*>( item )->Pads() )
2151 pad->SetLocalRatsnestVisible( showGlobalRatsnest );
2152 }
2153 }
2154
2155 // Synchronize layers
2156 // we should not ask PLUGINs to do these items:
2157 int copperLayerCount = brd->GetCopperLayerCount();
2158
2159 if( copperLayerCount > initialCopperLayerCount )
2160 brd->SetCopperLayerCount( copperLayerCount );
2161
2162 // Enable all used layers, and make them visible:
2163 LSET enabledLayers = brd->GetEnabledLayers();
2164 enabledLayers |= initialEnabledLayers;
2165 brd->SetEnabledLayers( enabledLayers );
2166 brd->SetVisibleLayers( enabledLayers );
2168
2169 int ret = 0;
2170
2171 bool placeAsGroup = false;
2172
2173 if( APP_SETTINGS_BASE* cfg = editFrame->config() )
2174 placeAsGroup = cfg->m_DesignBlockChooserPanel.place_as_group;
2175
2176 if( placeBoardItems( commit, brd, false, false /* Don't reannotate dupes on Append Board */, aSkipMove ) )
2177 {
2178 if( placeAsGroup )
2179 {
2180 PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
2182
2183 // Count items that would be added to the group
2184 int groupableCount = 0;
2185
2186 for( EDA_ITEM* eda_item : selection )
2187 {
2188 if( eda_item->IsBOARD_ITEM()
2189 && !static_cast<BOARD_ITEM*>( eda_item )->GetParentFootprint() )
2190 {
2191 groupableCount++;
2192 }
2193 }
2194
2195 if( groupableCount >= 2 )
2196 {
2197 PCB_GROUP* group = new PCB_GROUP( brd );
2198
2199 if( aDesignBlock )
2200 {
2201 group->SetName( aDesignBlock->GetLibId().GetLibItemName() );
2202 group->SetDesignBlockLibId( aDesignBlock->GetLibId() );
2203 }
2204 else
2205 {
2206 group->SetName( wxFileName( fileName ).GetName() );
2207 }
2208
2209 for( EDA_ITEM* eda_item : selection )
2210 {
2211 if( eda_item->IsBOARD_ITEM() )
2212 {
2213 if( static_cast<BOARD_ITEM*>( eda_item )->IsLocked() )
2214 group->SetLocked( true );
2215 }
2216 }
2217
2218 commit->Add( group );
2219
2220 for( EDA_ITEM* eda_item : selection )
2221 {
2222 if( eda_item->IsBOARD_ITEM()
2223 && !static_cast<BOARD_ITEM*>( eda_item )->GetParentFootprint() )
2224 {
2225 commit->Modify( eda_item );
2226 group->AddItem( eda_item );
2227 }
2228 }
2229
2230 selTool->ClearSelection();
2231 selTool->select( group );
2232
2234 m_frame->OnModify();
2235 m_frame->Refresh();
2236 }
2237 }
2238
2239 // If we were provided a commit, let the caller control when to push it
2240 if( !aCommit )
2241 commit->Push( aDesignBlock ? _( "Place Design Block" ) : _( "Append Board" ) );
2242
2243 editFrame->GetBoard()->BuildConnectivity();
2244 ret = 0;
2245 }
2246 else
2247 {
2248 // If we were provided a commit, let the caller control when to revert it
2249 if( !aCommit )
2250 commit->Revert();
2251
2252 ret = 1;
2253 }
2254
2255 // Refresh the UI for the updated board properties
2256 editFrame->GetAppearancePanel()->OnBoardChanged();
2257 clearSkipStructOnExistingItems();
2258
2259 return ret;
2260}
2261
2262
2263int PCB_CONTROL::Undo( const TOOL_EVENT& aEvent )
2264{
2265 PCB_BASE_EDIT_FRAME* editFrame = dynamic_cast<PCB_BASE_EDIT_FRAME*>( m_frame );
2266 wxCommandEvent dummy;
2267
2268 if( editFrame )
2269 editFrame->RestoreCopyFromUndoList( dummy );
2270
2271 return 0;
2272}
2273
2274
2275int PCB_CONTROL::Redo( const TOOL_EVENT& aEvent )
2276{
2277 PCB_BASE_EDIT_FRAME* editFrame = dynamic_cast<PCB_BASE_EDIT_FRAME*>( m_frame );
2278 wxCommandEvent dummy;
2279
2280 if( editFrame )
2281 editFrame->RestoreCopyFromRedoList( dummy );
2282
2283 return 0;
2284}
2285
2286
2288{
2289 MAGNETIC_SETTINGS& settings = m_isFootprintEditor ? m_frame->GetFootprintEditorSettings()->m_MagneticItems
2290 : m_frame->GetPcbNewSettings()->m_MagneticItems;
2291 bool& snapMode = settings.allLayers;
2292
2294 snapMode = false;
2295 else if( aEvent.IsAction( &PCB_ACTIONS::magneticSnapAllLayers ) )
2296 snapMode = true;
2297 else
2298 snapMode = !snapMode;
2299
2301
2302 return 0;
2303}
2304
2305
2307{
2308 if( !Pgm().GetCommonSettings()->m_Input.hotkey_feedback )
2309 return 0;
2310
2311 wxArrayString labels;
2312 labels.Add( _( "Active Layer" ) );
2313 labels.Add( _( "All Layers" ) );
2314
2315 if( !m_frame->GetHotkeyPopup() )
2316 m_frame->CreateHotkeyPopup();
2317
2318 HOTKEY_CYCLE_POPUP* popup = m_frame->GetHotkeyPopup();
2319
2320 MAGNETIC_SETTINGS& settings = m_isFootprintEditor ? m_frame->GetFootprintEditorSettings()->m_MagneticItems
2321 : m_frame->GetPcbNewSettings()->m_MagneticItems;
2322
2323 if( popup )
2324 popup->Popup( _( "Object Snapping" ), labels, static_cast<int>( settings.allLayers ) );
2325
2326 return 0;
2327}
2328
2329
2331{
2332 PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
2333 ROUTER_TOOL* routerTool = m_toolMgr->GetTool<ROUTER_TOOL>();
2334 PCB_SELECTION& selection = selTool->GetSelection();
2335 PCB_EDIT_FRAME* pcbFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
2336 std::shared_ptr<DRC_ENGINE> drcEngine = m_frame->GetBoard()->GetDesignSettings().m_DRCEngine;
2337 DRC_CONSTRAINT constraint;
2338
2339 std::vector<MSG_PANEL_ITEM> msgItems;
2340
2341 if( routerTool && routerTool->RoutingInProgress() )
2342 {
2343 routerTool->UpdateMessagePanel();
2344 return 0;
2345 }
2346
2347 if( !pcbFrame && !m_frame->GetModel() )
2348 return 0;
2349
2350 if( selection.Empty() )
2351 {
2352 if( !pcbFrame )
2353 {
2354 FOOTPRINT* fp = static_cast<FOOTPRINT*>( m_frame->GetModel() );
2355 fp->GetMsgPanelInfo( m_frame, msgItems );
2356 }
2357 else
2358 {
2359 m_frame->SetMsgPanel( m_frame->GetBoard() );
2360 }
2361 }
2362 else if( selection.GetSize() == 1 )
2363 {
2364 EDA_ITEM* item = selection.Front();
2365
2366 if( std::optional<wxString> uuid = GetMsgPanelDisplayUuid( item->m_Uuid ) )
2367 msgItems.emplace_back( _( "UUID" ), *uuid );
2368
2369 item->GetMsgPanelInfo( m_frame, msgItems );
2370
2371 PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( item );
2372 NETINFO_ITEM* net = track ? track->GetNet() : nullptr;
2373 NETINFO_ITEM* coupledNet = net ? m_frame->GetBoard()->DpCoupledNet( net ) : nullptr;
2374
2375 if( coupledNet )
2376 {
2377 SEG trackSeg( track->GetStart(), track->GetEnd() );
2378 PCB_TRACK* coupledItem = nullptr;
2379 SEG::ecoord closestDist_sq = VECTOR2I::ECOORD_MAX;
2380
2381 for( PCB_TRACK* candidate : m_frame->GetBoard()->Tracks() )
2382 {
2383 if( candidate->GetNet() != coupledNet )
2384 continue;
2385
2386 SEG::ecoord dist_sq = trackSeg.SquaredDistance( SEG( candidate->GetStart(), candidate->GetEnd() ) );
2387
2388 if( !coupledItem || dist_sq < closestDist_sq )
2389 {
2390 coupledItem = candidate;
2391 closestDist_sq = dist_sq;
2392 }
2393 }
2394
2395 constraint = drcEngine->EvalRules( DIFF_PAIR_GAP_CONSTRAINT, track, coupledItem, track->GetLayer() );
2396
2397 wxString msg = m_frame->MessageTextFromMinOptMax( constraint.Value() );
2398
2399 if( !msg.IsEmpty() )
2400 {
2401 msgItems.emplace_back( wxString::Format( _( "DP Gap Constraints: %s" ), msg ),
2402 wxString::Format( _( "(from %s)" ), constraint.GetName() ) );
2403 }
2404
2405 constraint = drcEngine->EvalRules( MAX_UNCOUPLED_CONSTRAINT, track, coupledItem, track->GetLayer() );
2406
2407 if( constraint.Value().HasMax() )
2408 {
2409 msg = m_frame->MessageTextFromValue( constraint.Value().Max() );
2410 msgItems.emplace_back( wxString::Format( _( "DP Max Uncoupled-length: %s" ), msg ),
2411 wxString::Format( _( "(from %s)" ), constraint.GetName() ) );
2412 }
2413 }
2414 }
2415 else if( pcbFrame && selection.GetSize() == 2 )
2416 {
2417 // Pair selection broken into multiple, optional data, starting with the selected item
2418 // names
2419
2420 BOARD_ITEM* a = dynamic_cast<BOARD_ITEM*>( selection[0] );
2421 BOARD_ITEM* b = dynamic_cast<BOARD_ITEM*>( selection[1] );
2422
2423 if( a && b )
2424 {
2425 msgItems.emplace_back( MSG_PANEL_ITEM( a->GetItemDescription( m_frame, false ),
2426 b->GetItemDescription( m_frame, false ) ) );
2427 }
2428
2429 BOARD_CONNECTED_ITEM* a_conn = dynamic_cast<BOARD_CONNECTED_ITEM*>( a );
2430 BOARD_CONNECTED_ITEM* b_conn = dynamic_cast<BOARD_CONNECTED_ITEM*>( b );
2431
2432 if( a_conn && b_conn )
2433 {
2434 LSET overlap = a_conn->GetLayerSet() & b_conn->GetLayerSet() & LSET::AllCuMask();
2435 int a_netcode = a_conn->GetNetCode();
2436 int b_netcode = b_conn->GetNetCode();
2437
2438 if( overlap.count() > 0 )
2439 {
2440 PCB_LAYER_ID layer = overlap.CuStack().front();
2441
2442 if( a_netcode != b_netcode || a_netcode < 0 || b_netcode < 0 )
2443 {
2444 constraint = drcEngine->EvalRules( CLEARANCE_CONSTRAINT, a, b, layer );
2445 msgItems.emplace_back( _( "Resolved Clearance" ),
2446 m_frame->MessageTextFromValue( constraint.m_Value.Min() ) );
2447 }
2448
2449 std::shared_ptr<SHAPE> a_shape( a_conn->GetEffectiveShape( layer ) );
2450 std::shared_ptr<SHAPE> b_shape( b_conn->GetEffectiveShape( layer ) );
2451
2452 int actual_clearance = a_shape->GetClearance( b_shape.get() );
2453
2454 if( actual_clearance > -1 && actual_clearance < std::numeric_limits<int>::max() )
2455 {
2456 msgItems.emplace_back( _( "Actual Clearance" ),
2457 m_frame->MessageTextFromValue( actual_clearance ) );
2458 }
2459 }
2460 }
2461
2462 if( a && b && ( a->HasHole() || b->HasHole() ) )
2463 {
2464 PCB_LAYER_ID active = m_frame->GetActiveLayer();
2466
2467 if( b->IsOnLayer( active ) && IsCopperLayer( active ) )
2468 layer = active;
2469 else if( b->HasHole() && a->IsOnLayer( active ) && IsCopperLayer( active ) )
2470 layer = active;
2471 else if( a->HasHole() && b->IsOnCopperLayer() )
2472 layer = b->GetLayer();
2473 else if( b->HasHole() && a->IsOnCopperLayer() )
2474 layer = a->GetLayer();
2475
2476 if( IsCopperLayer( layer ) )
2477 {
2478 int actual = std::numeric_limits<int>::max();
2479
2480 if( a->HasHole() && b->IsOnCopperLayer() )
2481 {
2482 std::shared_ptr<SHAPE_SEGMENT> hole = a->GetEffectiveHoleShape();
2483 std::shared_ptr<SHAPE> other( b->GetEffectiveShape( layer ) );
2484
2485 actual = std::min( actual, hole->GetClearance( other.get() ) );
2486 }
2487
2488 if( b->HasHole() && a->IsOnCopperLayer() )
2489 {
2490 std::shared_ptr<SHAPE_SEGMENT> hole = b->GetEffectiveHoleShape();
2491 std::shared_ptr<SHAPE> other( a->GetEffectiveShape( layer ) );
2492
2493 actual = std::min( actual, hole->GetClearance( other.get() ) );
2494 }
2495
2496 if( actual < std::numeric_limits<int>::max() )
2497 {
2498 constraint = drcEngine->EvalRules( HOLE_CLEARANCE_CONSTRAINT, a, b, layer );
2499 msgItems.emplace_back( _( "Resolved Hole Clearance" ),
2500 m_frame->MessageTextFromValue( constraint.m_Value.Min() ) );
2501
2502 if( actual > -1 && actual < std::numeric_limits<int>::max() )
2503 {
2504 msgItems.emplace_back( _( "Actual Hole Clearance" ),
2505 m_frame->MessageTextFromValue( actual ) );
2506 }
2507 }
2508 }
2509 }
2510
2511 if( a && b )
2512 {
2513 for( PCB_LAYER_ID edgeLayer : { Edge_Cuts, Margin } )
2514 {
2515 PCB_LAYER_ID active = m_frame->GetActiveLayer();
2517
2518 if( a->IsOnLayer( edgeLayer ) && b->Type() != PCB_FOOTPRINT_T )
2519 {
2520 if( b->IsOnLayer( active ) && IsCopperLayer( active ) )
2521 layer = active;
2522 else if( IsCopperLayer( b->GetLayer() ) )
2523 layer = b->GetLayer();
2524 }
2525 else if( b->IsOnLayer( edgeLayer ) && a->Type() != PCB_FOOTPRINT_T )
2526 {
2527 if( a->IsOnLayer( active ) && IsCopperLayer( active ) )
2528 layer = active;
2529 else if( IsCopperLayer( a->GetLayer() ) )
2530 layer = a->GetLayer();
2531 }
2532
2533 if( layer >= 0 )
2534 {
2535 constraint = drcEngine->EvalRules( EDGE_CLEARANCE_CONSTRAINT, a, b, layer );
2536
2537 if( edgeLayer == Edge_Cuts )
2538 {
2539 msgItems.emplace_back( _( "Resolved Edge Clearance" ),
2540 m_frame->MessageTextFromValue( constraint.m_Value.Min() ) );
2541 }
2542 else
2543 {
2544 msgItems.emplace_back( _( "Resolved Margin Clearance" ),
2545 m_frame->MessageTextFromValue( constraint.m_Value.Min() ) );
2546 }
2547 }
2548 }
2549 }
2550 }
2551
2552 if( selection.GetSize() )
2553 {
2554 if( msgItems.empty() )
2555 {
2556 // Count items by type
2557 std::map<KICAD_T, int> typeCounts;
2558
2559 for( EDA_ITEM* item : selection )
2560 typeCounts[item->Type()]++;
2561
2562 // Check if all items are the same type
2563 bool allSameType = ( typeCounts.size() == 1 );
2564 KICAD_T commonType = allSameType ? typeCounts.begin()->first : NOT_USED;
2565
2566 if( allSameType )
2567 {
2568 // Show "Type: N" for homogeneous selections
2569 wxString typeName = selection.Front()->GetFriendlyName();
2570 msgItems.emplace_back( typeName,
2571 wxString::Format( wxT( "%d" ), selection.GetSize() ) );
2572
2573 // For pads, show common properties
2574 if( commonType == PCB_PAD_T )
2575 {
2576 std::set<wxString> layers;
2577 std::set<PAD_SHAPE> shapes;
2578 std::set<VECTOR2I> sizes;
2579
2580 for( EDA_ITEM* item : selection )
2581 {
2582 PAD* pad = static_cast<PAD*>( item );
2583 layers.insert( pad->LayerMaskDescribe() );
2584 shapes.insert( pad->GetShape( PADSTACK::ALL_LAYERS ) );
2585 sizes.insert( pad->GetSize( PADSTACK::ALL_LAYERS ) );
2586 }
2587
2588 if( layers.size() == 1 )
2589 msgItems.emplace_back( _( "Layer" ), *layers.begin() );
2590
2591 if( shapes.size() == 1 )
2592 {
2593 PAD* firstPad = static_cast<PAD*>( selection.Front() );
2594 msgItems.emplace_back( _( "Pad Shape" ),
2595 firstPad->ShowPadShape( PADSTACK::ALL_LAYERS ) );
2596 }
2597
2598 if( sizes.size() == 1 )
2599 {
2600 VECTOR2I size = *sizes.begin();
2601 msgItems.emplace_back( _( "Pad Size" ),
2602 wxString::Format( wxT( "%s x %s" ),
2603 m_frame->MessageTextFromValue( size.x ),
2604 m_frame->MessageTextFromValue( size.y ) ) );
2605 }
2606 }
2607 }
2608 else
2609 {
2610 // Show type breakdown for mixed selections
2611 wxString breakdown;
2612
2613 for( const auto& [type, count] : typeCounts )
2614 {
2615 if( !breakdown.IsEmpty() )
2616 breakdown += wxT( ", " );
2617
2618 // Get friendly name from first item of this type
2619 wxString typeName;
2620
2621 for( EDA_ITEM* item : selection )
2622 {
2623 if( item->Type() == type )
2624 {
2625 typeName = item->GetFriendlyName();
2626 break;
2627 }
2628 }
2629
2630 breakdown += wxString::Format( wxT( "%s: %d" ), typeName, count );
2631 }
2632
2633 msgItems.emplace_back( _( "Selected Items" ),
2634 wxString::Format( wxT( "%d (%s)" ),
2635 selection.GetSize(), breakdown ) );
2636 }
2637
2638 if( m_isBoardEditor )
2639 {
2640 std::set<wxString> netNames;
2641 std::set<wxString> netClasses;
2642
2643 for( EDA_ITEM* item : selection )
2644 {
2645 if( BOARD_CONNECTED_ITEM* bci = dynamic_cast<BOARD_CONNECTED_ITEM*>( item ) )
2646 {
2647 if( !bci->GetNet() || bci->GetNetCode() <= NETINFO_LIST::UNCONNECTED )
2648 continue;
2649
2650 netNames.insert( UnescapeString( bci->GetNetname() ) );
2651 netClasses.insert( UnescapeString( bci->GetEffectiveNetClass()->GetHumanReadableName() ) );
2652
2653 if( netNames.size() > 1 && netClasses.size() > 1 )
2654 break;
2655 }
2656 }
2657
2658 if( netNames.size() == 1 )
2659 msgItems.emplace_back( _( "Net" ), *netNames.begin() );
2660
2661 if( netClasses.size() == 1 )
2662 msgItems.emplace_back( _( "Resolved Netclass" ), *netClasses.begin() );
2663 }
2664 }
2665
2666 if( selection.GetSize() >= 2 )
2667 {
2668 bool lengthValid = true;
2669 double selectedLength = 0;
2670
2671 // Lambda to accumulate track length if item is a track or arc, otherwise mark invalid
2672 std::function<void( EDA_ITEM* )> accumulateTrackLength;
2673
2674 accumulateTrackLength =
2675 [&]( EDA_ITEM* aItem )
2676 {
2677 if( aItem->Type() == PCB_TRACE_T || aItem->Type() == PCB_ARC_T )
2678 {
2679 selectedLength += static_cast<PCB_TRACK*>( aItem )->GetLength();
2680 }
2681 else if( aItem->Type() == PCB_VIA_T )
2682 {
2683 // zero 2D length
2684 }
2685 else if( aItem->Type() == PCB_SHAPE_T )
2686 {
2687 PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( aItem );
2688
2689 if( shape->GetShape() == SHAPE_T::SEGMENT
2690 || shape->GetShape() == SHAPE_T::ARC
2691 || shape->GetShape() == SHAPE_T::BEZIER )
2692 {
2693 selectedLength += shape->GetLength();
2694 }
2695 else
2696 {
2697 lengthValid = false;
2698 }
2699 }
2700 // Use dynamic_cast to include PCB_GENERATORs.
2701 else if( PCB_GROUP* group = dynamic_cast<PCB_GROUP*>( aItem ) )
2702 {
2703 group->RunOnChildren( accumulateTrackLength, RECURSE_MODE::RECURSE );
2704 }
2705 else
2706 {
2707 lengthValid = false;
2708 }
2709 };
2710
2711 for( EDA_ITEM* item : selection )
2712 {
2713 if( lengthValid )
2714 accumulateTrackLength( item );
2715 }
2716
2717 if( lengthValid )
2718 {
2719 msgItems.emplace_back( _( "Selected 2D Length" ),
2720 m_frame->MessageTextFromValue( selectedLength ) );
2721 }
2722 }
2723
2724 if( selection.GetSize() >= 2 && selection.GetSize() < 100 )
2725 {
2726 LSET enabledLayers = m_frame->GetBoard()->GetEnabledLayers();
2727 LSET enabledCopper = LSET::AllCuMask( m_frame->GetBoard()->GetCopperLayerCount() );
2728 bool areaValid = true;
2729 bool hasCopper = false;
2730 bool hasNonCopper = false;
2731
2732 std::map<PCB_LAYER_ID, SHAPE_POLY_SET> layerPolys;
2733 SHAPE_POLY_SET holes;
2734
2735 std::function<void( EDA_ITEM* )> accumulateArea;
2736
2737 accumulateArea =
2738 [&]( EDA_ITEM* aItem )
2739 {
2740 if( aItem->Type() == PCB_FOOTPRINT_T || aItem->Type() == PCB_MARKER_T )
2741 {
2742 areaValid = false;
2743 return;
2744 }
2745
2746 if( PCB_GROUP* group = dynamic_cast<PCB_GROUP*>( aItem ) )
2747 {
2748 group->RunOnChildren( accumulateArea, RECURSE_MODE::RECURSE );
2749 return;
2750 }
2751
2752 if( BOARD_ITEM* boardItem = dynamic_cast<BOARD_ITEM*>( aItem ) )
2753 {
2754 boardItem->RunOnChildren( accumulateArea, RECURSE_MODE::NO_RECURSE );
2755
2756 LSET itemLayers = boardItem->GetLayerSet() & enabledLayers;
2757
2758 for( PCB_LAYER_ID layer : itemLayers )
2759 {
2760 boardItem->TransformShapeToPolySet( layerPolys[layer], layer, 0,
2762
2763 if( enabledCopper.Contains( layer ) )
2764 hasCopper = true;
2765 else
2766 hasNonCopper = true;
2767 }
2768
2769 if( aItem->Type() == PCB_PAD_T && static_cast<PAD*>( aItem )->HasHole() )
2770 {
2771 static_cast<PAD*>( aItem )->TransformHoleToPolygon( holes, 0, ARC_LOW_DEF,
2772 ERROR_OUTSIDE );
2773 }
2774 else if( aItem->Type() == PCB_VIA_T )
2775 {
2776 PCB_VIA* via = static_cast<PCB_VIA*>( aItem );
2777 VECTOR2I center = via->GetPosition();
2778 int R = via->GetDrillValue() / 2;
2779
2781 }
2782 }
2783 };
2784
2785 for( EDA_ITEM* item : selection )
2786 {
2787 if( areaValid )
2788 accumulateArea( item );
2789 }
2790
2791 if( areaValid )
2792 {
2793 double area = 0.0;
2794
2795 for( auto& [layer, layerPoly] : layerPolys )
2796 {
2797 // Only subtract holes from copper layers
2798 if( enabledCopper.Contains( layer ) )
2799 layerPoly.BooleanSubtract( holes );
2800
2801 area += layerPoly.Area();
2802 }
2803
2804 // Choose appropriate label based on what layers are involved
2805 wxString areaLabel;
2806
2807 if( hasCopper && !hasNonCopper )
2808 areaLabel = _( "Selected 2D Copper Area" );
2809 else if( !hasCopper && hasNonCopper )
2810 areaLabel = _( "Selected 2D Area" );
2811 else
2812 areaLabel = _( "Selected 2D Total Area" );
2813
2814 msgItems.emplace_back( areaLabel,
2815 m_frame->MessageTextFromValue( area, true, EDA_DATA_TYPE::AREA ) );
2816 }
2817 }
2818 }
2819 else
2820 {
2821 m_frame->GetBoard()->GetMsgPanelInfo( m_frame, msgItems );
2822 }
2823
2824 m_frame->SetMsgPanel( msgItems );
2825
2826 // Update vertex editor if it exists
2827 PCB_BASE_EDIT_FRAME* editFrame = dynamic_cast<PCB_BASE_EDIT_FRAME*>( m_frame );
2828 if( editFrame )
2829 {
2830 BOARD_ITEM* selectedItem = ( selection.GetSize() == 1 ) ? dynamic_cast<BOARD_ITEM*>( selection.Front() )
2831 : nullptr;
2832 editFrame->UpdateVertexEditorSelection( selectedItem );
2833 }
2834
2835 return 0;
2836}
2837
2838
2840{
2841 wxFileName fileName = wxFileName( *aEvent.Parameter<wxString*>() );
2842
2843 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
2844
2845 if( !editFrame )
2846 return 1;
2847
2848 wxString filePath = fileName.GetFullPath();
2850 IO_RELEASER<PCB_IO> pi( PCB_IO_MGR::FindPlugin( pluginType ) );
2851
2852 if( !pi )
2853 return 1;
2854
2855 return AppendBoard( *pi, filePath );
2856}
2857
2858
2860{
2861 BOARD_COMMIT commit( this );
2862 EDA_UNITS displayUnit = m_frame->GetUserUnits();
2863 PCB_TABLE* table = Build_Board_Characteristics_Table( m_frame->GetBoard(), displayUnit );
2864 table->SetLayer( m_frame->GetActiveLayer() );
2865
2866 std::vector<BOARD_ITEM*> items;
2867 items.push_back( table );
2868
2869 if( placeBoardItems( &commit, items, true, true, false, false ) )
2870 commit.Push( _( "Place Board Characteristics" ) );
2871 else
2872 delete table;
2873
2874 return 0;
2875}
2876
2877
2879{
2880 BOARD_COMMIT commit( this );
2881 EDA_UNITS displayUnit = m_frame->GetUserUnits();
2882
2883 PCB_TABLE* table = Build_Board_Stackup_Table( m_frame->GetBoard(), displayUnit );
2884 table->SetLayer( m_frame->GetActiveLayer() );
2885
2886 std::vector<BOARD_ITEM*> items;
2887 items.push_back( table );
2888
2889 if( placeBoardItems( &commit, items, true, true, false, false ) )
2890 commit.Push( _( "Place Board Stackup Table" ) );
2891 else
2892 delete table;
2893
2894 return 0;
2895}
2896
2897
2899{
2900 PCB_DISPLAY_OPTIONS opts = m_frame->GetDisplayOptions();
2901 opts.m_FlipBoardView = !opts.m_FlipBoardView;
2902 m_frame->SetDisplayOptions( opts );
2903
2904 return 0;
2905}
2906
2907
2909{
2910 if( aItem->Type() == PCB_SHAPE_T )
2911 {
2912 static_cast<PCB_SHAPE*>( aItem )->UpdateHatching();
2913
2914 if( view() )
2915 view()->Update( aItem );
2916 }
2917}
2918
2919
2921{
2922 for( FOOTPRINT* footprint : board()->Footprints() )
2923 footprint->RunOnChildren( std::bind( &PCB_CONTROL::rehatchBoardItem, this, _1 ), NO_RECURSE );
2924
2925 for( BOARD_ITEM* item : board()->Drawings() )
2926 rehatchBoardItem( item );
2927
2928 return 0;
2929}
2930
2931
2933{
2934 BOARD* brd = board();
2935
2936 if( !brd )
2937 return 0;
2938
2939 PROJECT& prj = m_frame->Prj();
2941 FILENAME_RESOLVER* resolver = cache ? cache->GetResolver() : nullptr;
2942
2943 wxString workingPath = prj.GetProjectPath();
2944 std::vector<const EMBEDDED_FILES*> stack;
2945 stack.push_back( brd->GetEmbeddedFiles() );
2946
2947 BOARD_COMMIT commit( m_frame );
2948 int embeddedCount = 0;
2949
2950 for( FOOTPRINT* fp : brd->Footprints() )
2951 {
2952 bool fpModified = false;
2953
2954 for( FP_3DMODEL& model : fp->Models() )
2955 {
2956 if( model.m_Filename.StartsWith( FILEEXT::KiCadUriPrefix ) )
2957 continue;
2958
2959 wxString fullPath =
2960 resolver ? resolver->ResolvePath( model.m_Filename, workingPath, stack )
2961 : model.m_Filename;
2962
2963 wxFileName fname( fullPath );
2964 wxString ext = fname.GetExt().Upper();
2965
2966 if( fname.Exists() )
2967 {
2969 brd->GetEmbeddedFiles()->AddFile( fname, false ) )
2970 {
2971 model.m_Filename = file->GetLink();
2972 fpModified = true;
2973 embeddedCount++;
2974
2975 // Store STEP along with WRL for the OCCT(STEP) exporter.
2976 if( ext == "WRL" || ext == "WRZ" )
2977 {
2978 wxArrayString alts;
2979
2980 // Step files
2981 alts.Add( wxT( "stp" ) );
2982 alts.Add( wxT( "step" ) );
2983 alts.Add( wxT( "STP" ) );
2984 alts.Add( wxT( "STEP" ) );
2985 alts.Add( wxT( "Stp" ) );
2986 alts.Add( wxT( "Step" ) );
2987 alts.Add( wxT( "stpz" ) );
2988 alts.Add( wxT( "stpZ" ) );
2989 alts.Add( wxT( "STPZ" ) );
2990
2991 for( const auto& alt : alts )
2992 {
2993 wxFileName altFile( fname.GetPath(),
2994 fname.GetName() + wxT( "." ) + alt );
2995
2996 if( altFile.IsOk() && altFile.FileExists() )
2997 {
2998 brd->GetEmbeddedFiles()->AddFile( altFile, false );
2999 break;
3000 }
3001 }
3002 }
3003 }
3004 }
3005 }
3006
3007 if( fpModified )
3008 commit.Modify( fp );
3009 }
3010
3011 if( embeddedCount > 0 )
3012 {
3013 commit.Push( _( "Embed 3D Models" ) );
3014 wxString msg = wxString::Format( _( "%d 3D model(s) successfully embedded." ), embeddedCount );
3015 m_frame->GetInfoBar()->ShowMessageFor( msg, 5000 );
3016 }
3017
3018 return 0;
3019}
3020
3021
3022// clang-format off
3024{
3027 Go( &PCB_CONTROL::Print, ACTIONS::print.MakeEvent() );
3028
3029 // Footprint library actions
3034
3035 // Display modes
3052
3053 // Layer control
3091
3094
3095 // Grid control
3098
3099 Go( &PCB_CONTROL::Undo, ACTIONS::undo.MakeEvent() );
3100 Go( &PCB_CONTROL::Redo, ACTIONS::redo.MakeEvent() );
3101
3102 // Snapping control
3107
3108 // Miscellaneous
3111
3112 // Append control
3121
3122 Go( &PCB_CONTROL::Paste, ACTIONS::paste.MakeEvent() );
3124
3131
3132 // Add library by dropping file
3135}
3136// clang-format on
const char * name
@ ERROR_OUTSIDE
@ ERROR_INSIDE
constexpr int ARC_LOW_DEF
Definition base_units.h:140
std::set< BOARD_ITEM *, CompareByUuid > BOARD_ITEM_SET
Set of BOARD_ITEMs ordered by UUID.
Definition board.h:307
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:922
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:990
static TOOL_ACTION paste
Definition actions.h:80
static TOOL_ACTION addLibrary
Definition actions.h:56
static TOOL_ACTION pickerTool
Definition actions.h:253
static TOOL_ACTION gridResetOrigin
Definition actions.h:196
static TOOL_ACTION pasteSpecial
Definition actions.h:81
static TOOL_ACTION highContrastModeCycle
Definition actions.h:156
static TOOL_ACTION undo
Definition actions.h:75
static TOOL_ACTION highContrastMode
Definition actions.h:155
static TOOL_ACTION redo
Definition actions.h:76
static TOOL_ACTION deleteTool
Definition actions.h:86
static TOOL_ACTION selectionClear
Clear the current selection.
Definition actions.h:224
static TOOL_ACTION print
Definition actions.h:64
static TOOL_ACTION newLibrary
Definition actions.h:55
static TOOL_ACTION gridSetOrigin
Definition actions.h:195
static TOOL_ACTION ddAddLibrary
Definition actions.h:67
static TOOL_ACTION selectItems
Select a list of items (specified as the event parameter)
Definition actions.h:232
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
APP_SETTINGS_BASE is a settings class that should be derived for each standalone KiCad application.
virtual void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Execute the changes.
virtual void Revert() override
Revert the commit by restoring the modified items state.
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
NETINFO_ITEM * GetNet() const
Return #NET_INFO object for a given item.
void SetGridOrigin(const VECTOR2I &aOrigin)
BOARD_STACKUP & GetStackupDescriptor()
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:84
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition board_item.h:268
virtual bool IsOnLayer(PCB_LAYER_ID aLayer) const
Test to see if this object is on the given layer.
Definition board_item.h:350
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:288
void ResetUuid()
Definition board_item.h:248
virtual bool IsOnCopperLayer() const
Definition board_item.h:175
virtual std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape() const
virtual bool HasHole() const
Definition board_item.h:180
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:323
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:2458
EMBEDDED_FILES * GetEmbeddedFiles() override
Definition board.cpp:3365
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:1018
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:3469
void BuildListOfNets()
Definition board.h:967
const std::vector< BOARD_CONNECTED_ITEM * > AllConnectedItems()
Definition board.cpp:3434
const PAGE_INFO & GetPageSettings() const
Definition board.h:807
void SetProperties(const std::map< wxString, wxString > &aProps)
Definition board.h:395
const GROUPS & Groups() const
The groups must maintain the following invariants.
Definition board.h:390
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:203
void SynchronizeNetsAndNetClasses(bool aResetTrackAndViaSizes)
Copy NETCLASS info to each NET, based on NET membership in a NETCLASS.
Definition board.cpp:2956
FOOTPRINT * GetFirstFootprint() const
Get the first footprint on the board or nullptr.
Definition board.h:524
TITLE_BLOCK & GetTitleBlock()
Definition board.h:813
int GetCopperLayerCount() const
Definition board.cpp:937
const std::map< wxString, wxString > & GetProperties() const
Definition board.h:394
const FOOTPRINTS & Footprints() const
Definition board.h:364
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:1490
const BOARD_ITEM_SET GetItemSet()
Definition board.cpp:3838
void SetPageSettings(const PAGE_INFO &aPageSettings)
Definition board.h:808
void SetCopperLayerCount(int aCount)
Definition board.cpp:943
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:992
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition board.cpp:1101
const LSET & GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition board.cpp:986
void SetEnabledLayers(const LSET &aLayerMask)
A proxy function that calls the correspondent function in m_BoardSettings.
Definition board.cpp:1006
void SetTitleBlock(const TITLE_BLOCK &aTitleBlock)
Definition board.h:815
const DRAWINGS & Drawings() const
Definition board.h:366
BOARD_ITEM * Parse()
int GetCount() const
Return the number of objects in the list.
Definition collector.h:83
void Remove(int aIndex)
Remove the item at aIndex (first position is 0).
Definition collector.h:111
int m_Threshold
Definition collector.h:236
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:84
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:106
COMMIT & Add(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Add a new item to the model.
Definition commit.h:78
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
int ShowModal() override
wxString GetName() const
Definition drc_rule.h:208
MINOPTMAX< int > & Value()
Definition drc_rule.h:201
MINOPTMAX< int > m_Value
Definition drc_rule.h:244
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...
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:46
bool HasDesignBlockLink() const
Definition eda_group.h:75
void RemoveItem(EDA_ITEM *aItem)
Remove item from group.
Definition eda_group.cpp:81
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:100
virtual void SetPosition(const VECTOR2I &aPos)
Definition eda_item.h:287
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition eda_item.h:156
virtual wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const
Return a user-visible description string of this item.
Definition eda_item.cpp:173
const KIID m_Uuid
Definition eda_item.h:535
virtual EDA_GROUP * GetParentGroup() const
Definition eda_item.h:118
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:112
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition eda_item.h:158
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:234
bool HasFlag(EDA_ITEM_FLAGS aFlag) const
Definition eda_item.h:160
virtual void SetParent(EDA_ITEM *aParent)
Definition eda_item.cpp:93
SHAPE_T GetShape() const
Definition eda_shape.h:189
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:56
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:347
static const TOOL_EVENT SelectedEvent
Definition actions.h:345
static const TOOL_EVENT SelectedItemsModified
Selected items were moved, this can be very high frequency on the canvas, use with care.
Definition actions.h:352
static const TOOL_EVENT PointSelectedEvent
Definition actions.h:344
static const TOOL_EVENT ContrastModeChangedByKeyEvent
Definition actions.h:366
static const TOOL_EVENT ConnectivityChangedEvent
Selected item had a property changed (except movement)
Definition actions.h:349
static const TOOL_EVENT UnselectedEvent
Definition actions.h:346
Provide an extensible class to resolve 3D model paths.
Component library viewer main window.
EDA_ANGLE GetOrientation() const
Definition footprint.h:408
ZONES & Zones()
Definition footprint.h:383
std::deque< PAD * > & Pads()
Definition footprint.h:377
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:1342
void SetReference(const wxString &aReference)
Definition footprint.h:835
bool IsLocked() const override
Definition footprint.h:622
void ClearTransientComponentClassNames()
Remove the transient component class names.
Definition footprint.h:1348
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:386
void GetFields(std::vector< PCB_FIELD * > &aVector, bool aVisibleOnly) const
Populate a std::vector with PCB_TEXTs.
DRAWINGS & GraphicalItems()
Definition footprint.h:380
A general implementation of a COLLECTORS_GUIDE.
Definition collectors.h:324
Used when the right click button is pressed, or when the select tool is in effect.
Definition collectors.h:207
static const std::vector< KICAD_T > BoardLevelItems
A scan list for all primary board items, omitting items which are subordinate to a FOOTPRINT,...
Definition collectors.h:69
static const std::vector< KICAD_T > AllBoardItems
A scan list for all editable board items.
Definition collectors.h:41
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:107
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:42
void DoNotShowCheckbox(wxString file, int line)
Shows the 'do not show again' checkbox.
Definition kidialog.cpp:55
int ShowModal() override
Definition kidialog.cpp:93
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:105
COLOR4D & Darken(double aFactor)
Makes the color darker by a given factor.
Definition color4d.h:227
COLOR4D & Brighten(double aFactor)
Makes the color brighter by a given factor.
Definition color4d.h:210
double a
Alpha component.
Definition color4d.h:396
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:91
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:102
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition view.h:67
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition view.cpp:304
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition view.cpp:408
GAL * GetGAL() const
Return the GAL this view is using to draw graphical primitives.
Definition view.h:211
void MarkDirty()
Force redraw of view on the next rendering.
Definition view.h:681
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:47
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:49
bool IsValid() const
Check if this LID_ID is valid.
Definition lib_id.h:172
wxString GetUniStringLibId() const
Definition lib_id.h:148
const UTF8 & GetLibItemName() const
Definition lib_id.h:102
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:608
LSEQ UIOrder() const
Return the copper, technical and user layers in the order shown in layer widget.
Definition lset.cpp:743
LSEQ CuStack() const
Return a sequence of copper layers in starting from the front/top and extending to the back/bottom.
Definition lset.cpp:263
static LSET AllCuMask(int aCuLayerCount)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition lset.cpp:599
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:33
bool HasMax() const
Definition minoptmax.h:38
T Max() const
Definition minoptmax.h:34
EDA_MSG_PANEL items for displaying messages.
Definition msgpanel.h:54
int RepeatLayout(const TOOL_EVENT &aEvent, ZONE *aRefZone)
Handle the data for a net.
Definition netinfo.h:50
static const int UNCONNECTED
Constant that holds the "unconnected net" number (typically 0) all items "connected" to this net are ...
Definition netinfo.h:260
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:268
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:65
static wxString ShowPadShape(PAD_SHAPE aShape)
Definition pad.cpp:2176
bool HasHole() const override
Definition pad.h:117
Describe the page size and margins of a paper page on which to eventually print or plot.
Definition page_info.h:79
static TOOL_ACTION layerToggle
static TOOL_ACTION layerInner12
static TOOL_ACTION nextFootprint
static TOOL_ACTION layerInner8
static TOOL_ACTION zoneDisplayToggle
static TOOL_ACTION previousFootprint
static TOOL_ACTION layerInner3
static TOOL_ACTION layerPrev
static TOOL_ACTION showRatsnest
static TOOL_ACTION zoneFillAll
static TOOL_ACTION layerInner2
static TOOL_ACTION magneticSnapAllLayers
static TOOL_ACTION collect3DModels
static TOOL_ACTION saveToLinkedDesignBlock
static TOOL_ACTION ddAppendBoard
Drag and drop.
static TOOL_ACTION layerInner25
static TOOL_ACTION magneticSnapActiveLayer
Snapping controls.
static TOOL_ACTION layerAlphaDec
static TOOL_ACTION zoneDisplayFilled
static TOOL_ACTION layerInner24
static TOOL_ACTION viaDisplayMode
static TOOL_ACTION layerInner29
static TOOL_ACTION placeCharacteristics
static TOOL_ACTION layerInner11
static TOOL_ACTION layerAlphaInc
static TOOL_ACTION layerPairPresetsCycle
static TOOL_ACTION layerInner16
static TOOL_ACTION layerInner26
static TOOL_ACTION layerInner18
static TOOL_ACTION layerInner14
static TOOL_ACTION trackDisplayMode
static TOOL_ACTION magneticSnapToggle
static TOOL_ACTION layerInner6
static TOOL_ACTION applyDesignBlockLayout
static TOOL_ACTION ddImportFootprint
static TOOL_ACTION zoneDisplayTriangulated
static TOOL_ACTION rehatchShapes
static TOOL_ACTION layerInner22
static TOOL_ACTION placeDesignBlock
static TOOL_ACTION layerInner5
static TOOL_ACTION zoneDisplayFractured
static TOOL_ACTION ratsnestModeCycle
static TOOL_ACTION layerInner20
static TOOL_ACTION layerInner7
static TOOL_ACTION layerInner27
static TOOL_ACTION loadFpFromBoard
static TOOL_ACTION appendBoard
static TOOL_ACTION netColorModeCycle
static TOOL_ACTION layerInner1
static TOOL_ACTION layerInner10
static TOOL_ACTION layerInner15
static TOOL_ACTION layerInner17
static TOOL_ACTION flipBoard
static TOOL_ACTION layerBottom
static TOOL_ACTION zoneDisplayOutline
static TOOL_ACTION ratsnestLineMode
static TOOL_ACTION layerInner19
static TOOL_ACTION layerInner9
static TOOL_ACTION move
move or drag an item
static TOOL_ACTION layerInner30
static TOOL_ACTION layerTop
static TOOL_ACTION updateDesignBlockFromSelection
static TOOL_ACTION layerInner4
static TOOL_ACTION layerInner13
static TOOL_ACTION layerInner21
static TOOL_ACTION saveFpToBoard
static TOOL_ACTION layerNext
static TOOL_ACTION placeLinkedDesignBlock
static TOOL_ACTION placeStackup
static TOOL_ACTION layerInner23
static TOOL_ACTION layerInner28
Common, abstract interface for edit frames.
void RestoreCopyFromUndoList(wxCommandEvent &aEvent)
Undo the last edit:
APPEARANCE_CONTROLS * GetAppearancePanel()
void RestoreCopyFromRedoList(wxCommandEvent &aEvent)
Redo the last edit:
void UpdateVertexEditorSelection(BOARD_ITEM *aItem)
Base PCB main window class for Pcbnew, Gerbview, and CvPcb footprint viewer.
const VECTOR2I GetPageSizeIU() const override
Works off of GetPageSettings() to return the size of the paper page in the internal units of this par...
void OnModify() override
Must be called after a change in order to set the "modify" flag and update other data structures and ...
BOARD * GetBoard() const
virtual BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Return the BOARD_DESIGN_SETTINGS for the open project.
int RehatchShapes(const TOOL_EVENT &aEvent)
void setTransitions() override
< Sets up handlers for various events.
int AppendBoardFromFile(const TOOL_EVENT &aEvent)
int AddLibrary(const TOOL_EVENT &aEvent)
int DdAppendBoard(const TOOL_EVENT &aEvent)
int LoadFpFromBoard(const TOOL_EVENT &aEvent)
int SaveToLinkedDesignBlock(const TOOL_EVENT &aEvent)
int DdImportFootprint(const TOOL_EVENT &aEvent)
int SnapModeFeedback(const TOOL_EVENT &aEvent)
int NetColorModeCycle(const TOOL_EVENT &aEvent)
int SaveFpToBoard(const TOOL_EVENT &aEvent)
int RatsnestModeCycle(const TOOL_EVENT &aEvent)
int TrackDisplayMode(const TOOL_EVENT &aEvent)
int DdAddLibrary(const TOOL_EVENT &aEvent)
int Redo(const TOOL_EVENT &aEvent)
int PlaceLinkedDesignBlock(const TOOL_EVENT &aEvent)
bool placeBoardItems(BOARD_COMMIT *aCommit, std::vector< BOARD_ITEM * > &aItems, bool aIsNew, bool aAnchorAtOrigin, bool aReannotateDuplicates, bool aSkipMove)
Add and select or just select for move/place command a list of board items.
int LayerPresetFeedback(const TOOL_EVENT &aEvent)
int UpdateMessagePanel(const TOOL_EVENT &aEvent)
int LayerAlphaDec(const TOOL_EVENT &aEvent)
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)
void rehatchBoardItem(BOARD_ITEM *aItem)
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:53
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:56
@ KICAD_SEXP
S-expression Pcbnew file format.
Definition pcb_io_mgr.h:58
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:79
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:109
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:74
Class that manages the presentation of PCB layers in a PCB frame.
wxString getLayerPairName(const LAYER_PAIR &aPair) const
Definition sel_layer.cpp:89
Generic tool for picking an item.
PCB_LAYER_ID m_Route_Layer_TOP
Definition pcb_screen.h:43
PCB_LAYER_ID m_Route_Layer_BOTTOM
Definition pcb_screen.h:44
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.
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:97
const VECTOR2I & GetEnd() const
Definition pcb_track.h:94
virtual COMMON_SETTINGS * GetCommonSettings() const
Definition pgm_base.cpp:541
void SetMotionHandler(MOTION_HANDLER aHandler)
Set a handler for mouse motion.
Definition picker_tool.h:92
void SetClickHandler(CLICK_HANDLER aHandler)
Set a handler for mouse click event.
Definition picker_tool.h:81
void SetSnapping(bool aSnap)
Definition picker_tool.h:66
void SetCursor(KICURSOR aCursor)
Definition picker_tool.h:64
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:66
virtual const wxString GetProjectPath() const
Return the full path of the project.
Definition project.cpp:187
Cache for storing the 3D shapes.
Definition 3d_cache.h:57
FILENAME_RESOLVER * GetResolver() noexcept
Definition 3d_cache.cpp:545
Definition seg.h:42
ecoord SquaredDistance(const SEG &aSeg) const
Definition seg.cpp:80
VECTOR2I::extended_type ecoord
Definition seg.h:44
void BrightenItem(EDA_ITEM *aItem)
void UnbrightenItem(EDA_ITEM *aItem)
virtual void Add(EDA_ITEM *aItem)
Definition selection.cpp:42
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:234
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:41
T * getEditFrame() const
Return the application window object, casted to requested user type.
Definition tool_base.h:186
const std::string & GetName() const
Return the name of the tool.
Definition tool_base.h:136
KIGFX::VIEW_CONTROLS * getViewControls() const
Return the instance of VIEW_CONTROLS object used in the application.
Definition tool_base.cpp:44
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:38
RESET_REASON
Determine the reason of reset for a tool.
Definition tool_base.h:78
@ REDRAW
Full drawing refresh.
Definition tool_base.h:83
@ MODEL_RELOAD
Model changes (the sheet for a schematic)
Definition tool_base.h:80
@ GAL_SWITCH
Rendering engine changes.
Definition tool_base.h:82
Generic, UI-independent tool event.
Definition tool_event.h:171
COMMIT * Commit() const
Definition tool_event.h:283
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:473
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:76
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:74
void SetDoNotAllowPads(bool aEnable)
Definition zone.h:821
void AddPolygon(std::vector< VECTOR2I > &aPolygon)
Add a polygon to the zone outline.
Definition zone.cpp:1263
void SetPlacementAreaSource(const wxString &aSource)
Definition zone.h:808
void SetPlacementAreaSourceType(PLACEMENT_SOURCE_T aType)
Definition zone.h:810
SHAPE_POLY_SET * Outline()
Definition zone.h:422
void SetHatchStyle(ZONE_BORDER_DISPLAY_STYLE aStyle)
Definition zone.h:677
void SetIsRuleArea(bool aEnable)
Definition zone.h:803
void SetDoNotAllowTracks(bool aEnable)
Definition zone.h:820
void SetLayerSet(const LSET &aLayerSet) override
Definition zone.cpp:628
void SetDoNotAllowVias(bool aEnable)
Definition zone.h:819
void SetDoNotAllowFootprints(bool aEnable)
Definition zone.h:822
void SetDoNotAllowZoneFills(bool aEnable)
Definition zone.h:818
void SetZoneName(const wxString &aName)
Definition zone.h:165
void SetPlacementAreaEnabled(bool aEnabled)
Definition zone.h:805
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:278
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition confirm.cpp:221
void DisplayError(wxWindow *aParent, const wxString &aText)
Display an error or warning message box with aMessage.
Definition confirm.cpp:196
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:54
@ PLACE
Definition cursors.h:98
@ ARROW
Definition cursors.h:46
#define ALPHA_MAX
@ DIFF_PAIR_GAP_CONSTRAINT
Definition drc_rule.h:82
@ EDGE_CLEARANCE_CONSTRAINT
Definition drc_rule.h:59
@ CLEARANCE_CONSTRAINT
Definition drc_rule.h:55
@ MAX_UNCOUPLED_CONSTRAINT
Definition drc_rule.h:83
@ HOLE_CLEARANCE_CONSTRAINT
Definition drc_rule.h:57
#define _(s)
Declaration of the eda_3d_viewer class.
@ RECURSE
Definition eda_item.h:53
@ NO_RECURSE
Definition eda_item.h:54
#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:50
EDA_UNITS
Definition eda_units.h:48
static FILENAME_RESOLVER * resolver
@ FRAME_PCB_EDITOR
Definition frame_type.h:42
@ FRAME_FOOTPRINT_VIEWER
Definition frame_type.h:45
@ FRAME_FOOTPRINT_EDITOR
Definition frame_type.h:43
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:856
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition layer_ids.h:679
@ LAYER_RATSNEST
Definition layer_ids.h:253
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:60
@ Edge_Cuts
Definition layer_ids.h:112
@ B_Cu
Definition layer_ids.h:65
@ Margin
Definition layer_ids.h:113
@ UNDEFINED_LAYER
Definition layer_ids.h:61
@ F_Cu
Definition layer_ids.h:64
#define ZONE_LAYER_FOR(boardLayer)
Definition layer_ids.h:370
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:220
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:58
wxPoint GetMousePosition()
Returns the mouse position in screen coordinates.
Definition wxgtk/ui.cpp:766
constexpr char APPEND_PRESERVE_DESTINATION_STACKUP[]
Definition pcb_io.h:47
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
Definition kicad_algo.h:100
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
KIBIS_MODEL * model
std::vector< std::vector< std::string > > table
VECTOR2I center
int actual
wxString result
Test unit parsing edge cases and error handling.
constexpr KICAD_T BaseType(const KICAD_T aType)
Return the underlying type of the given type.
Definition typeinfo.h:260
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition typeinfo.h:75
@ PCB_T
Definition typeinfo.h:79
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition typeinfo.h:85
@ PCB_DIM_ORTHOGONAL_T
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
Definition typeinfo.h:103
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition typeinfo.h:100
@ PCB_GENERATOR_T
class PCB_GENERATOR, generator on a layer
Definition typeinfo.h:88
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:94
@ PCB_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
Definition typeinfo.h:101
@ PCB_GROUP_T
class PCB_GROUP, a set of BOARD_ITEMs
Definition typeinfo.h:108
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
Definition typeinfo.h:90
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition typeinfo.h:89
@ NOT_USED
the 3d code uses this value
Definition typeinfo.h:76
@ PCB_MARKER_T
class PCB_MARKER, a marker used to show something
Definition typeinfo.h:96
@ PCB_BARCODE_T
class PCB_BARCODE, a barcode (graphic item)
Definition typeinfo.h:98
@ PCB_TABLECELL_T
class PCB_TABLECELL, PCB_TEXTBOX for use in tables
Definition typeinfo.h:92
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
Definition typeinfo.h:83
@ PCB_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
Definition typeinfo.h:99
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition typeinfo.h:84
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition typeinfo.h:95
@ PCB_DIMENSION_T
class PCB_DIMENSION_BASE: abstract dimension meta-type
Definition typeinfo.h:97
@ PCB_TABLE_T
class PCB_TABLE, table of PCB_TABLECELLs
Definition typeinfo.h:91
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition typeinfo.h:93
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
Definition typeinfo.h:102
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:687
VECTOR2< double > VECTOR2D
Definition vector2d.h:686
Definition of file extensions used in Kicad.
#define PR_CAN_ABORT