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