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