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