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