KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pcb_control.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2014-2016 CERN
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 * @author Maciej Suminski <[email protected]>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
26#include "pcb_control.h"
28
29#include <kiplatform/ui.h>
30#include <tools/edit_tool.h>
32#include <router/router_tool.h>
33#include <pgm_base.h>
34#include <tools/pcb_actions.h>
39#include <board_commit.h>
40#include <board.h>
42#include <board_item.h>
44#include <clipboard.h>
45#include <design_block.h>
47#include <pcb_dimension.h>
51#include <footprint.h>
52#include <layer_pairs.h>
53#include <pcb_group.h>
55#include <pcb_reference_image.h>
56#include <pcb_textbox.h>
57#include <pcb_track.h>
58#include <pcb_generator.h>
59#include <project_pcb.h>
61#include <filename_resolver.h>
62#include <3d_cache/3d_cache.h>
63#include <embedded_files.h>
64#include <wx/filename.h>
65#include <zone.h>
66#include <confirm.h>
67#include <kidialog.h>
69#include <core/kicad_algo.h>
71#include <kicad_clipboard.h>
72#include <origin_viewitem.h>
73#include <pcb_edit_frame.h>
74#include <pcb_painter.h>
76#include <string>
77#include <tool/tool_manager.h>
85#include <widgets/wx_infobar.h>
86#include <wx/hyperlink.h>
87
88
89using namespace std::placeholders;
90
91
92// files.cpp
93extern bool AskLoadBoardFileName( PCB_EDIT_FRAME* aParent, wxString* aFileName, int aCtl = 0 );
94
95
97 PCB_TOOL_BASE( "pcbnew.Control" ),
98 m_frame( nullptr ),
99 m_pickerItem( nullptr )
100{
102}
103
104
108
109
111{
113
114 if( aReason == MODEL_RELOAD || aReason == GAL_SWITCH || aReason == REDRAW )
115 {
116 m_gridOrigin->SetPosition( board()->GetDesignSettings().GetGridOrigin() );
117
118 double backgroundBrightness = m_frame->GetCanvas()->GetGAL()->GetClearColor().GetBrightness();
119 COLOR4D color = m_frame->GetGridColor();
120
121 if( backgroundBrightness > 0.5 )
122 color.Darken( 0.25 );
123 else
124 color.Brighten( 0.25 );
125
126 m_gridOrigin->SetColor( color );
127
128 getView()->Remove( m_gridOrigin.get() );
129 getView()->Add( m_gridOrigin.get() );
130 }
131}
132
133
135{
136 if( m_frame->IsType( FRAME_FOOTPRINT_EDITOR ) || m_frame->IsType( FRAME_PCB_EDITOR ) )
137 {
138 if( aEvent.IsAction( &ACTIONS::newLibrary ) )
139 static_cast<PCB_BASE_EDIT_FRAME*>( m_frame )->CreateNewLibrary( _( "New Footprint Library" ) );
140 else if( aEvent.IsAction( &ACTIONS::addLibrary ) )
141 static_cast<PCB_BASE_EDIT_FRAME*>( m_frame )->AddLibrary( _( "Add Footprint Library" ) );
142 }
143
144 return 0;
145}
146
147
149{
150 if( m_frame->IsType( FRAME_FOOTPRINT_EDITOR ) )
151 static_cast<FOOTPRINT_EDIT_FRAME*>( m_frame )->LoadFootprintFromBoard( nullptr );
152
153 return 0;
154}
155
156
158{
159 if( m_frame->IsType( FRAME_FOOTPRINT_EDITOR ) )
160 static_cast<FOOTPRINT_EDIT_FRAME*>( m_frame )->SaveFootprintToBoard( true );
161 else if( m_frame->IsType( FRAME_FOOTPRINT_VIEWER ) )
162 static_cast<FOOTPRINT_VIEWER_FRAME*>( m_frame )->AddFootprintToPCB();
163
164 return 0;
165}
166
167
169{
170 const wxString fn = *aEvent.Parameter<wxString*>();
171 static_cast<PCB_BASE_EDIT_FRAME*>( m_frame )->AddLibrary( _( "Add Footprint Library" ), fn,
173 return 0;
174}
175
176
178{
179 const wxString fn = *aEvent.Parameter<wxString*>();
180 static_cast<FOOTPRINT_EDIT_FRAME*>( m_frame )->ImportFootprint( fn );
181 m_frame->Zoom_Automatique( false );
182 return 0;
183}
184
185
187{
188 if( m_frame->IsType( FRAME_FOOTPRINT_VIEWER ) )
189 static_cast<FOOTPRINT_VIEWER_FRAME*>( m_frame )->SelectAndViewFootprint( aEvent.Parameter<FPVIEWER_CONSTANTS>() );
190
191 return 0;
192}
193
194
195int PCB_CONTROL::Quit( const TOOL_EVENT& aEvent )
196{
197 m_frame->Close( false );
198 return 0;
199}
200
201
202template<class T> void Flip( T& aValue )
203{
204 aValue = !aValue;
205}
206
207
209{
210 Flip( displayOptions().m_DisplayPcbTrackFill );
211
212 for( PCB_TRACK* track : board()->Tracks() )
213 {
214 if( track->Type() == PCB_TRACE_T || track->Type() == PCB_ARC_T )
215 view()->Update( track, KIGFX::REPAINT );
216 }
217
218 for( BOARD_ITEM* shape : board()->Drawings() )
219 {
220 if( shape->Type() == PCB_SHAPE_T && static_cast<PCB_SHAPE*>( shape )->IsOnCopperLayer() )
221 view()->Update( shape, KIGFX::REPAINT );
222 }
223
224 canvas()->Refresh();
225
226 return 0;
227}
228
229
231{
232 if( PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame ) )
233 {
234 if( aEvent.IsAction( &PCB_ACTIONS::showRatsnest ) )
235 {
236 // N.B. Do not disable the Ratsnest layer here. We use it for local ratsnest
237 Flip( displayOptions().m_ShowGlobalRatsnest );
238 editFrame->SetElementVisibility( LAYER_RATSNEST, displayOptions().m_ShowGlobalRatsnest );
239
240 }
241 else if( aEvent.IsAction( &PCB_ACTIONS::ratsnestLineMode ) )
242 {
243 Flip( displayOptions().m_DisplayRatsnestLinesCurved );
244 }
245
246 editFrame->OnDisplayOptionsChanged();
247
249 canvas()->Refresh();
250 }
251
252 return 0;
253}
254
255
257{
258 Flip( displayOptions().m_DisplayViaFill );
259
260 for( PCB_TRACK* track : board()->Tracks() )
261 {
262 if( track->Type() == PCB_VIA_T )
263 view()->Update( track, KIGFX::REPAINT );
264 }
265
266 canvas()->Refresh();
267 return 0;
268}
269
270
277{
278 if( Pgm().GetCommonSettings()->m_DoNotShowAgain.zone_fill_warning )
279 return;
280
281 bool unfilledZones = false;
282
283 for( const ZONE* zone : board()->Zones() )
284 {
285 if( !zone->GetIsRuleArea() && !zone->IsFilled() )
286 {
287 unfilledZones = true;
288 break;
289 }
290 }
291
292 if( unfilledZones )
293 {
294 WX_INFOBAR* infobar = m_frame->GetInfoBar();
295 wxHyperlinkCtrl* button = new wxHyperlinkCtrl( infobar, wxID_ANY, _( "Don't show again" ), wxEmptyString );
296
297 button->Bind( wxEVT_COMMAND_HYPERLINK, std::function<void( wxHyperlinkEvent& aEvent )>(
298 [&]( wxHyperlinkEvent& aEvent )
299 {
301 m_frame->GetInfoBar()->Dismiss();
302 } ) );
303
304 infobar->RemoveAllButtons();
305 infobar->AddButton( button );
306
307 wxString msg;
308 msg.Printf( _( "Not all zones are filled. Use Edit > Fill All Zones (%s) "
309 "if you wish to see all fills." ),
311
312 infobar->ShowMessageFor( msg, 5000, wxICON_WARNING );
313 }
314}
315
316
318{
319 PCB_DISPLAY_OPTIONS opts = m_frame->GetDisplayOptions();
320
321 // Apply new display options to the GAL canvas
323 {
325
327 }
328 else if( aEvent.IsAction( &PCB_ACTIONS::zoneDisplayOutline ) )
329 {
331 }
332 else if( aEvent.IsAction( &PCB_ACTIONS::zoneDisplayFractured ) )
333 {
335 }
337 {
339 }
340 else if( aEvent.IsAction( &PCB_ACTIONS::zoneDisplayToggle ) )
341 {
344 else
346 }
347 else
348 {
349 wxFAIL;
350 }
351
352 m_frame->SetDisplayOptions( opts );
353
354 for( ZONE* zone : board()->Zones() )
355 view()->Update( zone, KIGFX::REPAINT );
356
357 canvas()->Refresh();
358
359 return 0;
360}
361
362
364{
365 PCB_DISPLAY_OPTIONS opts = m_frame->GetDisplayOptions();
366
370
371 m_frame->SetDisplayOptions( opts );
372 return 0;
373}
374
375
377{
378 PCB_DISPLAY_OPTIONS opts = m_frame->GetDisplayOptions();
379
380 switch( opts.m_ContrastModeDisplay )
381 {
385 }
386
387 m_frame->SetDisplayOptions( opts );
388
390 return 0;
391}
392
393
395{
396 if( !Pgm().GetCommonSettings()->m_Input.hotkey_feedback )
397 return 0;
398
399 PCB_DISPLAY_OPTIONS opts = m_frame->GetDisplayOptions();
400
401 wxArrayString labels;
402 labels.Add( _( "Normal" ) );
403 labels.Add( _( "Dimmed" ) );
404 labels.Add( _( "Hidden" ) );
405
406 if( !m_frame->GetHotkeyPopup() )
407 m_frame->CreateHotkeyPopup();
408
409 HOTKEY_CYCLE_POPUP* popup = m_frame->GetHotkeyPopup();
410
411 if( popup )
412 {
413 popup->Popup( _( "Inactive Layer Display" ), labels,
414 static_cast<int>( opts.m_ContrastModeDisplay ) );
415 }
416
417 return 0;
418}
419
420
422{
423 PCB_DISPLAY_OPTIONS opts = m_frame->GetDisplayOptions();
424
425 switch( opts.m_NetColorMode )
426 {
430 }
431
432 m_frame->SetDisplayOptions( opts );
433 return 0;
434}
435
436
438{
439 if( PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame ) )
440 {
441 if( !displayOptions().m_ShowGlobalRatsnest )
442 {
445 }
446 else if( displayOptions().m_RatsnestMode == RATSNEST_MODE::ALL )
447 {
449 }
450 else
451 {
453 }
454
455 editFrame->SetElementVisibility( LAYER_RATSNEST, displayOptions().m_ShowGlobalRatsnest );
456
457 editFrame->OnDisplayOptionsChanged();
458
460 canvas()->Refresh();
461 }
462
463 return 0;
464}
465
466
468{
469 m_frame->SwitchLayer( aEvent.Parameter<PCB_LAYER_ID>() );
470
471 return 0;
472}
473
474
476{
477 BOARD* brd = board();
478 PCB_LAYER_ID layer = m_frame->GetActiveLayer();
479 bool wraparound = false;
480
481 if( !IsCopperLayer( layer ) )
482 {
483 m_frame->SwitchLayer( B_Cu );
484 return 0;
485 }
486
487 LSET cuMask = LSET::AllCuMask( brd->GetCopperLayerCount() );
488 LSEQ layerStack = cuMask.UIOrder();
489
490 int ii = 0;
491
492 // Find the active layer in list
493 for( ; ii < (int)layerStack.size(); ii++ )
494 {
495 if( layer == layerStack[ii] )
496 break;
497 }
498
499 // Find the next visible layer in list
500 for( ; ii < (int)layerStack.size(); ii++ )
501 {
502 int jj = ii+1;
503
504 if( jj >= (int)layerStack.size() )
505 jj = 0;
506
507 layer = layerStack[jj];
508
509 if( brd->IsLayerVisible( layer ) )
510 break;
511
512 if( jj == 0 ) // the end of list is reached. Try from the beginning
513 {
514 if( wraparound )
515 {
516 wxBell();
517 return 0;
518 }
519 else
520 {
521 wraparound = true;
522 ii = -1;
523 }
524 }
525 }
526
527 wxCHECK( IsCopperLayer( layer ), 0 );
528 m_frame->SwitchLayer( layer );
529
530 return 0;
531}
532
533
535{
536 BOARD* brd = board();
537 PCB_LAYER_ID layer = m_frame->GetActiveLayer();
538 bool wraparound = false;
539
540 if( !IsCopperLayer( layer ) )
541 {
542 m_frame->SwitchLayer( F_Cu );
543 return 0;
544 }
545
546 LSET cuMask = LSET::AllCuMask( brd->GetCopperLayerCount() );
547 LSEQ layerStack = cuMask.UIOrder();
548
549 int ii = 0;
550
551 // Find the active layer in list
552 for( ; ii < (int)layerStack.size(); ii++ )
553 {
554 if( layer == layerStack[ii] )
555 break;
556 }
557
558 // Find the previous visible layer in list
559 for( ; ii >= 0; ii-- )
560 {
561 int jj = ii - 1;
562
563 if( jj < 0 )
564 jj = (int)layerStack.size() - 1;
565
566 layer = layerStack[jj];
567
568 if( brd->IsLayerVisible( layer ) )
569 break;
570
571 if( ii == 0 ) // the start of list is reached. Try from the last
572 {
573 if( wraparound )
574 {
575 wxBell();
576 return 0;
577 }
578 else
579 {
580 wraparound = true;
581 ii = 1;
582 }
583 }
584 }
585
586 wxCHECK( IsCopperLayer( layer ), 0 );
587 m_frame->SwitchLayer( layer );
588
589 return 0;
590}
591
592
594{
595 int currentLayer = m_frame->GetActiveLayer();
596 PCB_SCREEN* screen = m_frame->GetScreen();
597
598 if( currentLayer == screen->m_Route_Layer_TOP )
599 m_frame->SwitchLayer( screen->m_Route_Layer_BOTTOM );
600 else
601 m_frame->SwitchLayer( screen->m_Route_Layer_TOP );
602
603 return 0;
604}
605
606
607// It'd be nice to share the min/max with the DIALOG_COLOR_PICKER, but those are
608// set in wxFormBuilder.
609#define ALPHA_MIN 0.20
610#define ALPHA_MAX 1.00
611#define ALPHA_STEP 0.05
612
613
615{
616 COLOR_SETTINGS* settings = m_frame->GetColorSettings();
617 int currentLayer = m_frame->GetActiveLayer();
618 KIGFX::COLOR4D currentColor = settings->GetColor( currentLayer );
619
620 if( currentColor.a <= ALPHA_MAX - ALPHA_STEP )
621 {
622 currentColor.a += ALPHA_STEP;
623 settings->SetColor( currentLayer, currentColor );
624 m_frame->GetCanvas()->UpdateColors();
625
626 KIGFX::VIEW* view = m_frame->GetCanvas()->GetView();
627 view->UpdateLayerColor( currentLayer );
628 view->UpdateLayerColor( GetNetnameLayer( currentLayer ) );
629
630 if( IsCopperLayer( currentLayer ) )
631 view->UpdateLayerColor( ZONE_LAYER_FOR( currentLayer ) );
632
633 m_frame->GetCanvas()->ForceRefresh();
634 }
635 else
636 {
637 wxBell();
638 }
639
640 return 0;
641}
642
643
645{
646 COLOR_SETTINGS* settings = m_frame->GetColorSettings();
647 int currentLayer = m_frame->GetActiveLayer();
648 KIGFX::COLOR4D currentColor = settings->GetColor( currentLayer );
649
650 if( currentColor.a >= ALPHA_MIN + ALPHA_STEP )
651 {
652 currentColor.a -= ALPHA_STEP;
653 settings->SetColor( currentLayer, currentColor );
654 m_frame->GetCanvas()->UpdateColors();
655
656 KIGFX::VIEW* view = m_frame->GetCanvas()->GetView();
657 view->UpdateLayerColor( currentLayer );
658 view->UpdateLayerColor( GetNetnameLayer( currentLayer ) );
659
660 if( IsCopperLayer( currentLayer ) )
661 view->UpdateLayerColor( ZONE_LAYER_FOR( currentLayer ) );
662
663 m_frame->GetCanvas()->ForceRefresh();
664 }
665 else
666 {
667 wxBell();
668 }
669
670 return 0;
671}
672
673
675{
676 if( PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame ) )
677 {
678 LAYER_PAIR_SETTINGS* settings = editFrame->GetLayerPairSettings();
679
680 if( !settings )
681 return 0;
682
683 int currentIndex;
684 std::vector<LAYER_PAIR_INFO> presets = settings->GetEnabledLayerPairs( currentIndex );
685
686 if( presets.size() < 2 )
687 return 0;
688
689 if( currentIndex < 0 )
690 {
691 wxASSERT_MSG( false, "Current layer pair not found in layer settings" );
692 currentIndex = 0;
693 }
694
695 const int nextIndex = ( currentIndex + 1 ) % presets.size();
696 const LAYER_PAIR& nextPair = presets[nextIndex].GetLayerPair();
697
698 settings->SetCurrentLayerPair( nextPair );
699
701 }
702
703 return 0;
704}
705
706
708{
709 if( !Pgm().GetCommonSettings()->m_Input.hotkey_feedback )
710 return 0;
711
712 if( PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame ) )
713 {
714 LAYER_PAIR_SETTINGS* settings = editFrame->GetLayerPairSettings();
715
716 if( !settings )
717 return 0;
718
719 PCB_LAYER_PRESENTATION layerPresentation( editFrame );
720
721 int currentIndex;
722 std::vector<LAYER_PAIR_INFO> presets = settings->GetEnabledLayerPairs( currentIndex );
723
724 wxArrayString labels;
725 for( const LAYER_PAIR_INFO& layerPairInfo : presets )
726 {
727 wxString label = layerPresentation.getLayerPairName( layerPairInfo.GetLayerPair() );
728
729 if( layerPairInfo.GetName() )
730 label += wxT( " (" ) + *layerPairInfo.GetName() + wxT( ")" );
731
732 labels.Add( label );
733 }
734
735 if( !editFrame->GetHotkeyPopup() )
736 editFrame->CreateHotkeyPopup();
737
738 HOTKEY_CYCLE_POPUP* popup = editFrame->GetHotkeyPopup();
739
740 if( popup )
741 {
742 int selection = currentIndex;
743 popup->Popup( _( "Preset Layer Pairs" ), labels, selection );
744 }
745 }
746
747 return 0;
748}
749
750
752 EDA_ITEM* originViewItem, const VECTOR2D& aPoint )
753{
754 aFrame->GetDesignSettings().SetGridOrigin( VECTOR2I( aPoint ) );
755 aView->GetGAL()->SetGridOrigin( aPoint );
756 originViewItem->SetPosition( aPoint );
757 aView->MarkDirty();
758 aFrame->OnModify();
759}
760
761
763{
764 VECTOR2D* origin = aEvent.Parameter<VECTOR2D*>();
765
766 if( origin )
767 {
768 // We can't undo the other grid dialog settings, so no sense undoing just the origin
769 DoSetGridOrigin( getView(), m_frame, m_gridOrigin.get(), *origin );
770 delete origin;
771 }
772 else
773 {
775 return 0;
776
777 PCB_PICKER_TOOL* picker = m_toolMgr->GetTool<PCB_PICKER_TOOL>();
778
779 if( !picker ) // Happens in footprint wizard
780 return 0;
781
782 // Deactivate other tools; particularly important if another PICKER is currently running
783 Activate();
784
785 picker->SetCursor( KICURSOR::PLACE );
786 picker->ClearHandlers();
787
788 picker->SetClickHandler(
789 [this]( const VECTOR2D& pt ) -> bool
790 {
791 m_frame->SaveCopyInUndoList( m_gridOrigin.get(), UNDO_REDO::GRIDORIGIN );
793 return false; // drill origin is a one-shot; don't continue with tool
794 } );
795
796 m_toolMgr->RunAction( ACTIONS::pickerTool, &aEvent );
797 }
798
799 return 0;
800}
801
802
804{
805 m_frame->SaveCopyInUndoList( m_gridOrigin.get(), UNDO_REDO::GRIDORIGIN );
807 return 0;
808}
809
810
811#define HITTEST_THRESHOLD_PIXELS 5
812
813
815{
816 if( m_isFootprintEditor && !m_frame->GetBoard()->GetFirstFootprint() )
817 return 0;
818
819 PCB_PICKER_TOOL* picker = m_toolMgr->GetTool<PCB_PICKER_TOOL>();
820
821 m_pickerItem = nullptr;
823
824 // Deactivate other tools; particularly important if another PICKER is currently running
825 Activate();
826
827 picker->SetCursor( KICURSOR::REMOVE );
828 picker->SetSnapping( false );
829 picker->ClearHandlers();
830
831 picker->SetClickHandler(
832 [this]( const VECTOR2D& aPosition ) -> bool
833 {
834 if( m_pickerItem )
835 {
836 if( m_pickerItem && m_pickerItem->IsLocked() )
837 {
839 m_statusPopup->SetText( _( "Item locked." ) );
840 m_statusPopup->PopupFor( 2000 );
841 m_statusPopup->Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, 20 ) );
842 return true;
843 }
844
845 PCB_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
846 selectionTool->UnbrightenItem( m_pickerItem );
847
848 PCB_SELECTION items;
849 items.Add( m_pickerItem );
850
851 EDIT_TOOL* editTool = m_toolMgr->GetTool<EDIT_TOOL>();
852 editTool->DeleteItems( items, false );
853
854 m_pickerItem = nullptr;
855 }
856
857 return true;
858 } );
859
860 picker->SetMotionHandler(
861 [this]( const VECTOR2D& aPos )
862 {
863 BOARD* board = m_frame->GetBoard();
864 PCB_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
865 GENERAL_COLLECTORS_GUIDE guide = m_frame->GetCollectorsGuide();
866 GENERAL_COLLECTOR collector;
867 collector.m_Threshold = KiROUND( getView()->ToWorld( HITTEST_THRESHOLD_PIXELS ) );
868
870 collector.Collect( board, GENERAL_COLLECTOR::FootprintItems, aPos, guide );
871 else
872 collector.Collect( board, GENERAL_COLLECTOR::BoardLevelItems, aPos, guide );
873
874 // Remove unselectable items
875 for( int i = collector.GetCount() - 1; i >= 0; --i )
876 {
877 if( !selectionTool->Selectable( collector[ i ] ) )
878 collector.Remove( i );
879 }
880
881 selectionTool->FilterCollectorForHierarchy( collector, false );
882 selectionTool->FilterCollectedItems( collector, false, nullptr );
883
884 if( collector.GetCount() > 1 )
885 selectionTool->GuessSelectionCandidates( collector, aPos );
886
887 BOARD_ITEM* item = collector.GetCount() == 1 ? collector[ 0 ] : nullptr;
888
889 if( m_pickerItem != item )
890 {
891 if( m_pickerItem )
892 selectionTool->UnbrightenItem( m_pickerItem );
893
894 m_pickerItem = item;
895
896 if( m_pickerItem )
897 selectionTool->BrightenItem( m_pickerItem );
898 }
899 } );
900
901 picker->SetFinalizeHandler(
902 [this]( const int& aFinalState )
903 {
904 if( m_pickerItem )
905 m_toolMgr->GetTool<PCB_SELECTION_TOOL>()->UnbrightenItem( m_pickerItem );
906
907 m_statusPopup.reset();
908
909 // Ensure the cursor gets changed&updated
910 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
911 m_frame->GetCanvas()->Refresh();
912 } );
913
914 m_toolMgr->RunAction( ACTIONS::pickerTool, &aEvent );
915
916 return 0;
917}
918
919
920static void pasteFootprintItemsToFootprintEditor( FOOTPRINT* aClipFootprint, BOARD* aBoard,
921 std::vector<BOARD_ITEM*>& aPastedItems )
922{
923 FOOTPRINT* editorFootprint = aBoard->GetFirstFootprint();
924
925 aClipFootprint->SetParent( aBoard );
926
927 for( PAD* pad : aClipFootprint->Pads() )
928 {
929 pad->SetParent( editorFootprint );
930 aPastedItems.push_back( pad );
931 }
932
933 aClipFootprint->Pads().clear();
934
935 // Not all items can be added to the current footprint: mandatory fields are already existing
936 // in the current footprint.
937 //
938 for( PCB_FIELD* field : aClipFootprint->GetFields() )
939 {
940 if( field->IsMandatory() )
941 {
942 if( EDA_GROUP* parentGroup = field->GetParentGroup() )
943 parentGroup->RemoveItem( field );
944 }
945 else
946 {
947 PCB_TEXT* text = static_cast<PCB_TEXT*>( field );
948
949 text->SetTextAngle( text->GetTextAngle() - aClipFootprint->GetOrientation() );
950 text->SetTextAngle( text->GetTextAngle() + editorFootprint->GetOrientation() );
951
952 VECTOR2I pos = field->GetFPRelativePosition();
953 field->SetParent( editorFootprint );
954 field->SetFPRelativePosition( pos );
955
956 aPastedItems.push_back( field );
957 }
958 }
959
960 aClipFootprint->GetFields().clear();
961
962 for( BOARD_ITEM* item : aClipFootprint->GraphicalItems() )
963 {
964 if( item->Type() == PCB_TEXT_T )
965 {
966 PCB_TEXT* text = static_cast<PCB_TEXT*>( item );
967
968 text->SetTextAngle( text->GetTextAngle() - aClipFootprint->GetOrientation() );
969 text->SetTextAngle( text->GetTextAngle() + editorFootprint->GetOrientation() );
970 }
971
972 item->Rotate( item->GetPosition(), -aClipFootprint->GetOrientation() );
973 item->Rotate( item->GetPosition(), editorFootprint->GetOrientation() );
974
975 VECTOR2I pos = item->GetFPRelativePosition();
976 item->SetParent( editorFootprint );
977 item->SetFPRelativePosition( pos );
978
979 aPastedItems.push_back( item );
980 }
981
982 aClipFootprint->GraphicalItems().clear();
983
984 for( ZONE* zone : aClipFootprint->Zones() )
985 {
986 zone->SetParent( editorFootprint );
987 aPastedItems.push_back( zone );
988 }
989
990 aClipFootprint->Zones().clear();
991
992 for( PCB_GROUP* group : aClipFootprint->Groups() )
993 {
994 group->SetParent( editorFootprint );
995 aPastedItems.push_back( group );
996 }
997
998 aClipFootprint->Groups().clear();
999}
1000
1001
1002void PCB_CONTROL::pruneItemLayers( std::vector<BOARD_ITEM*>& aItems )
1003{
1004 // Do not prune items or layers when copying to the FP editor, because all
1005 // layers are accepted, even if they are not enabled in the dummy board
1006 // This is mainly true for internal copper layers: all are allowed but only one
1007 // (In1.cu) is enabled for the GUI.
1009 return;
1010
1011 LSET enabledLayers = board()->GetEnabledLayers();
1012 std::vector<BOARD_ITEM*> returnItems;
1013 bool fpItemDeleted = false;
1014
1015 for( BOARD_ITEM* item : aItems )
1016 {
1017 if( item->Type() == PCB_FOOTPRINT_T )
1018 {
1019 FOOTPRINT* fp = static_cast<FOOTPRINT*>( item );
1020
1021 // Items living in a parent footprint are never removed, even if their
1022 // layer does not exist in the board editor
1023 // Otherwise the parent footprint could be seriously broken especially
1024 // if some layers are later re-enabled.
1025 // Moreover a fp lives in a fp library, that does not know the enabled
1026 // layers of a given board, so fp items are just ignored when on not
1027 // enabled layers in board editor
1028 returnItems.push_back( fp );
1029 }
1030 else if( item->Type() == PCB_GROUP_T || item->Type() == PCB_GENERATOR_T )
1031 {
1032 returnItems.push_back( item );
1033 }
1034 else
1035 {
1036 LSET allowed = item->GetLayerSet() & enabledLayers;
1037 bool item_valid = true;
1038
1039 // Ensure, for vias, the top and bottom layers are compatible with
1040 // the current board copper layers.
1041 // Otherwise they must be skipped, even is one layer is valid
1042 if( item->Type() == PCB_VIA_T )
1043 item_valid = static_cast<PCB_VIA*>( item )->HasValidLayerPair(
1044 board()->GetCopperLayerCount() );
1045
1046 if( allowed.any() && item_valid )
1047 {
1048 item->SetLayerSet( allowed );
1049 returnItems.push_back( item );
1050 }
1051 else
1052 {
1053 if( EDA_GROUP* parentGroup = item->GetParentGroup() )
1054 parentGroup->RemoveItem( item );
1055 }
1056 }
1057 }
1058
1059 if( ( returnItems.size() < aItems.size() ) || fpItemDeleted )
1060 {
1061 DisplayError( m_frame, _( "Warning: some pasted items were on layers which are not "
1062 "present in the current board.\n"
1063 "These items could not be pasted.\n" ) );
1064 }
1065
1066 aItems = returnItems;
1067}
1068
1069
1070int PCB_CONTROL::Paste( const TOOL_EVENT& aEvent )
1071{
1072 // The viewer frames cannot paste
1073 if( !m_frame->IsType( FRAME_FOOTPRINT_EDITOR ) && !m_frame->IsType( FRAME_PCB_EDITOR ) )
1074 return 0;
1075
1076 bool isFootprintEditor = m_isFootprintEditor || m_frame->IsType( FRAME_FOOTPRINT_EDITOR );
1077
1078 // The clipboard can contain two different things, an entire kicad_pcb or a single footprint
1079 if( isFootprintEditor && ( !board() || !footprint() ) )
1080 return 0;
1081
1082 // We should never get here if a modal dialog is up... but we do on MacOS.
1083 // https://gitlab.com/kicad/code/kicad/-/issues/18912
1084#ifdef __WXMAC__
1085 if( wxDialog::OSXHasModalDialogsOpen() )
1086 {
1087 wxBell();
1088 return 0;
1089 }
1090#endif
1091
1092 BOARD_COMMIT commit( m_frame );
1093
1094 CLIPBOARD_IO pi;
1095 BOARD_ITEM* clipItem = pi.Parse();
1096
1097 if( !clipItem )
1098 {
1099 // When the clipboard doesn't parse, create a PCB item with the clipboard contents
1100 std::vector<BOARD_ITEM*> newItems;
1101
1102 if( std::unique_ptr<wxImage> clipImg = GetImageFromClipboard() )
1103 {
1104 auto refImg = std::make_unique<PCB_REFERENCE_IMAGE>( m_frame->GetModel() );
1105
1106 if( refImg->GetReferenceImage().SetImage( *clipImg ) )
1107 newItems.push_back( refImg.release() );
1108 }
1109 else
1110 {
1111 const wxString clipText = GetClipboardUTF8();
1112
1113 if( clipText.empty() )
1114 return 0;
1115
1116 // If it wasn't content, then paste as a text object.
1117 if( clipText.size() > static_cast<size_t>( ADVANCED_CFG::GetCfg().m_MaxPastedTextLength ) )
1118 {
1119 int result = IsOK( m_frame, _( "Pasting a long text text string may be very slow. "
1120 "Do you want to continue?" ) );
1121 if( !result )
1122 return 0;
1123 }
1124
1125 std::unique_ptr<PCB_TEXT> item = std::make_unique<PCB_TEXT>( m_frame->GetModel() );
1126 item->SetText( clipText );
1127
1128 newItems.push_back( item.release() );
1129 }
1130
1131 bool cancelled = !placeBoardItems( &commit, newItems, true, false, false, false );
1132
1133 if( cancelled )
1134 commit.Revert();
1135 else
1136 commit.Push( _( "Paste Text" ) );
1137 return 0;
1138 }
1139
1140 // If we get here, we have a parsed board/FP to paste
1141
1143 bool clear_nets = false;
1144 const wxString defaultRef = wxT( "REF**" );
1145
1146 if( aEvent.IsAction( &ACTIONS::pasteSpecial ) )
1147 {
1148 DIALOG_PASTE_SPECIAL dlg( m_frame, &mode, defaultRef );
1149
1150 if( clipItem->Type() != PCB_T )
1151 dlg.HideClearNets();
1152
1153 if( dlg.ShowModal() == wxID_CANCEL )
1154 return 0;
1155
1156 clear_nets = dlg.GetClearNets();
1157 }
1158
1159 if( clipItem->Type() == PCB_T )
1160 {
1161 BOARD* clipBoard = static_cast<BOARD*>( clipItem );
1162
1163 if( isFootprintEditor || clear_nets )
1164 {
1165 for( BOARD_CONNECTED_ITEM* item : clipBoard->AllConnectedItems() )
1166 item->SetNet( NETINFO_LIST::OrphanedItem() );
1167 }
1168 else
1169 {
1170 clipBoard->MapNets( m_frame->GetBoard() );
1171 }
1172 }
1173
1174 bool cancelled = false;
1175
1176 switch( clipItem->Type() )
1177 {
1178 case PCB_T:
1179 {
1180 BOARD* clipBoard = static_cast<BOARD*>( clipItem );
1181
1182 if( isFootprintEditor )
1183 {
1184 FOOTPRINT* editorFootprint = board()->GetFirstFootprint();
1185 std::vector<BOARD_ITEM*> pastedItems;
1186
1187 for( PCB_GROUP* group : clipBoard->Groups() )
1188 {
1189 group->SetParent( editorFootprint );
1190 pastedItems.push_back( group );
1191 }
1192
1193 clipBoard->RemoveAll( { PCB_GROUP_T } );
1194
1195 for( FOOTPRINT* clipFootprint : clipBoard->Footprints() )
1196 pasteFootprintItemsToFootprintEditor( clipFootprint, board(), pastedItems );
1197
1198 for( BOARD_ITEM* clipDrawItem : clipBoard->Drawings() )
1199 {
1200 switch( clipDrawItem->Type() )
1201 {
1202 case PCB_TEXT_T:
1203 case PCB_TEXTBOX_T:
1204 case PCB_TABLE_T:
1205 case PCB_SHAPE_T:
1206 case PCB_BARCODE_T:
1207 case PCB_DIM_ALIGNED_T:
1208 case PCB_DIM_CENTER_T:
1209 case PCB_DIM_LEADER_T:
1211 case PCB_DIM_RADIAL_T:
1212 clipDrawItem->SetParent( editorFootprint );
1213 pastedItems.push_back( clipDrawItem );
1214 break;
1215
1216 default:
1217 // Everything we *didn't* put into pastedItems is going to get nuked, so
1218 // make sure it's not still included in its parent group.
1219 if( EDA_GROUP* parentGroup = clipDrawItem->GetParentGroup() )
1220 parentGroup->RemoveItem( clipDrawItem );
1221
1222 break;
1223 }
1224 }
1225
1226 // NB: PCB_SHAPE_T actually removes everything in Drawings() (including PCB_TEXTs,
1227 // PCB_TABLEs, PCB_BARCODEs, dimensions, etc.), not just PCB_SHAPEs.)
1228 clipBoard->RemoveAll( { PCB_SHAPE_T } );
1229
1230 clipBoard->Visit(
1231 [&]( EDA_ITEM* item, void* testData )
1232 {
1233 if( item->IsBOARD_ITEM() )
1234 {
1235 // Anything still on the clipboard didn't get copied and needs to be
1236 // removed from the pasted groups.
1237 BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( item );
1238 EDA_GROUP* parentGroup = boardItem->GetParentGroup();
1239
1240 if( parentGroup )
1241 parentGroup->RemoveItem( boardItem );
1242 }
1243
1245 },
1247
1248 delete clipBoard;
1249
1250 pruneItemLayers( pastedItems );
1251
1252 cancelled = !placeBoardItems( &commit, pastedItems, true, true, mode == PASTE_MODE::UNIQUE_ANNOTATIONS,
1253 false );
1254 }
1255 else // isBoardEditor
1256 {
1257 // Fixup footprint component classes
1258 for( FOOTPRINT* fp : clipBoard->Footprints() )
1259 {
1260 fp->ResolveComponentClassNames( board(), fp->GetTransientComponentClassNames() );
1261 fp->ClearTransientComponentClassNames();
1262 }
1263
1264 if( mode == PASTE_MODE::REMOVE_ANNOTATIONS )
1265 {
1266 for( FOOTPRINT* fp : clipBoard->Footprints() )
1267 fp->SetReference( defaultRef );
1268 }
1269
1270 cancelled = !placeBoardItems( &commit, clipBoard, true, mode == PASTE_MODE::UNIQUE_ANNOTATIONS,
1271 false );
1272 }
1273
1274 break;
1275 }
1276
1277 case PCB_FOOTPRINT_T:
1278 {
1279 FOOTPRINT* clipFootprint = static_cast<FOOTPRINT*>( clipItem );
1280 std::vector<BOARD_ITEM*> pastedItems;
1281
1282 if( isFootprintEditor )
1283 {
1284 pasteFootprintItemsToFootprintEditor( clipFootprint, board(), pastedItems );
1285 delete clipFootprint;
1286 }
1287 else
1288 {
1289 if( mode == PASTE_MODE::REMOVE_ANNOTATIONS )
1290 clipFootprint->SetReference( defaultRef );
1291
1292 clipFootprint->SetParent( board() );
1293 clipFootprint->ResolveComponentClassNames( board(), clipFootprint->GetTransientComponentClassNames() );
1294 clipFootprint->ClearTransientComponentClassNames();
1295 pastedItems.push_back( clipFootprint );
1296 }
1297
1298 pruneItemLayers( pastedItems );
1299
1300 cancelled = !placeBoardItems( &commit, pastedItems, true, true, mode == PASTE_MODE::UNIQUE_ANNOTATIONS,
1301 false );
1302 break;
1303 }
1304
1305 default:
1306 m_frame->DisplayToolMsg( _( "Invalid clipboard contents" ) );
1307 break;
1308 }
1309
1310 if( cancelled )
1311 commit.Revert();
1312 else
1313 commit.Push( _( "Paste" ) );
1314
1315 return 1;
1316}
1317
1318
1320{
1321 wxString fileName;
1322
1323 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
1324
1325 if( !editFrame )
1326 return 1;
1327
1328 // Pick a file to append
1329 if( !AskLoadBoardFileName( editFrame, &fileName, KICTL_KICAD_ONLY ) )
1330 return 1;
1331
1333 IO_RELEASER<PCB_IO> pi( PCB_IO_MGR::PluginFind( pluginType ) );
1334
1335 if( !pi )
1336 return 1;
1337
1338 return AppendBoard( *pi, fileName );
1339}
1340
1341
1343{
1344 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
1345
1346 if( !editFrame )
1347 return 1;
1348
1349 if( !editFrame->GetDesignBlockPane()->GetSelectedLibId().IsValid() )
1350 return 1;
1351
1352 DESIGN_BLOCK_PANE* designBlockPane = editFrame->GetDesignBlockPane();
1353 std::unique_ptr<DESIGN_BLOCK> designBlock( designBlockPane->GetDesignBlock( designBlockPane->GetSelectedLibId(),
1354 true, true ) );
1355
1356 if( !designBlock || designBlock->GetBoardFile().IsEmpty() )
1357 return 1;
1358
1360 IO_RELEASER<PCB_IO> pi( PCB_IO_MGR::PluginFind( pluginType ) );
1361
1362 if( !pi )
1363 return 1;
1364
1365 bool repeatPlacement = false;
1366
1367 if( APP_SETTINGS_BASE* cfg = editFrame->config() )
1368 repeatPlacement = cfg->m_DesignBlockChooserPanel.repeated_placement;
1369
1370 int ret = 0;
1371
1372 do
1373 {
1374 ret = AppendBoard( *pi, designBlock->GetBoardFile(), designBlock.get() );
1375 } while( repeatPlacement && ret == 0 );
1376
1377 return ret;
1378}
1379
1381{
1382 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
1383
1384 if( !editFrame )
1385 return 1;
1386
1387 BOARD* brd = board();
1388
1389 if( !brd )
1390 return 1;
1391
1392 // Need to have a group selected and it needs to have a linked design block
1393 PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
1395
1396 if( selection.Size() != 1 || selection[0]->Type() != PCB_GROUP_T )
1397 return 1;
1398
1399 PCB_GROUP* group = static_cast<PCB_GROUP*>( selection[0] );
1400
1401 if( !group->HasDesignBlockLink() )
1402 return 1;
1403
1404 BOARD_COMMIT tempCommit( m_frame );
1405
1406 std::set<EDA_ITEM*> originalItems;
1407 // Apply MCT_SKIP_STRUCT to every EDA_ITEM on the board so we know what is not part of the design block
1408 // Can't use SKIP_STRUCT as that is used and cleared by the temporary board appending
1409 brd->Visit( []( EDA_ITEM* item, void* )
1410 {
1411 item->SetFlags( MCT_SKIP_STRUCT );
1413 },
1415
1416 int ret = 1;
1417
1418 bool skipMove = true;
1419
1420 // If we succeeded in placing the linked design block, we're ready to apply the multichannel tool
1421 if( m_toolMgr->RunSynchronousAction( PCB_ACTIONS::placeLinkedDesignBlock, &tempCommit, &skipMove ) )
1422 {
1423 // Lambda for the bounding box of all the components
1424 auto generateBoundingBox = [&]( std::unordered_set<EDA_ITEM*> aItems )
1425 {
1426 std::vector<VECTOR2I> bbCorners;
1427 bbCorners.reserve( aItems.size() * 4 );
1428
1429 for( auto item : aItems )
1430 {
1431 const BOX2I bb = item->GetBoundingBox().GetInflated( 100000 );
1432 KIGEOM::CollectBoxCorners( bb, bbCorners );
1433 }
1434
1435 std::vector<VECTOR2I> hullVertices;
1436 BuildConvexHull( hullVertices, bbCorners );
1437
1438 SHAPE_LINE_CHAIN hull( hullVertices );
1439
1440 // Make the newly computed convex hull use only 90 degree segments
1441 return KIGEOM::RectifyPolygon( hull );
1442 };
1443
1444 // Build a rule area that contains all the components in the design block,
1445 // meaning all items without SKIP_STRUCT set.
1446 RULE_AREA dbRA;
1447
1449 dbRA.m_generateEnabled = true;
1450
1451 // Add all components that aren't marked MCT_SKIP_STRUCT to ra.m_components
1452 brd->Visit(
1453 [&]( EDA_ITEM* item, void* data )
1454 {
1455 if( !item->HasFlag( MCT_SKIP_STRUCT ) )
1456 {
1457 dbRA.m_designBlockItems.insert( item );
1458
1459 if( item->Type() == PCB_FOOTPRINT_T )
1460 dbRA.m_components.insert( static_cast<FOOTPRINT*>( item ) );
1461 }
1463 },
1465
1466 dbRA.m_zone = new ZONE( board() );
1467 //dbRA.m_area->SetZoneName( wxString::Format( wxT( "design-block-source-%s" ), group->GetDesignBlockLibId().GetUniStringLibId() ) );
1468 dbRA.m_zone->SetIsRuleArea( true );
1470 dbRA.m_zone->SetPlacementAreaEnabled( true );
1471 dbRA.m_zone->SetDoNotAllowZoneFills( false );
1472 dbRA.m_zone->SetDoNotAllowVias( false );
1473 dbRA.m_zone->SetDoNotAllowTracks( false );
1474 dbRA.m_zone->SetDoNotAllowPads( false );
1475 dbRA.m_zone->SetDoNotAllowFootprints( false );
1477 dbRA.m_zone->SetPlacementAreaSource( group->GetDesignBlockLibId().GetUniStringLibId() );
1479 dbRA.m_zone->AddPolygon( generateBoundingBox( dbRA.m_designBlockItems ) );
1480 dbRA.m_center = dbRA.m_zone->Outline()->COutline( 0 ).Centre();
1481
1482 // Create the destination rule area for the group
1483 RULE_AREA destRA;
1484
1486
1487 // Add all the design block group footprints to the destination rule area
1488 for( EDA_ITEM* item : group->GetItems() )
1489 {
1490 if( item->Type() == PCB_FOOTPRINT_T )
1491 {
1492 FOOTPRINT* fp = static_cast<FOOTPRINT*>( item );
1493
1494 // If the footprint is locked, we can't place it
1495 if( fp->IsLocked() )
1496 {
1497 wxString msg;
1498 msg.Printf( _( "Footprint %s is locked and cannot be placed." ), fp->GetReference() );
1499 m_frame->GetInfoBar()->ShowMessageFor( msg, 5000, wxICON_WARNING );
1500 return 1;
1501 }
1502
1503 destRA.m_components.insert( fp );
1504 }
1505 }
1506
1507 destRA.m_zone = new ZONE( board() );
1508 destRA.m_zone->SetZoneName(
1509 wxString::Format( wxT( "design-block-dest-%s" ), group->GetDesignBlockLibId().GetUniStringLibId() ) );
1510 destRA.m_zone->SetIsRuleArea( true );
1511 destRA.m_zone->SetLayerSet( LSET::AllCuMask() );
1512 destRA.m_zone->SetPlacementAreaEnabled( true );
1513 destRA.m_zone->SetDoNotAllowZoneFills( false );
1514 destRA.m_zone->SetDoNotAllowVias( false );
1515 destRA.m_zone->SetDoNotAllowTracks( false );
1516 destRA.m_zone->SetDoNotAllowPads( false );
1517 destRA.m_zone->SetDoNotAllowFootprints( false );
1519 destRA.m_zone->SetPlacementAreaSource( group->GetName() );
1521 destRA.m_zone->AddPolygon( generateBoundingBox( group->GetItems() ) );
1522 destRA.m_center = destRA.m_zone->Outline()->COutline( 0 ).Centre();
1523
1524 // Use the multichannel tool to repeat the layout
1526
1527 ret = mct->RepeatLayout( aEvent, dbRA, destRA );
1528
1529 // Get rid of the temporary design blocks and rule areas
1530 tempCommit.Revert();
1531
1532 delete dbRA.m_zone;
1533 delete destRA.m_zone;
1534 }
1535
1536 // We're done, remove SKIP_STRUCT
1537 brd->Visit( []( EDA_ITEM* item, void* )
1538 {
1539 item->ClearFlags( MCT_SKIP_STRUCT );
1541 },
1543
1544 return ret;
1545}
1546
1548{
1549 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
1550
1551 if( !editFrame )
1552 return 1;
1553
1554 // Need to have a group selected and it needs to have a linked design block
1555 PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
1557
1558 if( selection.Size() != 1 || selection[0]->Type() != PCB_GROUP_T )
1559 return 1;
1560
1561 PCB_GROUP* group = static_cast<PCB_GROUP*>( selection[0] );
1562
1563 if( !group->HasDesignBlockLink() )
1564 return 1;
1565
1566 // Get the associated design block
1567 DESIGN_BLOCK_PANE* designBlockPane = editFrame->GetDesignBlockPane();
1568 std::unique_ptr<DESIGN_BLOCK> designBlock( designBlockPane->GetDesignBlock( group->GetDesignBlockLibId(),
1569 true, true ) );
1570
1571 if( !designBlock )
1572 {
1573 wxString msg;
1574 msg.Printf( _( "Could not find design block %s." ), group->GetDesignBlockLibId().GetUniStringLibId() );
1575 m_frame->GetInfoBar()->ShowMessageFor( msg, 5000, wxICON_WARNING );
1576 return 1;
1577 }
1578
1579 if( designBlock->GetBoardFile().IsEmpty() )
1580 {
1581 wxString msg;
1582 msg.Printf( _( "Design block %s does not have a board file." ),
1583 group->GetDesignBlockLibId().GetUniStringLibId() );
1584 m_frame->GetInfoBar()->ShowMessageFor( msg, 5000, wxICON_WARNING );
1585 return 1;
1586 }
1587
1588
1590 IO_RELEASER<PCB_IO> pi( PCB_IO_MGR::PluginFind( pluginType ) );
1591
1592 if( !pi )
1593 return 1;
1594
1595 if( aEvent.Parameter<bool*>() != nullptr )
1596 return AppendBoard( *pi, designBlock->GetBoardFile(), designBlock.get(),
1597 static_cast<BOARD_COMMIT*>( aEvent.Commit() ), *aEvent.Parameter<bool*>() );
1598 else
1599 return AppendBoard( *pi, designBlock->GetBoardFile(), designBlock.get() );
1600}
1601
1602
1604{
1605 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
1606
1607 if( !editFrame )
1608 return 1;
1609
1610 // Need to have a group selected and it needs to have a linked design block
1611 PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
1613
1614 if( selection.Size() != 1 || selection[0]->Type() != PCB_GROUP_T )
1615 return 1;
1616
1617 PCB_GROUP* group = static_cast<PCB_GROUP*>( selection[0] );
1618
1619 if( !group->HasDesignBlockLink() )
1620 return 1;
1621
1622 // Get the associated design block
1623 DESIGN_BLOCK_PANE* designBlockPane = editFrame->GetDesignBlockPane();
1624 std::unique_ptr<DESIGN_BLOCK> designBlock( designBlockPane->GetDesignBlock( group->GetDesignBlockLibId(),
1625 true, true ) );
1626
1627 if( !designBlock )
1628 {
1629 wxString msg;
1630 msg.Printf( _( "Could not find design block %s." ), group->GetDesignBlockLibId().GetUniStringLibId() );
1631 m_frame->GetInfoBar()->ShowMessageFor( msg, 5000, wxICON_WARNING );
1632 return 1;
1633 }
1634
1635 editFrame->GetDesignBlockPane()->SelectLibId( group->GetDesignBlockLibId() );
1636
1637 return m_toolMgr->RunAction( PCB_ACTIONS::saveSelectionToDesignBlock ) ? 1 : 0;
1638}
1639
1640
1641template<typename T>
1642static void moveUnflaggedItems( const std::deque<T>& aList, std::vector<BOARD_ITEM*>& aTarget,
1643 bool aIsNew )
1644{
1645 std::copy_if( aList.begin(), aList.end(), std::back_inserter( aTarget ),
1646 [aIsNew]( T aItem )
1647 {
1648 bool doCopy = ( aItem->GetFlags() & SKIP_STRUCT ) == 0;
1649
1650 aItem->ClearFlags( SKIP_STRUCT );
1651 aItem->SetFlags( aIsNew ? IS_NEW : 0 );
1652
1653 return doCopy;
1654 } );
1655}
1656
1657
1658template<typename T>
1659static void moveUnflaggedItems( const std::vector<T>& aList, std::vector<BOARD_ITEM*>& aTarget,
1660 bool aIsNew )
1661{
1662 std::copy_if( aList.begin(), aList.end(), std::back_inserter( aTarget ),
1663 [aIsNew]( T aItem )
1664 {
1665 bool doCopy = ( aItem->GetFlags() & SKIP_STRUCT ) == 0;
1666
1667 aItem->ClearFlags( SKIP_STRUCT );
1668 aItem->SetFlags( aIsNew ? IS_NEW : 0 );
1669
1670 return doCopy;
1671 } );
1672}
1673
1674
1675bool PCB_CONTROL::placeBoardItems( BOARD_COMMIT* aCommit, BOARD* aBoard, bool aAnchorAtOrigin,
1676 bool aReannotateDuplicates, bool aSkipMove )
1677{
1678 // items are new if the current board is not the board source
1679 bool isNew = board() != aBoard;
1680 std::vector<BOARD_ITEM*> items;
1681
1682 moveUnflaggedItems( aBoard->Tracks(), items, isNew );
1683 moveUnflaggedItems( aBoard->Footprints(), items, isNew );
1684 moveUnflaggedItems( aBoard->Drawings(), items, isNew );
1685 moveUnflaggedItems( aBoard->Zones(), items, isNew );
1686
1687 // Subtlety: When selecting a group via the mouse,
1688 // PCB_SELECTION_TOOL::highlightInternal runs, which does a SetSelected() on all
1689 // descendants. In PCB_CONTROL::placeBoardItems, below, we skip that and
1690 // mark items non-recursively. That works because the saving of the
1691 // selection created aBoard that has the group and all descendants in it.
1692 moveUnflaggedItems( aBoard->Groups(), items, isNew );
1693
1694 moveUnflaggedItems( aBoard->Generators(), items, isNew );
1695
1696 if( isNew )
1697 aBoard->RemoveAll();
1698
1699 // Reparent before calling pruneItemLayers, as SetLayer can have a dependence on the
1700 // item's parent board being set correctly.
1701 if( isNew )
1702 {
1703 for( BOARD_ITEM* item : items )
1704 item->SetParent( board() );
1705 }
1706
1707 pruneItemLayers( items );
1708
1709 return placeBoardItems( aCommit, items, isNew, aAnchorAtOrigin, aReannotateDuplicates, aSkipMove );
1710}
1711
1712
1713bool PCB_CONTROL::placeBoardItems( BOARD_COMMIT* aCommit, std::vector<BOARD_ITEM*>& aItems, bool aIsNew,
1714 bool aAnchorAtOrigin, bool aReannotateDuplicates, bool aSkipMove )
1715{
1716 m_toolMgr->RunAction( ACTIONS::selectionClear );
1717
1718 PCB_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
1719
1720 std::vector<BOARD_ITEM*> itemsToSel;
1721 itemsToSel.reserve( aItems.size() );
1722
1723 for( BOARD_ITEM* item : aItems )
1724 {
1725 if( aIsNew )
1726 {
1727 const_cast<KIID&>( item->m_Uuid ) = KIID();
1728
1729 item->RunOnChildren(
1730 []( BOARD_ITEM* aChild )
1731 {
1732 const_cast<KIID&>( aChild->m_Uuid ) = KIID();
1733 },
1735
1736 // While BOARD_COMMIT::Push() will add any new items to the entered group,
1737 // we need to do it earlier so that the previews while moving are correct.
1738 if( PCB_GROUP* enteredGroup = selectionTool->GetEnteredGroup() )
1739 {
1740 if( item->IsGroupableType() && !item->GetParentGroup() )
1741 {
1742 aCommit->Modify( enteredGroup, nullptr, RECURSE_MODE::NO_RECURSE );
1743 enteredGroup->AddItem( item );
1744 }
1745 }
1746
1747 item->SetParent( board() );
1748 }
1749
1750 // Update item attributes if needed
1751 if( BaseType( item->Type() ) == PCB_DIMENSION_T )
1752 {
1753 static_cast<PCB_DIMENSION_BASE*>( item )->UpdateUnits();
1754 }
1755 else if( item->Type() == PCB_FOOTPRINT_T )
1756 {
1757 FOOTPRINT* footprint = static_cast<FOOTPRINT*>( item );
1758
1759 // Update the footprint path with the new KIID path if the footprint is new
1760 if( aIsNew )
1761 footprint->SetPath( KIID_PATH() );
1762
1763 for( BOARD_ITEM* dwg : footprint->GraphicalItems() )
1764 {
1765 if( BaseType( dwg->Type() ) == PCB_DIMENSION_T )
1766 static_cast<PCB_DIMENSION_BASE*>( dwg )->UpdateUnits();
1767 }
1768 }
1769
1770 // We only need to add the items that aren't inside a group currently selected
1771 // to the selection. If an item is inside a group and that group is selected,
1772 // then the selection tool will select it for us.
1773 if( !item->GetParentGroup() || !alg::contains( aItems, item->GetParentGroup()->AsEdaItem() ) )
1774 itemsToSel.push_back( item );
1775 }
1776
1777 // Select the items that should be selected
1778 EDA_ITEMS toSel( itemsToSel.begin(), itemsToSel.end() );
1779 m_toolMgr->RunAction<EDA_ITEMS*>( ACTIONS::selectItems, &toSel );
1780
1781 // Reannotate duplicate footprints (make sense only in board editor )
1782 if( aReannotateDuplicates && m_isBoardEditor )
1783 m_toolMgr->GetTool<BOARD_REANNOTATE_TOOL>()->ReannotateDuplicatesInSelection();
1784
1785 for( BOARD_ITEM* item : aItems )
1786 {
1787 if( aIsNew )
1788 aCommit->Add( item );
1789 else
1790 aCommit->Added( item );
1791 }
1792
1793 PCB_SELECTION& selection = selectionTool->GetSelection();
1794
1795 if( selection.Size() > 0 )
1796 {
1797 if( aAnchorAtOrigin )
1798 {
1799 selection.SetReferencePoint( VECTOR2I( 0, 0 ) );
1800 }
1801 else if( BOARD_ITEM* item = dynamic_cast<BOARD_ITEM*>( selection.GetTopLeftItem() ) )
1802 {
1803 selection.SetReferencePoint( item->GetPosition() );
1804 }
1805
1806 getViewControls()->SetCursorPosition( getViewControls()->GetMousePosition(), false );
1807
1808 m_toolMgr->ProcessEvent( EVENTS::SelectedEvent );
1809
1810 if( !aSkipMove )
1811 return m_toolMgr->RunSynchronousAction( PCB_ACTIONS::move, aCommit );
1812 }
1813
1814 return true;
1815}
1816
1817
1818int PCB_CONTROL::AppendBoard( PCB_IO& pi, const wxString& fileName, DESIGN_BLOCK* aDesignBlock, BOARD_COMMIT* aCommit,
1819 bool aSkipMove )
1820{
1821 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
1822
1823 if( !editFrame )
1824 return 1;
1825
1826 BOARD* brd = board();
1827
1828 if( !brd )
1829 return 1;
1830
1831 // Give ourselves a commit to work with if we weren't provided one
1832 std::unique_ptr<BOARD_COMMIT> tempCommit;
1833 BOARD_COMMIT* commit = aCommit;
1834
1835 if( !commit )
1836 {
1837 tempCommit = std::make_unique<BOARD_COMMIT>( editFrame );
1838 commit = tempCommit.get();
1839 }
1840
1841 // Mark existing items, in order to know what are the new items so we can select only
1842 // the new items after loading
1843 for( PCB_TRACK* track : brd->Tracks() )
1844 track->SetFlags( SKIP_STRUCT );
1845
1846 for( FOOTPRINT* footprint : brd->Footprints() )
1847 footprint->SetFlags( SKIP_STRUCT );
1848
1849 for( PCB_GROUP* group : brd->Groups() )
1850 group->SetFlags( SKIP_STRUCT );
1851
1852 for( BOARD_ITEM* drawing : brd->Drawings() )
1853 drawing->SetFlags( SKIP_STRUCT );
1854
1855 for( ZONE* zone : brd->Zones() )
1856 zone->SetFlags( SKIP_STRUCT );
1857
1858 for( PCB_GENERATOR* generator : brd->Generators() )
1859 generator->SetFlags( SKIP_STRUCT );
1860
1861 std::map<wxString, wxString> oldProperties = brd->GetProperties();
1862 std::map<wxString, wxString> newProperties;
1863
1864 PAGE_INFO oldPageInfo = brd->GetPageSettings();
1865 TITLE_BLOCK oldTitleBlock = brd->GetTitleBlock();
1866
1867 // Keep also the count of copper layers, to adjust if necessary
1868 int initialCopperLayerCount = brd->GetCopperLayerCount();
1869 LSET initialEnabledLayers = brd->GetEnabledLayers();
1870
1871 // Load the data
1872 try
1873 {
1874 std::map<std::string, UTF8> props;
1875
1876 // PCB_IO_EAGLE can use this info to center the BOARD, but it does not yet.
1877
1878 props["page_width"] = std::to_string( editFrame->GetPageSizeIU().x );
1879 props["page_height"] = std::to_string( editFrame->GetPageSizeIU().y );
1880
1882 [&]( wxString aTitle, int aIcon, wxString aMessage, wxString aAction ) -> bool
1883 {
1884 KIDIALOG dlg( editFrame, aMessage, aTitle, wxOK | wxCANCEL | aIcon );
1885
1886 if( !aAction.IsEmpty() )
1887 dlg.SetOKLabel( aAction );
1888
1889 dlg.DoNotShowCheckbox( aMessage, 0 );
1890
1891 return dlg.ShowModal() == wxID_OK;
1892 } );
1893
1894 WX_PROGRESS_REPORTER progressReporter( editFrame, _( "Load PCB" ), 1, PR_CAN_ABORT );
1895
1897 pi.SetProgressReporter( &progressReporter );
1898 pi.LoadBoard( fileName, brd, &props, nullptr );
1899 }
1900 catch( const IO_ERROR& ioe )
1901 {
1902 DisplayErrorMessage( editFrame, _( "Error loading board." ), ioe.What() );
1903
1904 return 0;
1905 }
1906
1907 newProperties = brd->GetProperties();
1908
1909 for( const std::pair<const wxString, wxString>& prop : oldProperties )
1910 newProperties[ prop.first ] = prop.second;
1911
1912 brd->SetProperties( newProperties );
1913
1914 brd->SetPageSettings( oldPageInfo );
1915 brd->SetTitleBlock( oldTitleBlock );
1916
1917 // rebuild nets and ratsnest before any use of nets
1918 brd->BuildListOfNets();
1919 brd->SynchronizeNetsAndNetClasses( true );
1920 brd->BuildConnectivity();
1921
1922 // Synchronize layers
1923 // we should not ask PLUGINs to do these items:
1924 int copperLayerCount = brd->GetCopperLayerCount();
1925
1926 if( copperLayerCount > initialCopperLayerCount )
1927 brd->SetCopperLayerCount( copperLayerCount );
1928
1929 // Enable all used layers, and make them visible:
1930 LSET enabledLayers = brd->GetEnabledLayers();
1931 enabledLayers |= initialEnabledLayers;
1932 brd->SetEnabledLayers( enabledLayers );
1933 brd->SetVisibleLayers( enabledLayers );
1934
1935 int ret = 0;
1936
1937 bool placeAsGroup = false;
1938
1939 if( APP_SETTINGS_BASE* cfg = editFrame->config() )
1940 placeAsGroup = cfg->m_DesignBlockChooserPanel.place_as_group;
1941
1942 if( placeBoardItems( commit, brd, false, false /* Don't reannotate dupes on Append Board */, aSkipMove ) )
1943 {
1944 if( placeAsGroup )
1945 {
1946 PCB_GROUP* group = new PCB_GROUP( brd );
1947
1948 if( aDesignBlock )
1949 {
1950 group->SetName( aDesignBlock->GetLibId().GetLibItemName() );
1951 group->SetDesignBlockLibId( aDesignBlock->GetLibId() );
1952 }
1953 else
1954 {
1955 group->SetName( wxFileName( fileName ).GetName() );
1956 }
1957
1958 // Get the selection tool selection
1959 PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
1961
1962 for( EDA_ITEM* eda_item : selection )
1963 {
1964 if( eda_item->IsBOARD_ITEM() )
1965 {
1966 if( static_cast<BOARD_ITEM*>( eda_item )->IsLocked() )
1967 group->SetLocked( true );
1968 }
1969 }
1970
1971 commit->Add( group );
1972
1973 for( EDA_ITEM* eda_item : selection )
1974 {
1975 if( eda_item->IsBOARD_ITEM() && !static_cast<BOARD_ITEM*>( eda_item )->GetParentFootprint() )
1976 {
1977 commit->Modify( eda_item );
1978 group->AddItem( eda_item );
1979 }
1980 }
1981
1982 selTool->ClearSelection();
1983 selTool->select( group );
1984
1986 m_frame->OnModify();
1987 m_frame->Refresh();
1988 }
1989
1990 // If we were provided a commit, let the caller control when to push it
1991 if( !aCommit )
1992 commit->Push( aDesignBlock ? _( "Place Design Block" ) : _( "Append Board" ) );
1993
1994 editFrame->GetBoard()->BuildConnectivity();
1995 ret = 0;
1996 }
1997 else
1998 {
1999 // If we were provided a commit, let the caller control when to revert it
2000 if( !aCommit )
2001 commit->Revert();
2002
2003 ret = 1;
2004 }
2005
2006 // Refresh the UI for the updated board properties
2007 editFrame->GetAppearancePanel()->OnBoardChanged();
2008
2009 return ret;
2010}
2011
2012
2013int PCB_CONTROL::Undo( const TOOL_EVENT& aEvent )
2014{
2015 PCB_BASE_EDIT_FRAME* editFrame = dynamic_cast<PCB_BASE_EDIT_FRAME*>( m_frame );
2016 wxCommandEvent dummy;
2017
2018 if( editFrame )
2019 editFrame->RestoreCopyFromUndoList( dummy );
2020
2021 return 0;
2022}
2023
2024
2025int PCB_CONTROL::Redo( const TOOL_EVENT& aEvent )
2026{
2027 PCB_BASE_EDIT_FRAME* editFrame = dynamic_cast<PCB_BASE_EDIT_FRAME*>( m_frame );
2028 wxCommandEvent dummy;
2029
2030 if( editFrame )
2031 editFrame->RestoreCopyFromRedoList( dummy );
2032
2033 return 0;
2034}
2035
2036
2038{
2039 MAGNETIC_SETTINGS& settings = m_isFootprintEditor ? m_frame->GetFootprintEditorSettings()->m_MagneticItems
2040 : m_frame->GetPcbNewSettings()->m_MagneticItems;
2041 bool& snapMode = settings.allLayers;
2042
2044 snapMode = false;
2045 else if( aEvent.IsAction( &PCB_ACTIONS::magneticSnapAllLayers ) )
2046 snapMode = true;
2047 else
2048 snapMode = !snapMode;
2049
2051
2052 return 0;
2053}
2054
2055
2057{
2058 if( !Pgm().GetCommonSettings()->m_Input.hotkey_feedback )
2059 return 0;
2060
2061 wxArrayString labels;
2062 labels.Add( _( "Active Layer" ) );
2063 labels.Add( _( "All Layers" ) );
2064
2065 if( !m_frame->GetHotkeyPopup() )
2066 m_frame->CreateHotkeyPopup();
2067
2068 HOTKEY_CYCLE_POPUP* popup = m_frame->GetHotkeyPopup();
2069
2070 MAGNETIC_SETTINGS& settings = m_isFootprintEditor ? m_frame->GetFootprintEditorSettings()->m_MagneticItems
2071 : m_frame->GetPcbNewSettings()->m_MagneticItems;
2072
2073 if( popup )
2074 popup->Popup( _( "Object Snapping" ), labels, static_cast<int>( settings.allLayers ) );
2075
2076 return 0;
2077}
2078
2079
2081{
2082 PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
2083 ROUTER_TOOL* routerTool = m_toolMgr->GetTool<ROUTER_TOOL>();
2084 PCB_SELECTION& selection = selTool->GetSelection();
2085 PCB_EDIT_FRAME* pcbFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
2086 std::shared_ptr<DRC_ENGINE> drcEngine = m_frame->GetBoard()->GetDesignSettings().m_DRCEngine;
2087 DRC_CONSTRAINT constraint;
2088
2089 std::vector<MSG_PANEL_ITEM> msgItems;
2090
2091 if( routerTool && routerTool->RoutingInProgress() )
2092 {
2093 routerTool->UpdateMessagePanel();
2094 return 0;
2095 }
2096
2097 if( !pcbFrame && !m_frame->GetModel() )
2098 return 0;
2099
2100 if( selection.Empty() )
2101 {
2102 if( !pcbFrame )
2103 {
2104 FOOTPRINT* fp = static_cast<FOOTPRINT*>( m_frame->GetModel() );
2105 fp->GetMsgPanelInfo( m_frame, msgItems );
2106 }
2107 else
2108 {
2109 m_frame->SetMsgPanel( m_frame->GetBoard() );
2110 }
2111 }
2112 else if( selection.GetSize() == 1 )
2113 {
2114 EDA_ITEM* item = selection.Front();
2115
2116 if( std::optional<wxString> uuid = GetMsgPanelDisplayUuid( item->m_Uuid ) )
2117 msgItems.emplace_back( _( "UUID" ), *uuid );
2118
2119 item->GetMsgPanelInfo( m_frame, msgItems );
2120
2121 PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( item );
2122 NETINFO_ITEM* net = track ? track->GetNet() : nullptr;
2123 NETINFO_ITEM* coupledNet = net ? m_frame->GetBoard()->DpCoupledNet( net ) : nullptr;
2124
2125 if( coupledNet )
2126 {
2127 SEG trackSeg( track->GetStart(), track->GetEnd() );
2128 PCB_TRACK* coupledItem = nullptr;
2129 SEG::ecoord closestDist_sq = VECTOR2I::ECOORD_MAX;
2130
2131 for( PCB_TRACK* candidate : m_frame->GetBoard()->Tracks() )
2132 {
2133 if( candidate->GetNet() != coupledNet )
2134 continue;
2135
2136 SEG::ecoord dist_sq = trackSeg.SquaredDistance( SEG( candidate->GetStart(),
2137 candidate->GetEnd() ) );
2138
2139 if( !coupledItem || dist_sq < closestDist_sq )
2140 {
2141 coupledItem = candidate;
2142 closestDist_sq = dist_sq;
2143 }
2144 }
2145
2146 constraint = drcEngine->EvalRules( DIFF_PAIR_GAP_CONSTRAINT, track, coupledItem,
2147 track->GetLayer() );
2148
2149 wxString msg = m_frame->MessageTextFromMinOptMax( constraint.Value() );
2150
2151 if( !msg.IsEmpty() )
2152 {
2153 msgItems.emplace_back( wxString::Format( _( "DP Gap Constraints: %s" ), msg ),
2154 wxString::Format( _( "(from %s)" ), constraint.GetName() ) );
2155 }
2156
2157 constraint = drcEngine->EvalRules( MAX_UNCOUPLED_CONSTRAINT, track,
2158 coupledItem, track->GetLayer() );
2159
2160 if( constraint.Value().HasMax() )
2161 {
2162 msg = m_frame->MessageTextFromValue( constraint.Value().Max() );
2163 msgItems.emplace_back( wxString::Format( _( "DP Max Uncoupled-length: %s" ), msg ),
2164 wxString::Format( _( "(from %s)" ), constraint.GetName() ) );
2165 }
2166 }
2167 }
2168 else if( pcbFrame && selection.GetSize() == 2 )
2169 {
2170 // Pair selection broken into multiple, optional data, starting with the selected item
2171 // names
2172
2173 BOARD_ITEM* a = dynamic_cast<BOARD_ITEM*>( selection[0] );
2174 BOARD_ITEM* b = dynamic_cast<BOARD_ITEM*>( selection[1] );
2175
2176 if( a && b )
2177 {
2178 msgItems.emplace_back( MSG_PANEL_ITEM( a->GetItemDescription( m_frame, false ),
2179 b->GetItemDescription( m_frame, false ) ) );
2180 }
2181
2182 BOARD_CONNECTED_ITEM* a_conn = dynamic_cast<BOARD_CONNECTED_ITEM*>( a );
2183 BOARD_CONNECTED_ITEM* b_conn = dynamic_cast<BOARD_CONNECTED_ITEM*>( b );
2184
2185 if( a_conn && b_conn )
2186 {
2187 LSET overlap = a_conn->GetLayerSet() & b_conn->GetLayerSet() & LSET::AllCuMask();
2188 int a_netcode = a_conn->GetNetCode();
2189 int b_netcode = b_conn->GetNetCode();
2190
2191 if( overlap.count() > 0 )
2192 {
2193 PCB_LAYER_ID layer = overlap.CuStack().front();
2194
2195 if( a_netcode != b_netcode || a_netcode < 0 || b_netcode < 0 )
2196 {
2197 constraint = drcEngine->EvalRules( CLEARANCE_CONSTRAINT, a, b, layer );
2198 msgItems.emplace_back( _( "Resolved Clearance" ),
2199 m_frame->MessageTextFromValue( constraint.m_Value.Min() ) );
2200 }
2201
2202 std::shared_ptr<SHAPE> a_shape( a_conn->GetEffectiveShape( layer ) );
2203 std::shared_ptr<SHAPE> b_shape( b_conn->GetEffectiveShape( layer ) );
2204
2205 int actual_clearance = a_shape->GetClearance( b_shape.get() );
2206
2207 if( actual_clearance > -1 && actual_clearance < std::numeric_limits<int>::max() )
2208 {
2209 msgItems.emplace_back( _( "Actual Clearance" ),
2210 m_frame->MessageTextFromValue( actual_clearance ) );
2211 }
2212 }
2213 }
2214
2215 if( a && b && ( a->HasHole() || b->HasHole() ) )
2216 {
2217 PCB_LAYER_ID active = m_frame->GetActiveLayer();
2219
2220 if( b->IsOnLayer( active ) && IsCopperLayer( active ) )
2221 layer = active;
2222 else if( b->HasHole() && a->IsOnLayer( active ) && IsCopperLayer( active ) )
2223 layer = active;
2224 else if( a->HasHole() && b->IsOnCopperLayer() )
2225 layer = b->GetLayer();
2226 else if( b->HasHole() && a->IsOnCopperLayer() )
2227 layer = a->GetLayer();
2228
2229 if( IsCopperLayer( layer ) )
2230 {
2231 int actual = std::numeric_limits<int>::max();
2232
2233 if( a->HasHole() && b->IsOnCopperLayer() )
2234 {
2235 std::shared_ptr<SHAPE_SEGMENT> hole = a->GetEffectiveHoleShape();
2236 std::shared_ptr<SHAPE> other( b->GetEffectiveShape( layer ) );
2237
2238 actual = std::min( actual, hole->GetClearance( other.get() ) );
2239 }
2240
2241 if( b->HasHole() && a->IsOnCopperLayer() )
2242 {
2243 std::shared_ptr<SHAPE_SEGMENT> hole = b->GetEffectiveHoleShape();
2244 std::shared_ptr<SHAPE> other( a->GetEffectiveShape( layer ) );
2245
2246 actual = std::min( actual, hole->GetClearance( other.get() ) );
2247 }
2248
2249 if( actual < std::numeric_limits<int>::max() )
2250 {
2251 constraint = drcEngine->EvalRules( HOLE_CLEARANCE_CONSTRAINT, a, b, layer );
2252 msgItems.emplace_back( _( "Resolved Hole Clearance" ),
2253 m_frame->MessageTextFromValue( constraint.m_Value.Min() ) );
2254
2255 if( actual > -1 && actual < std::numeric_limits<int>::max() )
2256 {
2257 msgItems.emplace_back( _( "Actual Hole Clearance" ),
2258 m_frame->MessageTextFromValue( actual ) );
2259 }
2260 }
2261 }
2262 }
2263
2264 if( a && b )
2265 {
2266 for( PCB_LAYER_ID edgeLayer : { Edge_Cuts, Margin } )
2267 {
2268 PCB_LAYER_ID active = m_frame->GetActiveLayer();
2270
2271 if( a->IsOnLayer( edgeLayer ) && b->Type() != PCB_FOOTPRINT_T )
2272 {
2273 if( b->IsOnLayer( active ) && IsCopperLayer( active ) )
2274 layer = active;
2275 else if( IsCopperLayer( b->GetLayer() ) )
2276 layer = b->GetLayer();
2277 }
2278 else if( b->IsOnLayer( edgeLayer ) && a->Type() != PCB_FOOTPRINT_T )
2279 {
2280 if( a->IsOnLayer( active ) && IsCopperLayer( active ) )
2281 layer = active;
2282 else if( IsCopperLayer( a->GetLayer() ) )
2283 layer = a->GetLayer();
2284 }
2285
2286 if( layer >= 0 )
2287 {
2288 constraint = drcEngine->EvalRules( EDGE_CLEARANCE_CONSTRAINT, a, b, layer );
2289
2290 if( edgeLayer == Edge_Cuts )
2291 {
2292 msgItems.emplace_back( _( "Resolved Edge Clearance" ),
2293 m_frame->MessageTextFromValue( constraint.m_Value.Min() ) );
2294 }
2295 else
2296 {
2297 msgItems.emplace_back( _( "Resolved Margin Clearance" ),
2298 m_frame->MessageTextFromValue( constraint.m_Value.Min() ) );
2299 }
2300 }
2301 }
2302 }
2303 }
2304
2305 if( selection.GetSize() )
2306 {
2307 if( msgItems.empty() )
2308 {
2309 msgItems.emplace_back( _( "Selected Items" ),
2310 wxString::Format( wxT( "%d" ), selection.GetSize() ) );
2311
2312 if( m_isBoardEditor )
2313 {
2314 std::set<wxString> netNames;
2315 std::set<wxString> netClasses;
2316
2317 for( EDA_ITEM* item : selection )
2318 {
2319 if( BOARD_CONNECTED_ITEM* bci = dynamic_cast<BOARD_CONNECTED_ITEM*>( item ) )
2320 {
2321 netNames.insert( UnescapeString( bci->GetNetname() ) );
2322 netClasses.insert( UnescapeString( bci->GetEffectiveNetClass()->GetHumanReadableName() ) );
2323
2324 if( netNames.size() > 1 && netClasses.size() > 1 )
2325 break;
2326 }
2327 }
2328
2329 if( netNames.size() == 1 )
2330 msgItems.emplace_back( _( "Net" ), *netNames.begin() );
2331
2332 if( netClasses.size() == 1 )
2333 msgItems.emplace_back( _( "Resolved Netclass" ), *netClasses.begin() );
2334 }
2335 }
2336
2337 if( selection.GetSize() >= 2 )
2338 {
2339 bool lengthValid = true;
2340 double selectedLength = 0;
2341
2342 // Lambda to accumulate track length if item is a track or arc, otherwise mark invalid
2343 std::function<void( EDA_ITEM* )> accumulateTrackLength;
2344
2345 accumulateTrackLength =
2346 [&]( EDA_ITEM* aItem )
2347 {
2348 if( aItem->Type() == PCB_TRACE_T || aItem->Type() == PCB_ARC_T )
2349 {
2350 selectedLength += static_cast<PCB_TRACK*>( aItem )->GetLength();
2351 }
2352 else if( aItem->Type() == PCB_VIA_T )
2353 {
2354 // zero 2D length
2355 }
2356 else if( aItem->Type() == PCB_SHAPE_T )
2357 {
2358 PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( aItem );
2359
2360 if( shape->GetShape() == SHAPE_T::SEGMENT
2361 || shape->GetShape() == SHAPE_T::ARC
2362 || shape->GetShape() == SHAPE_T::BEZIER )
2363 {
2364 selectedLength += shape->GetLength();
2365 }
2366 else
2367 {
2368 lengthValid = false;
2369 }
2370 }
2371 // Use dynamic_cast to include PCB_GENERATORs.
2372 else if( PCB_GROUP* group = dynamic_cast<PCB_GROUP*>( aItem ) )
2373 {
2374 group->RunOnChildren( accumulateTrackLength, RECURSE_MODE::RECURSE );
2375 }
2376 else
2377 {
2378 lengthValid = false;
2379 }
2380 };
2381
2382 for( EDA_ITEM* item : selection )
2383 {
2384 if( lengthValid )
2385 accumulateTrackLength( item );
2386 }
2387
2388 if( lengthValid )
2389 {
2390 msgItems.emplace_back( _( "Selected 2D Length" ),
2391 m_frame->MessageTextFromValue( selectedLength ) );
2392 }
2393 }
2394
2395 if( selection.GetSize() >= 2 && selection.GetSize() < 100 )
2396 {
2397 LSET enabledCopper = LSET::AllCuMask( m_frame->GetBoard()->GetCopperLayerCount() );
2398 bool areaValid = true;
2399
2400 std::map<PCB_LAYER_ID, SHAPE_POLY_SET> copperPolys;
2401 SHAPE_POLY_SET holes;
2402
2403 std::function<void( EDA_ITEM* )> accumulateArea;
2404
2405 accumulateArea =
2406 [&]( EDA_ITEM* aItem )
2407 {
2408 if( aItem->Type() == PCB_FOOTPRINT_T || aItem->Type() == PCB_MARKER_T )
2409 {
2410 areaValid = false;
2411 return;
2412 }
2413
2414 if( PCB_GROUP* group = dynamic_cast<PCB_GROUP*>( aItem ) )
2415 {
2416 group->RunOnChildren( accumulateArea, RECURSE_MODE::RECURSE );
2417 return;
2418 }
2419
2420 if( BOARD_ITEM* boardItem = dynamic_cast<BOARD_ITEM*>( aItem ) )
2421 {
2422 boardItem->RunOnChildren( accumulateArea, RECURSE_MODE::NO_RECURSE );
2423
2424 for( PCB_LAYER_ID layer : LSET( boardItem->GetLayerSet() & enabledCopper ) )
2425 {
2426 boardItem->TransformShapeToPolySet( copperPolys[layer], layer, 0,
2428 }
2429
2430 if( aItem->Type() == PCB_PAD_T && static_cast<PAD*>( aItem )->HasHole() )
2431 {
2432 static_cast<PAD*>( aItem )->TransformHoleToPolygon( holes, 0, ARC_LOW_DEF,
2433 ERROR_OUTSIDE );
2434 }
2435 else if( aItem->Type() == PCB_VIA_T )
2436 {
2437 PCB_VIA* via = static_cast<PCB_VIA*>( aItem );
2438 VECTOR2I center = via->GetPosition();
2439 int R = via->GetDrillValue() / 2;
2440
2442 }
2443 }
2444 };
2445
2446 for( EDA_ITEM* item : selection )
2447 {
2448 if( areaValid )
2449 accumulateArea( item );
2450 }
2451
2452 if( areaValid )
2453 {
2454 double area = 0.0;
2455
2456 for( auto& [layer, copperPoly] : copperPolys )
2457 {
2458 copperPoly.BooleanSubtract( holes );
2459 area += copperPoly.Area();
2460 }
2461
2462 msgItems.emplace_back( _( "Selected 2D Copper Area" ),
2463 m_frame->MessageTextFromValue( area, true, EDA_DATA_TYPE::AREA ) );
2464 }
2465 }
2466 }
2467 else
2468 {
2469 m_frame->GetBoard()->GetMsgPanelInfo( m_frame, msgItems );
2470 }
2471
2472 m_frame->SetMsgPanel( msgItems );
2473
2474 // Update vertex editor if it exists
2475 PCB_BASE_EDIT_FRAME* editFrame = dynamic_cast<PCB_BASE_EDIT_FRAME*>( m_frame );
2476 if( editFrame )
2477 {
2478 BOARD_ITEM* selectedItem = ( selection.GetSize() == 1 ) ?
2479 dynamic_cast<BOARD_ITEM*>( selection.Front() ) : nullptr;
2480 editFrame->UpdateVertexEditorSelection( selectedItem );
2481 }
2482
2483 return 0;
2484}
2485
2486
2488{
2489 wxFileName fileName = wxFileName( *aEvent.Parameter<wxString*>() );
2490
2491 PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
2492
2493 if( !editFrame )
2494 return 1;
2495
2496 wxString filePath = fileName.GetFullPath();
2498 IO_RELEASER<PCB_IO> pi( PCB_IO_MGR::PluginFind( pluginType ) );
2499
2500 if( !pi )
2501 return 1;
2502
2503 return AppendBoard( *pi, filePath );
2504}
2505
2506
2508{
2509 BOARD_COMMIT commit( this );
2510 BOARD_DESIGN_SETTINGS& settings = m_frame->GetBoard()->GetDesignSettings();
2511 BOARD_STACKUP& stackup = settings.GetStackupDescriptor();
2512
2513 stackup.SynchronizeWithBoard( &settings );
2514
2515 PCB_TABLE* table = new PCB_TABLE( m_frame->GetModel(), pcbIUScale.mmToIU( DEFAULT_LINE_WIDTH ) );
2516 table->SetLayer( m_frame->GetActiveLayer() );
2517 table->SetColCount( 4 );
2518
2519 auto addHeaderCell =
2520 [&]( const wxString& text )
2521 {
2522 PCB_TABLECELL* c = new PCB_TABLECELL( table );
2523 c->SetTextSize( VECTOR2I( pcbIUScale.mmToIU( 2.0 ), pcbIUScale.mmToIU( 2.0 ) ) );
2524 c->SetTextThickness( pcbIUScale.mmToIU( 0.4 ) );
2525 c->SetText( text );
2526 c->SetColSpan( table->GetColCount() );
2527 table->AddCell( c );
2528 };
2529
2530 auto addDataCell =
2531 [&]( const wxString& text )
2532 {
2533 PCB_TABLECELL* c = new PCB_TABLECELL( table );
2534 c->SetTextSize( VECTOR2I( pcbIUScale.mmToIU( 1.5 ), pcbIUScale.mmToIU( 1.5 ) ) );
2535 c->SetTextThickness( pcbIUScale.mmToIU( 0.2 ) );
2536 c->SetText( text );
2537 table->AddCell( c );
2538 };
2539
2540 addHeaderCell( _( "BOARD CHARACTERISTICS" ) );
2541
2542 for( int col = 1; col < table->GetColCount(); ++col )
2543 {
2544 addHeaderCell( wxEmptyString );
2545 table->GetCell( 0, col )->SetColSpan( 0 );
2546 }
2547
2548 addDataCell( _( "Copper layer count: " ) );
2550 settings.GetCopperLayerCount(), false ) );
2551
2552 addDataCell( _( "Board thickness: " ) );
2553 addDataCell( m_frame->MessageTextFromValue( settings.GetBoardThickness(), true ) );
2554
2555 SHAPE_POLY_SET outline;
2556 m_frame->GetBoard()->GetBoardPolygonOutlines( outline );
2557 BOX2I size = outline.BBox();
2558
2559 addDataCell( _( "Board overall dimensions: " ) );
2560 addDataCell( wxString::Format( wxT( "%s x %s" ),
2561 m_frame->MessageTextFromValue( size.GetWidth(), true ),
2562 m_frame->MessageTextFromValue( size.GetHeight(), true ) ) );
2563
2564 addDataCell( wxEmptyString );
2565 addDataCell( wxEmptyString );
2566
2567 addDataCell( _( "Min track/spacing: " ) );
2568 addDataCell( wxString::Format( wxT( "%s / %s" ),
2569 m_frame->MessageTextFromValue( settings.m_TrackMinWidth, true ),
2570 m_frame->MessageTextFromValue( settings.m_MinClearance, true ) ) );
2571
2572 double holeSize = std::min( settings.m_MinThroughDrill, settings.m_ViasMinSize );
2573
2574 addDataCell( _( "Min hole diameter: " ) );
2575 addDataCell( m_frame->MessageTextFromValue( holeSize, true ) );
2576
2577 addDataCell( _( "Copper finish: " ) );
2578 addDataCell( stackup.m_FinishType );
2579
2580 addDataCell( _( "Impedance control: " ) );
2581 addDataCell( stackup.m_HasDielectricConstrains ? _( "Yes" ) : _( "No" ) );
2582
2583 addDataCell( _( "Castellated pads: " ) );
2584 int castellated_pad_count = m_frame->GetBoard()->GetPadWithCastellatedAttrCount();
2585 addDataCell( castellated_pad_count ? _( "Yes" ) : _( "No" ) );
2586
2587 addDataCell( _( "Press-fit pads: " ) );
2588 int pressfit_pad_count = m_frame->GetBoard()->GetPadWithPressFitAttrCount();
2589 addDataCell( pressfit_pad_count ? _( "Yes" ) : _( "No" ) );
2590
2591 addDataCell( _( "Plated board edge: " ) );
2592 addDataCell( stackup.m_EdgePlating ? _( "Yes" ) : _( "No" ) );
2593
2594 wxString msg;
2595
2596 switch( stackup.m_EdgeConnectorConstraints )
2597 {
2598 case BS_EDGE_CONNECTOR_NONE: msg = _( "No" ); break;
2599 case BS_EDGE_CONNECTOR_IN_USE: msg = _( "Yes" ); break;
2600 case BS_EDGE_CONNECTOR_BEVELLED: msg = _( "Yes, Bevelled" ); break;
2601 }
2602
2603 addDataCell( _( "Edge card connectors: " ) );
2604 addDataCell( msg );
2605
2606 // We are building a table having 4 columns.
2607 // So we must have a cell count multible of 4, to have fully build row.
2608 // Othewise the table is really badly drawn.
2609 std::vector<PCB_TABLECELL*> cells_list = table->GetCells();
2610 int cell_to_add_cnt = cells_list.size() % table->GetColCount();
2611
2612 for( int ii = 0; ii < cell_to_add_cnt; ii++ )
2613 addDataCell( wxEmptyString );
2614
2615 table->SetStrokeExternal( false );
2616 table->SetStrokeHeaderSeparator( false );
2617 table->SetStrokeColumns( false );
2618 table->SetStrokeRows( false );
2619 table->Autosize();
2620
2621 std::vector<BOARD_ITEM*> items;
2622 items.push_back( table );
2623
2624 if( placeBoardItems( &commit, items, true, true, false, false ) )
2625 commit.Push( _( "Place Board Characteristics" ) );
2626 else
2627 delete table;
2628
2629 return 0;
2630}
2631
2632
2633
2635{
2636 BOARD_COMMIT commit( this );
2637 BOARD_DESIGN_SETTINGS& settings = m_frame->GetBoard()->GetDesignSettings();
2638 BOARD_STACKUP& stackup = settings.GetStackupDescriptor();
2639
2640 stackup.SynchronizeWithBoard( &settings );
2641
2642 std::vector<BOARD_STACKUP_ITEM*> layers = stackup.GetList();
2643
2644 PCB_TABLE* table = new PCB_TABLE( m_frame->GetModel(), pcbIUScale.mmToIU( DEFAULT_LINE_WIDTH ) );
2645 table->SetLayer( m_frame->GetActiveLayer() );
2646 table->SetColCount( 7 );
2647
2648 const auto addHeaderCell =
2649 [&]( const wxString& text )
2650 {
2651 PCB_TABLECELL* c = new PCB_TABLECELL( table );
2652 c->SetTextSize( VECTOR2I( pcbIUScale.mmToIU( 1.5 ), pcbIUScale.mmToIU( 1.5 ) ) );
2653 c->SetTextThickness( pcbIUScale.mmToIU( 0.3 ) );
2654 c->SetText( text );
2655 table->AddCell( c );
2656 };
2657
2658 const auto addDataCell =
2659 [&]( const wxString& text, const char align = 'L' )
2660 {
2661 PCB_TABLECELL* c = new PCB_TABLECELL( table );
2662 c->SetTextSize( VECTOR2I( pcbIUScale.mmToIU( 1.5 ), pcbIUScale.mmToIU( 1.5 ) ) );
2663 c->SetTextThickness( pcbIUScale.mmToIU( 0.2 ) );
2664
2665 if( align == 'R' )
2667
2668 c->SetText( text );
2669 table->AddCell( c );
2670 };
2671
2672 const auto layerThicknessString =
2673 [&]( const BOARD_STACKUP_ITEM& aStackupItem, int aSublayerId )
2674 {
2675 const int layerThickness = aStackupItem.GetThickness( aSublayerId );
2676
2677 // Layers like silkscreen, paste, etc. have no defined thickness, but that
2678 // does not mean that they are specified as exactly 0mm
2679 if( !aStackupItem.IsThicknessEditable() )
2680 return NotSpecifiedPrm();
2681
2682 return m_frame->StringFromValue( layerThickness, true );
2683 };
2684
2685 addHeaderCell( _( "Layer Name" ) );
2686 addHeaderCell( _( "Type" ) );
2687 addHeaderCell( _( "Material" ) );
2688 addHeaderCell( _( "Thickness" ) );
2689 addHeaderCell( _( "Color" ) );
2690 addHeaderCell( _( "Epsilon R" ) );
2691 addHeaderCell( _( "Loss Tangent" ) );
2692
2693 for( int i = 0; i < stackup.GetCount(); i++ )
2694 {
2695 BOARD_STACKUP_ITEM* stackup_item = layers.at( i );
2696
2697 for( int sublayer_id = 0; sublayer_id < stackup_item->GetSublayersCount(); sublayer_id++ )
2698 {
2699 // Layer names are empty until we close at least once the board setup dialog.
2700 // If the user did not open the dialog, then get the names from the board.
2701 // But dielectric layer names will be missing.
2702 // In this case, for dielectric, a dummy name will be used
2703 if( stackup_item->GetLayerName().IsEmpty() )
2704 {
2705 wxString layerName;
2706
2707 if( IsValidLayer( stackup_item->GetBrdLayerId() ) )
2708 layerName = m_frame->GetBoard()->GetLayerName( stackup_item->GetBrdLayerId() );
2709
2710 if( layerName.IsEmpty() && stackup_item->GetType() == BS_ITEM_TYPE_DIELECTRIC )
2711 layerName = _( "Dielectric" );
2712
2713 addDataCell( layerName );
2714 }
2715 else
2716 {
2717 addDataCell( stackup_item->GetLayerName() );
2718 }
2719
2720 addDataCell( InitialCaps( stackup_item->GetTypeName() ) );
2721 addDataCell( stackup_item->GetMaterial( sublayer_id ) );
2722 addDataCell( layerThicknessString( *stackup_item, sublayer_id ), 'R' );
2723 addDataCell( stackup_item->GetColor( sublayer_id ) );
2725 stackup_item->GetEpsilonR( sublayer_id ) ), 'R' );
2727 stackup_item->GetLossTangent( sublayer_id ) ), 'R' );
2728 }
2729 }
2730
2731 table->Autosize();
2732
2733 std::vector<BOARD_ITEM*> items;
2734 items.push_back( table );
2735
2736 if( placeBoardItems( &commit, items, true, true, false, false ) )
2737 commit.Push( _( "Place Board Stackup Table" ) );
2738 else
2739 delete table;
2740
2741 return 0;
2742}
2743
2744
2745
2747{
2748 view()->SetMirror( !view()->IsMirroredX(), false );
2749 view()->RecacheAllItems();
2750 m_frame->GetCanvas()->ForceRefresh();
2751 m_frame->OnDisplayOptionsChanged();
2752 return 0;
2753}
2754
2755
2757{
2758 if( aItem->Type() == PCB_SHAPE_T )
2759 {
2760 static_cast<PCB_SHAPE*>( aItem )->UpdateHatching();
2761
2762 if( view() )
2763 view()->Update( aItem );
2764 }
2765}
2766
2767
2769{
2770 for( FOOTPRINT* footprint : board()->Footprints() )
2771 footprint->RunOnChildren( std::bind( &PCB_CONTROL::rehatchBoardItem, this, _1 ), NO_RECURSE );
2772
2773 for( BOARD_ITEM* item : board()->Drawings() )
2774 rehatchBoardItem( item );
2775
2776 return 0;
2777}
2778
2779
2781{
2782 BOARD* brd = board();
2783
2784 if( !brd )
2785 return 0;
2786
2787 PROJECT& prj = m_frame->Prj();
2789 FILENAME_RESOLVER* resolver = cache ? cache->GetResolver() : nullptr;
2790
2791 wxString workingPath = prj.GetProjectPath();
2792 std::vector<const EMBEDDED_FILES*> stack;
2793 stack.push_back( brd->GetEmbeddedFiles() );
2794
2795 BOARD_COMMIT commit( m_frame );
2796 int embeddedCount = 0;
2797
2798 for( FOOTPRINT* fp : brd->Footprints() )
2799 {
2800 bool fpModified = false;
2801
2802 for( FP_3DMODEL& model : fp->Models() )
2803 {
2804 if( model.m_Filename.StartsWith( FILEEXT::KiCadUriPrefix ) )
2805 continue;
2806
2807 wxString fullPath =
2808 resolver ? resolver->ResolvePath( model.m_Filename, workingPath, stack ) : model.m_Filename;
2809 wxFileName fname( fullPath );
2810
2811 if( fname.Exists() )
2812 {
2813 if( EMBEDDED_FILES::EMBEDDED_FILE* file = brd->GetEmbeddedFiles()->AddFile( fname, false ) )
2814 {
2815 model.m_Filename = file->GetLink();
2816 fpModified = true;
2817 embeddedCount++;
2818 }
2819 }
2820 }
2821
2822 if( fpModified )
2823 commit.Modify( fp );
2824 }
2825
2826 if( embeddedCount > 0 )
2827 {
2828 commit.Push( _( "Embed 3D Models" ) );
2829 wxString msg = wxString::Format( _( "%d 3D model(s) successfully embedded." ), embeddedCount );
2830 m_frame->GetInfoBar()->ShowMessageFor( msg, 5000 );
2831 }
2832
2833 return 0;
2834}
2835
2836
2837// clang-format off
2839{
2842 Go( &PCB_CONTROL::Print, ACTIONS::print.MakeEvent() );
2843 Go( &PCB_CONTROL::Quit, ACTIONS::quit.MakeEvent() );
2844
2845 // Footprint library actions
2850
2851 // Display modes
2868
2869 // Layer control
2907
2910
2911 // Grid control
2914
2915 Go( &PCB_CONTROL::Undo, ACTIONS::undo.MakeEvent() );
2916 Go( &PCB_CONTROL::Redo, ACTIONS::redo.MakeEvent() );
2917
2918 // Snapping control
2923
2924 // Miscellaneous
2927
2928 // Append control
2937
2938 Go( &PCB_CONTROL::Paste, ACTIONS::paste.MakeEvent() );
2940
2947
2948 // Add library by dropping file
2951}
2952// clang-format on
int color
@ ERROR_OUTSIDE
@ ERROR_INSIDE
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:112
constexpr int ARC_LOW_DEF
Definition base_units.h:128
constexpr EDA_IU_SCALE unityScale
Definition base_units.h:115
#define DEFAULT_LINE_WIDTH
@ 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)
@ BS_EDGE_CONNECTOR_BEVELLED
@ BS_EDGE_CONNECTOR_NONE
@ BS_EDGE_CONNECTOR_IN_USE
@ BS_ITEM_TYPE_DIELECTRIC
BOX2< VECTOR2I > BOX2I
Definition box2.h:922
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:990
static TOOL_ACTION paste
Definition actions.h:80
static TOOL_ACTION addLibrary
Definition actions.h:56
static TOOL_ACTION pickerTool
Definition actions.h:252
static TOOL_ACTION gridResetOrigin
Definition actions.h:195
static TOOL_ACTION pasteSpecial
Definition actions.h:81
static TOOL_ACTION highContrastModeCycle
Definition actions.h:155
static TOOL_ACTION undo
Definition actions.h:75
static TOOL_ACTION highContrastMode
Definition actions.h:154
static TOOL_ACTION quit
Definition actions.h:66
static TOOL_ACTION redo
Definition actions.h:76
static TOOL_ACTION deleteTool
Definition actions.h:86
static TOOL_ACTION selectionClear
Clear the current selection.
Definition actions.h:223
static TOOL_ACTION print
Definition actions.h:64
static TOOL_ACTION newLibrary
Definition actions.h:55
static TOOL_ACTION gridSetOrigin
Definition actions.h:194
static TOOL_ACTION ddAddLibrary
Definition actions.h:67
static TOOL_ACTION selectItems
Select a list of items (specified as the event parameter)
Definition actions.h:231
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
APP_SETTINGS_BASE is a settings class that should be derived for each standalone KiCad application.
virtual void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Execute the changes.
virtual void Revert() override
Revert the commit by restoring the modified items state.
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
NETINFO_ITEM * GetNet() const
Return #NET_INFO object for a given item.
Container for design settings for a BOARD object.
std::shared_ptr< NET_SETTINGS > m_NetSettings
void SetGridOrigin(const VECTOR2I &aOrigin)
int GetBoardThickness() const
The full thickness of the board including copper and masks.
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:79
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition board_item.h:232
virtual bool IsOnLayer(PCB_LAYER_ID aLayer) const
Test to see if this object is on the given layer.
Definition board_item.h:314
virtual std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING aFlash=FLASHING::DEFAULT) const
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
FOOTPRINT * GetParentFootprint() const
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition board_item.h:252
virtual bool IsOnCopperLayer() const
Definition board_item.h:151
virtual std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape() const
virtual bool HasHole() const
Definition board_item.h:156
Manage one layer needed to make a physical board.
wxString GetTypeName() const
int GetSublayersCount() const
double GetEpsilonR(int aDielectricSubLayer=0) const
wxString GetColor(int aDielectricSubLayer=0) const
wxString GetLayerName() const
PCB_LAYER_ID GetBrdLayerId() const
bool IsThicknessEditable() const
int GetThickness(int aDielectricSubLayer=0) const
BOARD_STACKUP_ITEM_TYPE GetType() const
wxString GetMaterial(int aDielectricSubLayer=0) const
double GetLossTangent(int aDielectricSubLayer=0) const
Manage layers needed to make a physical board.
const std::vector< BOARD_STACKUP_ITEM * > & GetList() const
int GetCount() const
bool SynchronizeWithBoard(BOARD_DESIGN_SETTINGS *aSettings)
Synchronize the BOARD_STACKUP_ITEM* list with the board.
bool m_HasDielectricConstrains
True if some layers have impedance controlled tracks or have specific constrains for micro-wave appli...
bool m_EdgePlating
True if the edge board is plated.
BS_EDGE_CONNECTOR_CONSTRAINTS m_EdgeConnectorConstraints
If the board has edge connector cards, some constrains can be specified in job file: BS_EDGE_CONNECTO...
wxString m_FinishType
The name of external copper finish.
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:322
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:2123
EMBEDDED_FILES * GetEmbeddedFiles() override
Definition board.cpp:2840
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:956
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:2935
void BuildListOfNets()
Definition board.h:916
const GENERATORS & Generators() const
Definition board.h:369
const std::vector< BOARD_CONNECTED_ITEM * > AllConnectedItems()
Definition board.cpp:2909
const PAGE_INFO & GetPageSettings() const
Definition board.h:758
void SetProperties(const std::map< wxString, wxString > &aProps)
Definition board.h:401
const ZONES & Zones() const
Definition board.h:367
const GROUPS & Groups() const
The groups must maintain the following invariants.
Definition board.h:396
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:189
void SynchronizeNetsAndNetClasses(bool aResetTrackAndViaSizes)
Copy NETCLASS info to each NET, based on NET membership in a NETCLASS.
Definition board.cpp:2417
FOOTPRINT * GetFirstFootprint() const
Get the first footprint on the board or nullptr.
Definition board.h:505
TITLE_BLOCK & GetTitleBlock()
Definition board.h:764
int GetCopperLayerCount() const
Definition board.cpp:876
const std::map< wxString, wxString > & GetProperties() const
Definition board.h:400
const FOOTPRINTS & Footprints() const
Definition board.h:363
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:1445
const TRACKS & Tracks() const
Definition board.h:361
void SetPageSettings(const PAGE_INFO &aPageSettings)
Definition board.h:759
void SetCopperLayerCount(int aCount)
Definition board.cpp:882
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:930
const LSET & GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition board.cpp:924
void SetEnabledLayers(const LSET &aLayerMask)
A proxy function that calls the correspondent function in m_BoardSettings.
Definition board.cpp:944
void SetTitleBlock(const TITLE_BLOCK &aTitleBlock)
Definition board.h:766
const DRAWINGS & Drawings() const
Definition board.h:365
constexpr size_type GetWidth() const
Definition box2.h:214
constexpr size_type GetHeight() const
Definition box2.h:215
constexpr BOX2< Vec > GetInflated(coord_type aDx, coord_type aDy) const
Get a new rectangle that is this one, inflated by aDx and aDy.
Definition box2.h:638
BOARD_ITEM * Parse()
int GetCount() const
Return the number of objects in the list.
Definition collector.h:83
void Remove(int aIndex)
Remove the item at aIndex (first position is 0).
Definition collector.h:111
int m_Threshold
Definition collector.h:236
Color settings are a bit different than most of the settings objects in that there can be more than o...
void SetColor(int aLayer, const COLOR4D &aColor)
COLOR4D GetColor(int aLayer) const
COMMIT & Added(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Notify observers that aItem has been added.
Definition commit.h:84
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr, RECURSE_MODE aRecurse=RECURSE_MODE::NO_RECURSE)
Modify a given item in the model.
Definition commit.h:106
COMMIT & Add(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Add a new item to the model.
Definition commit.h:78
DO_NOT_SHOW_AGAIN m_DoNotShowAgain
void SelectLibId(const LIB_ID &aLibId)
LIB_ID GetSelectedLibId(int *aUnit=nullptr) const
DESIGN_BLOCK * GetDesignBlock(const LIB_ID &aLibId, bool aUseCacheLib, bool aShowErrorMsg)
Load design block from design block library table.
const LIB_ID & GetLibId() const
int ShowModal() override
wxString GetName() const
Definition drc_rule.h:174
MINOPTMAX< int > & Value()
Definition drc_rule.h:167
MINOPTMAX< int > m_Value
Definition drc_rule.h:208
virtual APP_SETTINGS_BASE * config() const
Return the settings object used in SaveSettings(), and is overloaded in KICAD_MANAGER_FRAME.
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
A set of EDA_ITEMs (i.e., without duplicates).
Definition eda_group.h:46
void RemoveItem(EDA_ITEM *aItem)
Remove item from group.
Definition eda_group.cpp:40
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:98
virtual void SetPosition(const VECTOR2I &aPos)
Definition eda_item.h:273
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
Definition eda_item.cpp:110
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition eda_item.h:142
virtual wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const
Return a user-visible description string of this item.
Definition eda_item.cpp:144
const KIID m_Uuid
Definition eda_item.h:516
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:144
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:220
virtual void SetParent(EDA_ITEM *aParent)
Definition eda_item.h:113
bool HasFlag(EDA_ITEM_FLAGS aFlag) const
Definition eda_item.h:146
SHAPE_T GetShape() const
Definition eda_shape.h:168
double GetLength() const
void SetTextSize(VECTOR2I aNewSize, bool aEnforceMinTextSize=true)
Definition eda_text.cpp:544
void SetTextThickness(int aWidth)
The TextThickness is that set by the user.
Definition eda_text.cpp:295
virtual void SetText(const wxString &aText)
Definition eda_text.cpp:281
void SetHorizJustify(GR_TEXT_H_ALIGN_T aType)
Definition eda_text.cpp:420
The interactive edit tool.
Definition edit_tool.h:56
void DeleteItems(const PCB_SELECTION &aItem, bool aIsCut)
EMBEDDED_FILE * AddFile(const wxFileName &aName, bool aOverwrite)
Load a file from disk and adds it to the collection.
static const TOOL_EVENT ClearedEvent
Definition actions.h:348
static const TOOL_EVENT SelectedEvent
Definition actions.h:346
static const TOOL_EVENT SelectedItemsModified
Selected items were moved, this can be very high frequency on the canvas, use with care.
Definition actions.h:353
static const TOOL_EVENT PointSelectedEvent
Definition actions.h:345
static const TOOL_EVENT ContrastModeChangedByKeyEvent
Definition actions.h:367
static const TOOL_EVENT ConnectivityChangedEvent
Selected item had a property changed (except movement)
Definition actions.h:350
static const TOOL_EVENT UnselectedEvent
Definition actions.h:347
Provide an extensible class to resolve 3D model paths.
Component library viewer main window.
EDA_ANGLE GetOrientation() const
Definition footprint.h:248
ZONES & Zones()
Definition footprint.h:230
std::deque< PAD * > & Pads()
Definition footprint.h:224
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:1063
void SetReference(const wxString &aReference)
Definition footprint.h:667
bool IsLocked() const override
Definition footprint.h:454
void ClearTransientComponentClassNames()
Remove the transient component class names.
Definition footprint.h:1069
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:233
void GetFields(std::vector< PCB_FIELD * > &aVector, bool aVisibleOnly) const
Populate a std::vector with PCB_TEXTs.
const wxString & GetReference() const
Definition footprint.h:661
DRAWINGS & GraphicalItems()
Definition footprint.h:227
A general implementation of a COLLECTORS_GUIDE.
Definition collectors.h:324
Used when the right click button is pressed, or when the select tool is in effect.
Definition collectors.h:207
static const std::vector< KICAD_T > BoardLevelItems
A scan list for all primary board items, omitting items which are subordinate to a FOOTPRINT,...
Definition collectors.h:69
static const std::vector< KICAD_T > AllBoardItems
A scan list for all editable board items.
Definition collectors.h:41
void Collect(BOARD_ITEM *aItem, const std::vector< KICAD_T > &aScanList, const VECTOR2I &aRefPos, const COLLECTORS_GUIDE &aGuide)
Scan a BOARD_ITEM using this class's Inspector method, which does the collection.
static const std::vector< KICAD_T > FootprintItems
A scan list for primary footprint items.
Definition collectors.h:107
Similar to EDA_VIEW_SWITCHER, this dialog is a popup that shows feedback when using a hotkey to cycle...
void Popup(const wxString &aTitle, const wxArrayString &aItems, int aSelection)
virtual void SetProgressReporter(PROGRESS_REPORTER *aReporter)
Set an optional progress reporter.
Definition io_base.h:89
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
virtual const wxString What() const
A composite of Problem() and Where()
Helper class to create more flexible dialogs, including 'do not show again' checkbox handling.
Definition kidialog.h:42
void DoNotShowCheckbox(wxString file, int line)
Shows the 'do not show again' checkbox.
Definition kidialog.cpp:55
int ShowModal() override
Definition kidialog.cpp:93
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:104
double a
Alpha component.
Definition color4d.h:395
void SetGridOrigin(const VECTOR2D &aGridOrigin)
Set the origin point for the grid.
virtual void Update(const VIEW_ITEM *aItem, int aUpdateFlags) const override
For dynamic VIEWs, inform the associated VIEW that the graphical representation of this item has chan...
Definition pcb_view.cpp:91
virtual void SetCursorPosition(const VECTOR2D &aPosition, bool aWarpView=true, bool aTriggeredByArrows=false, long aArrowCommand=0)=0
Move cursor to the requested position expressed in world coordinates.
bool IsBOARD_ITEM() const
Definition view_item.h:102
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition view.h:66
void SetMirror(bool aMirrorX, bool aMirrorY)
Control the mirroring of the VIEW.
Definition view.cpp:557
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition view.cpp:298
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition view.cpp:341
GAL * GetGAL() const
Return the GAL this view is using to draw graphical primitives.
Definition view.h:202
void RecacheAllItems()
Rebuild GAL display lists.
Definition view.cpp:1451
void MarkDirty()
Force redraw of view on the next rendering.
Definition view.h:659
Definition kiid.h:49
All information about a layer pair as stored in the layer pair store.
Management class for layer pairs in a PCB.
Definition layer_pairs.h:47
std::vector< LAYER_PAIR_INFO > GetEnabledLayerPairs(int &aCurrentIndex) const
Get a vector of all enabled layer pairs, in order.
void SetCurrentLayerPair(const LAYER_PAIR &aPair)
Set the "active" layer pair.
bool IsValid() const
Check if this LID_ID is valid.
Definition lib_id.h:172
const UTF8 & GetLibItemName() const
Definition lib_id.h:102
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
Definition lseq.h:47
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
LSEQ UIOrder() const
Return the copper, technical and user layers in the order shown in layer widget.
Definition lset.cpp:726
LSEQ CuStack() const
Return a sequence of copper layers in starting from the front/top and extending to the back/bottom.
Definition lset.cpp:246
static LSET AllCuMask(int aCuLayerCount)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition lset.cpp:582
static LSET AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
Definition lset.cpp:591
T Min() const
Definition minoptmax.h:33
bool HasMax() const
Definition minoptmax.h:38
T Max() const
Definition minoptmax.h:34
EDA_MSG_PANEL items for displaying messages.
Definition msgpanel.h:54
int RepeatLayout(const TOOL_EVENT &aEvent, ZONE *aRefZone)
Handle the data for a net.
Definition netinfo.h:54
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:373
void ClearNetclasses()
Clears all netclasses Calling this method will reset the effective netclass calculation caches.
Definition pad.h:54
bool HasHole() const override
Definition pad.h:106
Describe the page size and margins of a paper page on which to eventually print or plot.
Definition page_info.h:79
static TOOL_ACTION layerToggle
static TOOL_ACTION layerInner12
static TOOL_ACTION nextFootprint
static TOOL_ACTION layerInner8
static TOOL_ACTION zoneDisplayToggle
static TOOL_ACTION previousFootprint
static TOOL_ACTION layerInner3
static TOOL_ACTION layerPrev
static TOOL_ACTION showRatsnest
static TOOL_ACTION zoneFillAll
static TOOL_ACTION layerInner2
static TOOL_ACTION magneticSnapAllLayers
static TOOL_ACTION collect3DModels
static TOOL_ACTION saveToLinkedDesignBlock
static TOOL_ACTION ddAppendBoard
Drag and drop.
static TOOL_ACTION layerInner25
static TOOL_ACTION magneticSnapActiveLayer
Snapping controls.
static TOOL_ACTION layerAlphaDec
static TOOL_ACTION zoneDisplayFilled
static TOOL_ACTION layerInner24
static TOOL_ACTION viaDisplayMode
static TOOL_ACTION layerInner29
static TOOL_ACTION placeCharacteristics
static TOOL_ACTION layerInner11
static TOOL_ACTION layerAlphaInc
static TOOL_ACTION layerPairPresetsCycle
static TOOL_ACTION layerInner16
static TOOL_ACTION layerInner26
static TOOL_ACTION layerInner18
static TOOL_ACTION layerInner14
static TOOL_ACTION trackDisplayMode
static TOOL_ACTION magneticSnapToggle
static TOOL_ACTION layerInner6
static TOOL_ACTION applyDesignBlockLayout
static TOOL_ACTION ddImportFootprint
static TOOL_ACTION zoneDisplayTriangulated
static TOOL_ACTION rehatchShapes
static TOOL_ACTION layerInner22
static TOOL_ACTION placeDesignBlock
static TOOL_ACTION layerInner5
static TOOL_ACTION zoneDisplayFractured
static TOOL_ACTION ratsnestModeCycle
static TOOL_ACTION layerInner20
static TOOL_ACTION layerInner7
static TOOL_ACTION layerInner27
static TOOL_ACTION loadFpFromBoard
static TOOL_ACTION appendBoard
static TOOL_ACTION netColorModeCycle
static TOOL_ACTION layerInner1
static TOOL_ACTION layerInner10
static TOOL_ACTION layerInner15
static TOOL_ACTION layerInner17
static TOOL_ACTION flipBoard
static TOOL_ACTION layerBottom
static TOOL_ACTION zoneDisplayOutline
static TOOL_ACTION ratsnestLineMode
static TOOL_ACTION layerInner19
static TOOL_ACTION layerInner9
static TOOL_ACTION saveSelectionToDesignBlock
static TOOL_ACTION move
move or drag an item
static TOOL_ACTION layerInner30
static TOOL_ACTION layerTop
static TOOL_ACTION layerInner4
static TOOL_ACTION layerInner13
static TOOL_ACTION layerInner21
static TOOL_ACTION saveFpToBoard
static TOOL_ACTION layerNext
static TOOL_ACTION placeLinkedDesignBlock
static TOOL_ACTION placeStackup
static TOOL_ACTION layerInner23
static TOOL_ACTION layerInner28
Common, abstract interface for edit frames.
void RestoreCopyFromUndoList(wxCommandEvent &aEvent)
Undo the last edit:
APPEARANCE_CONTROLS * GetAppearancePanel()
void RestoreCopyFromRedoList(wxCommandEvent &aEvent)
Redo the last edit:
void UpdateVertexEditorSelection(BOARD_ITEM *aItem)
Base PCB main window class for Pcbnew, Gerbview, and CvPcb footprint viewer.
const VECTOR2I GetPageSizeIU() const override
Works off of GetPageSettings() to return the size of the paper page in the internal units of this par...
void OnModify() override
Must be called after a change in order to set the "modify" flag and update other data structures and ...
BOARD * GetBoard() const
virtual BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Return the BOARD_DESIGN_SETTINGS for the open project.
int RehatchShapes(const TOOL_EVENT &aEvent)
void setTransitions() override
< Sets up handlers for various events.
int AppendBoardFromFile(const TOOL_EVENT &aEvent)
int AddLibrary(const TOOL_EVENT &aEvent)
int DdAppendBoard(const TOOL_EVENT &aEvent)
int LoadFpFromBoard(const TOOL_EVENT &aEvent)
int SaveToLinkedDesignBlock(const TOOL_EVENT &aEvent)
int DdImportFootprint(const TOOL_EVENT &aEvent)
int SnapModeFeedback(const TOOL_EVENT &aEvent)
int NetColorModeCycle(const TOOL_EVENT &aEvent)
int SaveFpToBoard(const TOOL_EVENT &aEvent)
int RatsnestModeCycle(const TOOL_EVENT &aEvent)
int TrackDisplayMode(const TOOL_EVENT &aEvent)
int DdAddLibrary(const TOOL_EVENT &aEvent)
int Redo(const TOOL_EVENT &aEvent)
int PlaceLinkedDesignBlock(const TOOL_EVENT &aEvent)
bool placeBoardItems(BOARD_COMMIT *aCommit, std::vector< BOARD_ITEM * > &aItems, bool aIsNew, bool aAnchorAtOrigin, bool aReannotateDuplicates, bool aSkipMove)
Add and select or just select for move/place command a list of board items.
int LayerPresetFeedback(const TOOL_EVENT &aEvent)
int UpdateMessagePanel(const TOOL_EVENT &aEvent)
int LayerAlphaDec(const TOOL_EVENT &aEvent)
int LayerNext(const TOOL_EVENT &aEvent)
int PlaceStackup(const TOOL_EVENT &aEvent)
std::unique_ptr< STATUS_TEXT_POPUP > m_statusPopup
int ToggleRatsnest(const TOOL_EVENT &aEvent)
int LayerAlphaInc(const TOOL_EVENT &aEvent)
int HighContrastModeCycle(const TOOL_EVENT &aEvent)
std::unique_ptr< KIGFX::ORIGIN_VIEWITEM > m_gridOrigin
int Quit(const TOOL_EVENT &aEvent)
int HighContrastMode(const TOOL_EVENT &aEvent)
int Undo(const TOOL_EVENT &aEvent)
int ViaDisplayMode(const TOOL_EVENT &aEvent)
PCB_BASE_FRAME * m_frame
static void DoSetGridOrigin(KIGFX::VIEW *aView, PCB_BASE_FRAME *aFrame, EDA_ITEM *originViewItem, const VECTOR2D &aPoint)
int CollectAndEmbed3DModels(const TOOL_EVENT &aEvent)
void pruneItemLayers(std::vector< BOARD_ITEM * > &aItems)
Helper for pasting.
int GridPlaceOrigin(const TOOL_EVENT &aEvent)
int FlipPcbView(const TOOL_EVENT &aEvent)
int PlaceCharacteristics(const TOOL_EVENT &aEvent)
int ApplyDesignBlockLayout(const TOOL_EVENT &aEvent)
int SnapMode(const TOOL_EVENT &aEvent)
int ContrastModeFeedback(const TOOL_EVENT &aEvent)
int LayerToggle(const TOOL_EVENT &aEvent)
int AppendBoard(PCB_IO &pi, const wxString &fileName, DESIGN_BLOCK *aDesignBlock=nullptr, BOARD_COMMIT *aCommit=nullptr, bool aSkipMove=false)
void Reset(RESET_REASON aReason) override
Bring the tool to a known, initial state.
int IterateFootprint(const TOOL_EVENT &aEvent)
int Print(const TOOL_EVENT &aEvent)
void rehatchBoardItem(BOARD_ITEM *aItem)
int ZoneDisplayMode(const TOOL_EVENT &aEvent)
int GridResetOrigin(const TOOL_EVENT &aEvent)
BOARD_ITEM * m_pickerItem
int InteractiveDelete(const TOOL_EVENT &aEvent)
int AppendDesignBlock(const TOOL_EVENT &aEvent)
int LayerPrev(const TOOL_EVENT &aEvent)
int CycleLayerPresets(const TOOL_EVENT &aEvent)
int Paste(const TOOL_EVENT &aEvent)
void unfilledZoneCheck()
We have bug reports indicating that some new users confuse zone filling/unfilling with the display mo...
int LayerSwitch(const TOOL_EVENT &aEvent)
Abstract dimension API.
HIGH_CONTRAST_MODE m_ContrastModeDisplay
How inactive layers are displayed.
NET_COLOR_MODE m_NetColorMode
How to use color overrides on specific nets and netclasses.
ZONE_DISPLAY_MODE m_ZoneDisplayMode
void RedrawRatsnest()
Return the bounding box of the view that should be used if model is not valid.
The main frame for Pcbnew.
PCB_DESIGN_BLOCK_PANE * GetDesignBlockPane() const
static const TOOL_EVENT & SnappingModeChangedByKeyEvent()
Hotkey feedback.
static const TOOL_EVENT & LayerPairPresetChangedByKeyEvent()
A set of BOARD_ITEMs (i.e., without duplicates).
Definition pcb_group.h:53
static PCB_IO * PluginFind(PCB_FILE_T aFileType)
Return a #PLUGIN which the caller can use to import, export, save, or load design documents.
PCB_FILE_T
The set of file types that the PCB_IO_MGR knows about, and for which there has been a plugin written,...
Definition pcb_io_mgr.h:56
@ KICAD_SEXP
S-expression Pcbnew file format.
Definition pcb_io_mgr.h:58
static PCB_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:71
virtual void SetQueryUserCallback(std::function< bool(wxString aTitle, int aIcon, wxString aMessage, wxString aAction)> aCallback)
Registers a KIDIALOG callback for collecting info from the user.
Definition pcb_io.h:97
virtual BOARD * LoadBoard(const wxString &aFileName, BOARD *aAppendToMe, const std::map< std::string, UTF8 > *aProperties=nullptr, PROJECT *aProject=nullptr)
Load information from some input file format that this PCB_IO implementation knows about into either ...
Definition pcb_io.cpp:74
Class that manages the presentation of PCB layers in a PCB frame.
wxString getLayerPairName(const LAYER_PAIR &aPair) const
Definition sel_layer.cpp:89
Generic tool for picking an item.
PCB_LAYER_ID m_Route_Layer_TOP
Definition pcb_screen.h:43
PCB_LAYER_ID m_Route_Layer_BOTTOM
Definition pcb_screen.h:44
The selection tool: currently supports:
void GuessSelectionCandidates(GENERAL_COLLECTOR &aCollector, const VECTOR2I &aWhere) const
Try to guess best selection candidates in case multiple items are clicked, by doing some brain-dead h...
void select(EDA_ITEM *aItem) override
Take necessary action mark an item as selected.
bool Selectable(const BOARD_ITEM *aItem, bool checkVisibilityOnly=false) const
PCB_GROUP * GetEnteredGroup()
void FilterCollectorForHierarchy(GENERAL_COLLECTOR &aCollector, bool aMultiselect) const
In general we don't want to select both a parent and any of it's children.
int ClearSelection(const TOOL_EVENT &aEvent)
PCB_SELECTION & GetSelection()
void FilterCollectedItems(GENERAL_COLLECTOR &aCollector, bool aMultiSelect, PCB_SELECTION_FILTER_OPTIONS *aRejected=nullptr)
Apply the SELECTION_FITLER_OPTIONS to the collector.
void SetColSpan(int aSpan)
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:154
const VECTOR2I & GetEnd() const
Definition pcb_track.h:151
virtual COMMON_SETTINGS * GetCommonSettings() const
Definition pgm_base.cpp:576
void SetMotionHandler(MOTION_HANDLER aHandler)
Set a handler for mouse motion.
Definition picker_tool.h:92
void SetClickHandler(CLICK_HANDLER aHandler)
Set a handler for mouse click event.
Definition picker_tool.h:81
void SetSnapping(bool aSnap)
Definition picker_tool.h:66
void SetCursor(KICURSOR aCursor)
Definition picker_tool.h:64
void SetFinalizeHandler(FINALIZE_HANDLER aHandler)
Set a handler for the finalize event.
static FP_LIB_TABLE * PcbFootprintLibs(PROJECT *aProject)
Return the table of footprint libraries without Kiway.
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:65
virtual const wxString GetProjectPath() const
Return the full path of the project.
Definition project.cpp:162
Cache for storing the 3D shapes.
Definition 3d_cache.h:55
FILENAME_RESOLVER * GetResolver() noexcept
Definition 3d_cache.cpp:513
Definition seg.h:42
ecoord SquaredDistance(const SEG &aSeg) const
Definition seg.cpp:80
VECTOR2I::extended_type ecoord
Definition seg.h:44
void BrightenItem(EDA_ITEM *aItem)
void UnbrightenItem(EDA_ITEM *aItem)
virtual void Add(EDA_ITEM *aItem)
Definition selection.cpp:42
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
Represent a set of closed polygons.
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
virtual VECTOR2I Centre() const
Compute a center-of-mass of the shape.
Definition shape.h:232
Extension of STATUS_POPUP for displaying a single line text.
Hold the information shown in the lower right corner of a plot, printout, or editing view.
Definition title_block.h:41
T * getEditFrame() const
Return the application window object, casted to requested user type.
Definition tool_base.h:186
const std::string & GetName() const
Return the name of the tool.
Definition tool_base.h:136
KIGFX::VIEW_CONTROLS * getViewControls() const
Return the instance of VIEW_CONTROLS object used in the application.
Definition tool_base.cpp:44
TOOL_MANAGER * m_toolMgr
Definition tool_base.h:220
KIGFX::VIEW * getView() const
Returns the instance of #VIEW object used in the application.
Definition tool_base.cpp:38
RESET_REASON
Determine the reason of reset for a tool.
Definition tool_base.h:78
@ REDRAW
Full drawing refresh.
Definition tool_base.h:83
@ MODEL_RELOAD
Model changes (the sheet for a schematic)
Definition tool_base.h:80
@ GAL_SWITCH
Rendering engine changes.
Definition tool_base.h:82
Generic, UI-independent tool event.
Definition tool_event.h:171
COMMIT * Commit() const
Definition tool_event.h:283
bool IsAction(const TOOL_ACTION *aAction) const
Test if the event contains an action issued upon activation of the given TOOL_ACTION.
T Parameter() const
Return a parameter assigned to the event.
Definition tool_event.h:473
void Go(int(T::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
Define which state (aStateFunc) to go when a certain event arrives (aConditions).
void Activate()
Run the tool.
static constexpr extended_type ECOORD_MAX
Definition vector2d.h:76
A modified version of the wxInfoBar class that allows us to:
Definition wx_infobar.h: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 AddButton(wxButton *aButton)
Add an already created button to the infobar.
Multi-thread safe progress reporter dialog, intended for use of tasks that parallel reporting back of...
Handle a list of polygons defining a copper zone.
Definition zone.h:74
void SetDoNotAllowPads(bool aEnable)
Definition zone.h:728
void AddPolygon(std::vector< VECTOR2I > &aPolygon)
Add a polygon to the zone outline.
Definition zone.cpp:1117
void SetPlacementAreaSource(const wxString &aSource)
Definition zone.h:710
void SetPlacementAreaSourceType(PLACEMENT_SOURCE_T aType)
Definition zone.h:715
SHAPE_POLY_SET * Outline()
Definition zone.h:335
void SetHatchStyle(ZONE_BORDER_DISPLAY_STYLE aStyle)
Definition zone.h:590
void SetIsRuleArea(bool aEnable)
Definition zone.h:705
void SetDoNotAllowTracks(bool aEnable)
Definition zone.h:727
void SetLayerSet(const LSET &aLayerSet) override
Definition zone.cpp:511
void SetDoNotAllowVias(bool aEnable)
Definition zone.h:726
void SetDoNotAllowFootprints(bool aEnable)
Definition zone.h:729
void SetDoNotAllowZoneFills(bool aEnable)
Definition zone.h:725
void SetZoneName(const wxString &aName)
Definition zone.h:164
void SetPlacementAreaEnabled(bool aEnabled)
Definition zone.h:707
std::string GetClipboardUTF8()
Return the information currently stored in the system clipboard.
Definition clipboard.cpp:58
std::unique_ptr< wxImage > GetImageFromClipboard()
Get image data from the clipboard, if there is any.
Definition clipboard.cpp:84
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition confirm.cpp:251
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition confirm.cpp:194
void DisplayError(wxWindow *aParent, const wxString &aText)
Display an error or warning message box with aMessage.
Definition confirm.cpp:169
This file is part of the common library.
void TransformCircleToPolygon(SHAPE_LINE_CHAIN &aBuffer, const VECTOR2I &aCenter, int aRadius, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a circle to a polygon, using multiple straight lines.
void BuildConvexHull(std::vector< VECTOR2I > &aResult, const std::vector< VECTOR2I > &aPoly)
Calculate the convex hull of a list of points in counter-clockwise order.
@ REMOVE
Definition cursors.h:54
@ PLACE
Definition cursors.h:98
@ ARROW
Definition cursors.h:46
#define ALPHA_MAX
@ DIFF_PAIR_GAP_CONSTRAINT
Definition drc_rule.h:73
@ EDGE_CLEARANCE_CONSTRAINT
Definition drc_rule.h:53
@ CLEARANCE_CONSTRAINT
Definition drc_rule.h:49
@ MAX_UNCOUPLED_CONSTRAINT
Definition drc_rule.h:74
@ HOLE_CLEARANCE_CONSTRAINT
Definition drc_rule.h:51
#define _(s)
Declaration of the eda_3d_viewer class.
@ RECURSE
Definition eda_item.h:51
@ NO_RECURSE
Definition eda_item.h:52
std::vector< EDA_ITEM * > EDA_ITEMS
Define list of drawing items for screens.
Definition eda_item.h:566
#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:45
static FILENAME_RESOLVER * resolver
@ FRAME_PCB_EDITOR
Definition frame_type.h:42
@ FRAME_FOOTPRINT_VIEWER
Definition frame_type.h:45
@ FRAME_FOOTPRINT_EDITOR
Definition frame_type.h:43
static const std::string KiCadUriPrefix
wxString KeyNameFromKeyCode(int aKeycode, bool *aIsFound)
Return the key name from the key code.
std::unique_ptr< T > IO_RELEASER
Helper to hold and release an IO_BASE object when exceptions are thrown.
Definition io_mgr.h:33
#define KICTL_KICAD_ONLY
chosen file is from KiCad according to user
int GetNetnameLayer(int aLayer)
Return a netname layer corresponding to the given layer.
Definition layer_ids.h:853
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition layer_ids.h:676
@ LAYER_RATSNEST
Definition layer_ids.h:253
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:60
@ Edge_Cuts
Definition layer_ids.h:112
@ B_Cu
Definition layer_ids.h:65
@ Margin
Definition layer_ids.h:113
@ UNDEFINED_LAYER
Definition layer_ids.h:61
@ F_Cu
Definition layer_ids.h:64
#define ZONE_LAYER_FOR(boardLayer)
Definition layer_ids.h:368
bool IsValidLayer(int aLayerId)
Test whether a given integer is a valid layer index, i.e.
Definition layer_ids.h:654
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:245
KICOMMON_API wxString StringFromValue(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnits, double aValue, bool aAddUnitsText=false, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
Return the string from aValue according to aUnits (inch, mm ...) for display.
SHAPE_LINE_CHAIN RectifyPolygon(const SHAPE_LINE_CHAIN &aPoly)
void CollectBoxCorners(const BOX2I &aBox, std::vector< VECTOR2I > &aCorners)
Add the 4 corners of a BOX2I to a vector.
@ REPAINT
Item needs to be redrawn.
Definition view_item.h:58
wxPoint GetMousePosition()
Returns the mouse position in screen coordinates.
Definition wxgtk/ui.cpp:689
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
Definition kicad_algo.h:100
bool AskLoadBoardFileName(PCB_EDIT_FRAME *aParent, wxString *aFileName, int aCtl=0)
Show a wxFileDialog asking for a BOARD filename to open.
#define ALPHA_STEP
static void pasteFootprintItemsToFootprintEditor(FOOTPRINT *aClipFootprint, BOARD *aBoard, std::vector< BOARD_ITEM * > &aPastedItems)
#define ALPHA_MIN
void Flip(T &aValue)
static void moveUnflaggedItems(const std::deque< T > &aList, std::vector< BOARD_ITEM * > &aTarget, bool aIsNew)
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.
Definition pgm_base.cpp:913
see class PGM_BASE
#define HITTEST_THRESHOLD_PIXELS
Utility functions for working with shapes.
std::vector< FAB_LAYER_COLOR > dummy
wxString NotSpecifiedPrm()
wxString UnescapeString(const wxString &aSource)
wxString InitialCaps(const wxString &aString)
Capitalize only the first word.
VECTOR2I m_center
std::unordered_set< EDA_ITEM * > m_designBlockItems
PLACEMENT_SOURCE_T m_sourceType
std::set< FOOTPRINT * > m_components
VECTOR2I center
int actual
wxString result
Test unit parsing edge cases and error handling.
@ GR_TEXT_H_ALIGN_RIGHT
constexpr KICAD_T BaseType(const KICAD_T aType)
Return the underlying type of the given type.
Definition typeinfo.h:254
@ PCB_T
Definition typeinfo.h:82
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition typeinfo.h:88
@ PCB_DIM_ORTHOGONAL_T
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
Definition typeinfo.h:106
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition typeinfo.h:103
@ PCB_GENERATOR_T
class PCB_GENERATOR, generator on a layer
Definition typeinfo.h:91
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:97
@ PCB_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
Definition typeinfo.h:104
@ PCB_GROUP_T
class PCB_GROUP, a set of BOARD_ITEMs
Definition typeinfo.h:111
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
Definition typeinfo.h:93
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition typeinfo.h:92
@ PCB_MARKER_T
class PCB_MARKER, a marker used to show something
Definition typeinfo.h:99
@ PCB_BARCODE_T
class PCB_BARCODE, a barcode (graphic item)
Definition typeinfo.h:101
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
Definition typeinfo.h:86
@ PCB_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
Definition typeinfo.h:102
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition typeinfo.h:87
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition typeinfo.h:98
@ PCB_DIMENSION_T
class PCB_DIMENSION_BASE: abstract dimension meta-type
Definition typeinfo.h:100
@ PCB_TABLE_T
class PCB_TABLE, table of PCB_TABLECELLs
Definition typeinfo.h:94
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition typeinfo.h:96
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
Definition typeinfo.h:105
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695
VECTOR2< double > VECTOR2D
Definition vector2d.h:694
Definition of file extensions used in Kicad.
#define PR_CAN_ABORT