KiCad PCB EDA Suite
Loading...
Searching...
No Matches
panel_setup_layers.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) 2009 Isaac Marino Bavaresco, [email protected]
5 * Copyright (C) 2009 SoftPLC Corporation, Dick Hollenbeck <[email protected]>
6 * Copyright (C) 2009-2024 KiCad Developers, see AUTHORS.txt for contributors.
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
27#include <confirm.h>
28#include <core/arraydim.h>
29#include <core/kicad_algo.h>
30#include <pcb_edit_frame.h>
31#include <tool/tool_manager.h>
32#include <tools/pcb_actions.h>
33#include <board.h>
34#include <collectors.h>
35#include <footprint.h>
36#include <pad.h>
37#include <pcb_track.h>
38#include <panel_setup_layers.h>
40
41#include <wx/choicdlg.h>
42#include <wx/msgdlg.h>
43#include <eda_list_dialog.h>
44
45
46// some define to choose how copper layers widgets are shown
47
48// if defined, display only active copper layers
49// if not displays always 1=the full set (32 copper layers)
50#define HIDE_INACTIVE_LAYERS
51
52
54{
55 // Layers that are put out into the dialog UI, coordinate with wxformbuilder and
56 // getCTLs( int aLayerNumber )
57 static const PCB_LAYER_ID layers[] = {
58 F_CrtYd,
59 F_Fab,
60 F_Adhes,
61 F_Paste,
62 F_SilkS,
63 F_Mask,
64 F_Cu,
65
66 In1_Cu,
67 In2_Cu,
68 In3_Cu,
69 In4_Cu,
70 In5_Cu,
71 In6_Cu,
72 In7_Cu,
73 In8_Cu,
74 In9_Cu,
75 In10_Cu,
76 In11_Cu,
77 In12_Cu,
78 In13_Cu,
79 In14_Cu,
80 In15_Cu,
81
82 In16_Cu,
83 In17_Cu,
84 In18_Cu,
85 In19_Cu,
86 In20_Cu,
87 In21_Cu,
88 In22_Cu,
89 In23_Cu,
90 In24_Cu,
91 In25_Cu,
92 In26_Cu,
93 In27_Cu,
94 In28_Cu,
95 In29_Cu,
96 In30_Cu,
97
98 B_Cu,
99 B_Mask,
100 B_SilkS,
101 B_Paste,
102 B_Adhes,
103 B_Fab,
104 B_CrtYd,
105
106 Edge_Cuts,
107 Margin,
108 Eco2_User,
109 Eco1_User,
110 Cmts_User,
111 Dwgs_User,
112
113 User_1,
114 User_2,
115 User_3,
116 User_4,
117 User_5,
118 User_6,
119 User_7,
120 User_8,
121 User_9,
122 };
123
124 return LSEQ( layers, layers + arrayDim( layers ) );
125}
126
127
128PANEL_SETUP_LAYERS::PANEL_SETUP_LAYERS( wxWindow* aParentWindow, PCB_EDIT_FRAME* aFrame ) :
129 PANEL_SETUP_LAYERS_BASE( aParentWindow ),
130 m_frame( aFrame ),
131 m_physicalStackup( nullptr ),
132 m_initialized( false )
133{
134 m_pcb = aFrame->GetBoard();
135}
136
137
139{
140#define RETURN_COPPER( x ) return PANEL_SETUP_LAYERS_CTLs( x##Name, x##CheckBox, x##Choice )
141#define RETURN_AUX( x ) return PANEL_SETUP_LAYERS_CTLs( x##Name, x##CheckBox, x##StaticText )
142#define RETURN_MANDATORY( x ) return PANEL_SETUP_LAYERS_CTLs( x##Name, nullptr, x##StaticText )
143
144 switch( aLayerNumber )
145 {
146 case F_CrtYd: RETURN_MANDATORY( m_CrtYdFront );
147 case F_Fab: RETURN_AUX( m_FabFront );
148 case F_Adhes: RETURN_AUX( m_AdhesFront );
149 case F_Paste: RETURN_AUX( m_SoldPFront );
150 case F_SilkS: RETURN_AUX( m_SilkSFront );
151 case F_Mask: RETURN_AUX( m_MaskFront );
152 case F_Cu: RETURN_COPPER( m_Front );
153
154 case In1_Cu: RETURN_COPPER( m_In1 );
155 case In2_Cu: RETURN_COPPER( m_In2 );
156 case In3_Cu: RETURN_COPPER( m_In3 );
157 case In4_Cu: RETURN_COPPER( m_In4 );
158 case In5_Cu: RETURN_COPPER( m_In5 );
159 case In6_Cu: RETURN_COPPER( m_In6 );
160 case In7_Cu: RETURN_COPPER( m_In7 );
161 case In8_Cu: RETURN_COPPER( m_In8 );
162 case In9_Cu: RETURN_COPPER( m_In9 );
163 case In10_Cu: RETURN_COPPER( m_In10 );
164 case In11_Cu: RETURN_COPPER( m_In11 );
165 case In12_Cu: RETURN_COPPER( m_In12 );
166 case In13_Cu: RETURN_COPPER( m_In13 );
167 case In14_Cu: RETURN_COPPER( m_In14 );
168 case In15_Cu: RETURN_COPPER( m_In15 );
169
170 case In16_Cu: RETURN_COPPER( m_In16 );
171 case In17_Cu: RETURN_COPPER( m_In17 );
172 case In18_Cu: RETURN_COPPER( m_In18 );
173 case In19_Cu: RETURN_COPPER( m_In19 );
174 case In20_Cu: RETURN_COPPER( m_In20 );
175 case In21_Cu: RETURN_COPPER( m_In21 );
176 case In22_Cu: RETURN_COPPER( m_In22 );
177 case In23_Cu: RETURN_COPPER( m_In23 );
178 case In24_Cu: RETURN_COPPER( m_In24 );
179 case In25_Cu: RETURN_COPPER( m_In25 );
180 case In26_Cu: RETURN_COPPER( m_In26 );
181 case In27_Cu: RETURN_COPPER( m_In27 );
182 case In28_Cu: RETURN_COPPER( m_In28 );
183 case In29_Cu: RETURN_COPPER( m_In29 );
184 case In30_Cu: RETURN_COPPER( m_In30 );
185
186 case B_Cu: RETURN_COPPER( m_Back );
187 case B_Mask: RETURN_AUX( m_MaskBack );
188 case B_SilkS: RETURN_AUX( m_SilkSBack );
189 case B_Paste: RETURN_AUX( m_SoldPBack );
190 case B_Adhes: RETURN_AUX( m_AdhesBack );
191 case B_Fab: RETURN_AUX( m_FabBack );
192 case B_CrtYd: RETURN_MANDATORY( m_CrtYdBack );
193
194 case Edge_Cuts: RETURN_MANDATORY( m_PCBEdges );
195 case Margin: RETURN_MANDATORY( m_Margin );
196 case Eco2_User: RETURN_AUX( m_Eco2 );
197 case Eco1_User: RETURN_AUX( m_Eco1 );
198 case Cmts_User: RETURN_AUX( m_Comments );
199 case Dwgs_User: RETURN_AUX( m_Drawings );
200
201 case User_1: RETURN_AUX( m_User1 );
202 case User_2: RETURN_AUX( m_User2 );
203 case User_3: RETURN_AUX( m_User3 );
204 case User_4: RETURN_AUX( m_User4 );
205 case User_5: RETURN_AUX( m_User5 );
206 case User_6: RETURN_AUX( m_User6 );
207 case User_7: RETURN_AUX( m_User7 );
208 case User_8: RETURN_AUX( m_User8 );
209 case User_9: RETURN_AUX( m_User9 );
210
211 default:
212 wxASSERT_MSG( 0, wxT( "bad layer id" ) );
213 return PANEL_SETUP_LAYERS_CTLs( nullptr, nullptr, nullptr );
214 }
215}
216
217
218wxControl* PANEL_SETUP_LAYERS::getName( int aLayer )
219{
220 return getCTLs( aLayer ).name;
221}
222
223
224wxCheckBox* PANEL_SETUP_LAYERS::getCheckBox( int aLayer )
225{
226 return getCTLs( aLayer ).checkbox;
227}
228
229
230wxChoice* PANEL_SETUP_LAYERS::getChoice( int aLayer )
231{
232 return (wxChoice*) getCTLs( aLayer ).choice;
233}
234
235
237{
239
240 // Rescue may be enabled, but should not be shown in this dialog
241 m_enabledLayers.reset( Rescue );
242
244
247
251
252 m_initialized = true;
253
254 return true;
255}
256
257
258void PANEL_SETUP_LAYERS::SyncCopperLayers( int aNumCopperLayers )
259{
260 setCopperLayerCheckBoxes( aNumCopperLayers );
261}
262
263
265{
266 for( int layer : { F_CrtYd, B_CrtYd, Edge_Cuts, Margin } )
267 setLayerCheckBox( layer, true );
268}
269
270
272{
273 for( LSEQ seq = LSET::UserDefinedLayers().Seq(); seq; ++seq )
274 {
275 PCB_LAYER_ID layer = *seq;
276 bool state = m_pcb->IsLayerEnabled( layer );
277
278#ifdef HIDE_INACTIVE_LAYERS
279 // This code hides inactive copper layers, or redisplays hidden layers which are now needed.
280 PANEL_SETUP_LAYERS_CTLs ctl = getCTLs( layer );
281
282 // All user-defined layers should have a checkbox
283 wxASSERT( ctl.checkbox );
284
285 ctl.name->Show( state );
286 ctl.checkbox->Show( state );
287 ctl.choice->Show( state );
288#endif
289
290 setLayerCheckBox( layer, state );
291 }
292
293#ifdef HIDE_INACTIVE_LAYERS
294 // Send an size event to force sizers to be updated,
295 // because the number of copper layers can have changed.
296 wxSizeEvent evt_size( m_LayersListPanel->GetSize() );
297 m_LayersListPanel->GetEventHandler()->ProcessEvent( evt_size );
298#endif
299}
300
301
303{
304 // Set all the board's layer names into the dialog by calling BOARD::GetLayerName(),
305 // which will call BOARD::GetStandardLayerName() for non-coppers.
306
307 for( LSEQ seq = dlg_layers(); seq; ++seq )
308 {
309 PCB_LAYER_ID layer = *seq;
310 wxControl* ctl = getName( layer );
311
312 if( ctl )
313 {
314 wxString lname = m_pcb->GetLayerName( layer );
315
316 if( auto textCtl = dynamic_cast<wxTextCtrl*>( ctl ) )
317 textCtl->ChangeValue( lname ); // wxTextCtrl
318 else
319 ctl->SetLabel( lname ); // wxStaticText
320 }
321 }
322}
323
324
326{
327 // The check boxes
328 for( LSEQ seq = dlg_layers(); seq; ++seq )
329 {
330 PCB_LAYER_ID layer = *seq;
331 setLayerCheckBox( layer, enabledLayers[layer] );
332 }
333}
334
335
337{
338 for( LSEQ seq = LSET::AllCuMask().Seq(); seq; ++seq )
339 {
340 PCB_LAYER_ID cu_layer = *seq;
341
342 wxChoice* ctl = getChoice( cu_layer );
343 ctl->SetSelection( m_pcb->GetLayerType( cu_layer ) );
344 }
345}
346
347
349{
350 LSET layerMaskResult;
351
352 for( LSEQ seq = dlg_layers(); seq; ++seq )
353 {
354 PCB_LAYER_ID layer = *seq;
355 wxCheckBox* ctl = getCheckBox( layer );
356
357 if( !ctl || ctl->GetValue() )
358 layerMaskResult.set( layer );
359 }
360
361 return layerMaskResult;
362}
363
364
365void PANEL_SETUP_LAYERS::setLayerCheckBox( int aLayer, bool isChecked )
366{
367 PANEL_SETUP_LAYERS_CTLs ctl = getCTLs( aLayer );
368
369 if( !ctl.checkbox )
370 return;
371
372 ctl.checkbox->SetValue( isChecked );
373}
374
375
377{
378 if( copperCount > 0 )
379 {
380 setLayerCheckBox( F_Cu, true );
381 --copperCount;
382 }
383
384 if( copperCount > 0 )
385 {
386 setLayerCheckBox( B_Cu, true );
387 --copperCount;
388 }
389
390 for( LSEQ seq = LSET::InternalCuMask().Seq(); seq; ++seq, --copperCount )
391 {
392 PCB_LAYER_ID layer = *seq;
393 bool state = copperCount > 0;
394
395#ifdef HIDE_INACTIVE_LAYERS
396 // This code hides inactive copper layers, or redisplays hidden layers which are now needed.
397 PANEL_SETUP_LAYERS_CTLs ctl = getCTLs( layer );
398
399 // Inner layers should have a checkbox
400 wxASSERT( ctl.checkbox );
401
402 ctl.name->Show( state );
403 ctl.checkbox->Show( state );
404 ctl.choice->Show( state );
405#endif
406
407 setLayerCheckBox( layer, state );
408 }
409
410#ifdef HIDE_INACTIVE_LAYERS
411 // Send an size event to force sizers to be updated,
412 // because the number of copper layers can have changed.
413 wxSizeEvent evt_size( m_LayersListPanel->GetSize() );
414 m_LayersListPanel->GetEventHandler()->ProcessEvent( evt_size );
415#endif
416}
417
418
419void PANEL_SETUP_LAYERS::OnCheckBox( wxCommandEvent& event )
420{
422}
423
424
425void PANEL_SETUP_LAYERS::DenyChangeCheckBox( wxCommandEvent& event )
426{
427 wxObject* source = event.GetEventObject();
428
429 for( LSEQ seq = LSET::AllCuMask().Seq(); seq; ++seq )
430 {
431 wxCheckBox* copper = getCheckBox( *seq );
432
433 if( source == copper )
434 {
435 DisplayError( wxGetTopLevelParent( this ),
436 _( "Use the Physical Stackup page to change the number of "
437 "copper layers." ) );
438
439 copper->SetValue( true );
440 return;
441 }
442 }
443}
444
445
447{
448 if( !testLayerNames() )
449 return false;
450
451 // Make sure we have the latest copper layer count
454
455 wxString msg;
456 bool modified = false;
457
458 // Check for removed layers with items which will get deleted from the board.
459 LSEQ removedLayers = getRemovedLayersWithItems();
460
461 // Check for non-copper layers in use in footprints, and therefore not removable.
462 LSEQ notremovableLayers = getNonRemovableLayers();
463
464 if( !notremovableLayers.empty() )
465 {
466 for( unsigned int ii = 0; ii < notremovableLayers.size(); ii++ )
467 msg << m_pcb->GetLayerName( notremovableLayers[ii] ) << wxT( "\n" );
468
469 if( !IsOK( wxGetTopLevelParent( this ),
470 wxString::Format( _( "Footprints have some items on removed layers:\n"
471 "%s\n"
472 "These items will be no longer accessible\n"
473 "Do you wish to continue?" ), msg ) ) )
474 {
475 return false;
476 }
477 }
478
479 if( !removedLayers.empty()
480 && !IsOK( wxGetTopLevelParent( this ),
481 _( "Items have been found on removed layers. This operation will "
482 "delete all items from removed layers and cannot be undone.\n"
483 "Do you wish to continue?" ) ) )
484 {
485 return false;
486 }
487
488 // Delete all objects on layers that have been removed. Leaving them in copper layers
489 // can (will?) result in DRC errors and it pollutes the board file with cruft.
490 bool hasRemovedBoardItems = false;
491
492 if( !removedLayers.empty() )
493 {
495
496 PCB_LAYER_COLLECTOR collector;
497
498 for( PCB_LAYER_ID layer_id : removedLayers )
499 {
500 collector.SetLayerId( layer_id );
502
503 // Bye-bye items on removed layer.
504 for( int i = 0; i < collector.GetCount(); i++ )
505 {
506 BOARD_ITEM* item = collector[i];
507
508 // Do not remove/change an item owned by a footprint
509 if( dynamic_cast<FOOTPRINT*>( item->GetParentFootprint() ) )
510 continue;
511
512 // Do not remove footprints
513 if( dynamic_cast<FOOTPRINT*>( item ) )
514 continue;
515
516 LSET layers = item->GetLayerSet();
517
518 layers.reset( layer_id );
519 hasRemovedBoardItems = true;
520 modified = true;
521
522 if( layers.any() )
523 {
524 item->SetLayerSet( layers );
525 }
526 else
527 {
528 m_pcb->Remove( item );
529 delete item;
530 }
531 }
532 }
533 }
534
536
537 LSET previousEnabled = m_pcb->GetEnabledLayers();
538
539 if( m_enabledLayers != previousEnabled )
540 {
542
543 LSET changedLayers = m_enabledLayers ^ previousEnabled;
544
545 /*
546 * Ensure enabled layers are also visible. This is mainly to avoid mistakes if some
547 * enabled layers are not visible when exiting this dialog.
548 */
549 m_pcb->SetVisibleLayers( m_pcb->GetVisibleLayers() | changedLayers );
550
551 /*
552 * Ensure items with through holes have all inner copper layers. (For historical reasons
553 * this is NOT trimmed to the currently-enabled inner layers.)
554 */
555 for( FOOTPRINT* fp : m_pcb->Footprints() )
556 {
557 for( PAD* pad : fp->Pads() )
558 {
559 if( pad->HasHole() && pad->IsOnCopperLayer() )
560 pad->SetLayerSet( pad->GetLayerSet() | LSET::InternalCuMask() );
561 }
562 }
563
564 // Tracks do not change their layer
565 // Vias layers are defined by the starting layer and the ending layer, so
566 // they are not modified by adding a layer.
567 // So do nothing for tracks/vias
568
569 modified = true;
570 }
571
572 for( LSEQ seq = LSET::AllLayersMask().Seq(); seq; ++seq )
573 {
574 PCB_LAYER_ID layer = *seq;
575
576 if( m_enabledLayers[layer] )
577 {
578 const wxString& newLayerName = GetLayerName( layer );
579
580 if( m_pcb->GetLayerName( layer ) != newLayerName )
581 {
582 m_pcb->SetLayerName( layer, newLayerName );
583 modified = true;
584 }
585
586 // Only copper layers have a definable type.
587 if( LSET::AllCuMask().Contains( layer ) )
588 {
589 LAYER_T t = (LAYER_T) getLayerTypeIndex( layer );
590
591 if( m_pcb->GetLayerType( layer ) != t )
592 {
593 m_pcb->SetLayerType( layer, t );
594 modified = true;
595 }
596 }
597 }
598 }
599
600 for( LSEQ seq = LSET::UserDefinedLayers().Seq(); seq; ++seq )
601 {
602 PCB_LAYER_ID layer = *seq;
603 const wxString& newLayerName = GetLayerName( layer );
604
605 if( m_enabledLayers[ layer ] && m_pcb->GetLayerName( layer ) != newLayerName )
606 {
607 m_pcb->SetLayerName( layer, newLayerName );
608 modified = true;
609 }
610 }
611
612 // If some board items are deleted: Rebuild the connectivity, because it is likely some
613 // tracks and vias were removed
614 if( hasRemovedBoardItems )
616
617 if( modified )
618 m_frame->OnModify();
619
620 return true;
621}
622
623
625{
626 wxChoice* ctl = getChoice( aLayer );
627 int ret = ctl->GetCurrentSelection(); // Indices must have same sequence as LAYER_T
628 return ret;
629}
630
631
633{
634 wxControl* control = getName( aLayer );
635
636 if( auto textCtl = dynamic_cast<wxTextCtrl*>( control ) )
637 return textCtl->GetValue().Trim();
638 else
639 return control->GetLabel();
640}
641
642
643static bool hasOneOf( const wxString& str, const wxString& chars )
644{
645 for( unsigned i=0; i<chars.Len(); ++i )
646 {
647 if( str.Find( chars[i] ) != wxNOT_FOUND )
648 return true;
649 }
650
651 return false;
652}
653
654
656{
657 std::vector<wxString> names;
658 wxTextCtrl* ctl;
659
660 for( LSEQ seq = LSET::AllLayersMask().Seq(); seq; ++seq )
661 {
662 PCB_LAYER_ID layer = *seq;
663
664 // we _can_ rely on m_enabledLayers being current here:
665
666 if( !m_enabledLayers[layer] )
667 continue;
668
669 wxString name = GetLayerName( layer );
670
671 ctl = (wxTextCtrl*) getName( layer );
672
673 // Check name for legality:
674 // 1) Cannot be blank.
675 // 2) Cannot have blanks.
676 // 3) Cannot have " chars
677 // 4) Cannot be 'signal'
678 // 5) Must be unique.
679 // 6) Cannot have illegal chars in filenames ( some filenames are built from layer names )
680 // like : % $ \ " / :
681 wxString badchars = wxFileName::GetForbiddenChars( wxPATH_DOS );
682 badchars.Append( '%' );
683
684 if( !name )
685 {
686 PAGED_DIALOG::GetDialog( this )->SetError( _( "Layer must have a name." ), this, ctl );
687 return false;
688 }
689
690 if( hasOneOf( name, badchars ) )
691 {
692 wxString msg = wxString::Format(_( "%s are forbidden in layer names." ), badchars );
693 PAGED_DIALOG::GetDialog( this )->SetError( msg, this, ctl );
694 return false;
695 }
696
697 if( name == wxT( "signal" ) )
698 {
699 PAGED_DIALOG::GetDialog( this )->SetError( _( "Layer name \"signal\" is reserved." ),
700 this, ctl );
701 return false;
702 }
703
704 for( const wxString& existingName : names )
705 {
706 if( name == existingName )
707 {
708 wxString msg = wxString::Format(_( "Layer name '%s' already in use." ), name );
709 PAGED_DIALOG::GetDialog( this )->SetError( msg, this, ctl );
710 return false;
711 }
712 }
713
714 names.push_back( name );
715 }
716
717 return true;
718}
719
720
722{
723 LSEQ removedLayers;
724 LSET newLayers = GetUILayerMask();
725 LSET curLayers = m_pcb->GetEnabledLayers();
726
727 if( newLayers == curLayers ) // Return an empty list if no change
728 return removedLayers;
729
730 PCB_LAYER_COLLECTOR collector;
731 LSEQ newLayerSeq = newLayers.Seq();
732
733 for( PCB_LAYER_ID layer_id : curLayers.Seq() )
734 {
735 if( !alg::contains( newLayerSeq, layer_id ) )
736 {
737 collector.SetLayerId( layer_id );
739
740 if( collector.GetCount() != 0 )
741 {
742 // Skip items owned by footprints and footprints when building
743 // the actual list of removed layers: these items are not removed
744 for( int i = 0; i < collector.GetCount(); i++ )
745 {
746 BOARD_ITEM* item = collector[i];
747
748 if( dynamic_cast<FOOTPRINT*>( item )
749 || dynamic_cast<FOOTPRINT*>( item->GetParentFootprint() ) )
750 continue;
751
752 removedLayers.push_back( layer_id );
753 break;
754 }
755 }
756 }
757 }
758
759 return removedLayers;
760}
761
762
764{
765 // Build the list of non-copper layers in use in footprints.
766 LSEQ inUseLayers;
767 LSET newLayers = GetUILayerMask();
768 LSET curLayers = m_pcb->GetEnabledLayers();
769
770 if( newLayers == curLayers ) // Return an empty list if no change
771 return inUseLayers;
772
773 PCB_LAYER_COLLECTOR collector;
774 LSEQ newLayerSeq = newLayers.Seq();
775
776 for( PCB_LAYER_ID layer_id : curLayers.Seq() )
777 {
778 if( IsCopperLayer( layer_id ) ) // Copper layers are not taken into account here
779 continue;
780
781 if( !alg::contains( newLayerSeq, layer_id ) )
782 {
783 collector.SetLayerId( layer_id );
785
786 if( collector.GetCount() != 0 )
787 inUseLayers.push_back( layer_id );
788 }
789 }
790
791 return inUseLayers;
792}
793
794
796{
797 BOARD* savedBoard = m_pcb;
798
799 m_pcb = aBoard;
801
802 m_pcb = savedBoard;
803}
804
805
806bool PANEL_SETUP_LAYERS::CheckCopperLayerCount( BOARD* aWorkingBoard, BOARD* aImportedBoard )
807{
808 /*
809 * This function warns users if they are going to delete inner copper layers because
810 * they're importing settings from a board with less copper layers than the board
811 * already loaded. We want to return "true" as default on the assumption no layer will
812 * actually be deleted.
813 */
814 bool okToDeleteCopperLayers = true;
815
816 // Get the number of copper layers in the loaded board and the "import settings" board
817 int currNumLayers = aWorkingBoard->GetCopperLayerCount();
818 int newNumLayers = aImportedBoard->GetCopperLayerCount();
819
820 if( newNumLayers < currNumLayers )
821 {
822 wxString msg = wxString::Format( _( "Imported settings have fewer copper layers than "
823 "the current board (%i instead of %i).\n\n"
824 "Continue and delete the extra inner copper layers "
825 "from the current board?" ),
826 newNumLayers,
827 currNumLayers );
828
829 wxWindow* topLevelParent = wxGetTopLevelParent( this );
830
831 wxMessageDialog dlg( topLevelParent, msg, _( "Inner Layers To Be Deleted" ),
832 wxICON_WARNING | wxSTAY_ON_TOP | wxYES | wxNO | wxNO_DEFAULT );
833
834 if( wxID_NO == dlg.ShowModal() )
835 okToDeleteCopperLayers = false;
836 }
837
838 return okToDeleteCopperLayers;
839}
840
841
842void PANEL_SETUP_LAYERS::addUserDefinedLayer( wxCommandEvent& aEvent )
843{
844 wxArrayString headers;
845 headers.Add( _( "Layers" ) );
846
847 // Build the available user-defined layers list:
848 std::vector<wxArrayString> list;
849
850 for( LSEQ seq = LSET::UserDefinedLayers().Seq(); seq; ++seq )
851 {
852 wxCheckBox* checkBox = getCheckBox( *seq );
853
854 if( checkBox && checkBox->IsShown() )
855 continue;
856
857 wxArrayString available_user_layer;
858 available_user_layer.Add( LayerName( *seq ) );
859
860 list.emplace_back( available_user_layer );
861 }
862
863 if( list.empty() )
864 {
866 _( "All user-defined layers have already been added." ) );
867 return;
868 }
869
870 EDA_LIST_DIALOG dlg( PAGED_DIALOG::GetDialog( this ), _( "Add User-defined Layer" ),
871 headers, list );
872 dlg.SetListLabel( _( "Select layer to add:" ) );
873 dlg.HideFilter();
874
875 if( dlg.ShowModal() == wxID_CANCEL || dlg.GetTextSelection().IsEmpty() )
876 return;
877
878 LSEQ seq;
879
880 for( seq = LSET::UserDefinedLayers().Seq(); seq; ++seq )
881 {
882 if( LayerName( *seq ) == dlg.GetTextSelection() )
883 break;
884 }
885
886 wxCHECK( *seq >= User_1 && *seq <= User_9, /* void */ );
887
888 LSET newLayer( *seq );
889
890 m_enabledLayers |= newLayer;
891
892 PANEL_SETUP_LAYERS_CTLs ctl = getCTLs( *seq );
893
894 // All user-defined layers should have a checkbox
895 wxASSERT( ctl.checkbox );
896
897 wxTextCtrl* textCtrl = dynamic_cast<wxTextCtrl*>( ctl.name );
898
899 wxCHECK( textCtrl, /* void */ );
900 textCtrl->ChangeValue( LSET::Name( *seq ) );
901 ctl.name->Show( true );
902 ctl.checkbox->Show( true );
903 ctl.choice->Show( true );
904
905 wxSizeEvent evt_size( m_LayersListPanel->GetSize() );
906 m_LayersListPanel->GetEventHandler()->ProcessEvent( evt_size );
907
908 setLayerCheckBox( *seq, true );
909}
910
911
const char * name
Definition: DXF_plotter.cpp:57
constexpr std::size_t arrayDim(T const (&)[N]) noexcept
Returns # of elements in an array.
Definition: arraydim.h:31
LAYER_T
The allowed types of layers, same as Specctra DSN spec.
Definition: board.h:150
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:77
FOOTPRINT * GetParentFootprint() const
Definition: board_item.cpp:248
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition: board_item.h:231
virtual void SetLayerSet(LSET aLayers)
Definition: board_item.h:239
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:282
LSET GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition: board.cpp:677
LSET GetVisibleLayers() const
A proxy function that calls the correspondent function in m_BoardSettings.
Definition: board.cpp:691
void SetEnabledLayers(LSET aLayerMask)
A proxy function that calls the correspondent function in m_BoardSettings.
Definition: board.cpp:697
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:176
bool IsLayerEnabled(PCB_LAYER_ID aLayer) const
A proxy function that calls the correspondent function in m_BoardSettings tests whether a given layer...
Definition: board.cpp:703
LAYER_T GetLayerType(PCB_LAYER_ID aLayer) const
Return the type of the copper layer given by aLayer.
Definition: board.cpp:598
bool SetLayerName(PCB_LAYER_ID aLayer, const wxString &aLayerName)
Changes the name of the layer given by aLayer.
Definition: board.cpp:580
int GetCopperLayerCount() const
Definition: board.cpp:653
const FOOTPRINTS & Footprints() const
Definition: board.h:323
void SetVisibleLayers(LSET aLayerMask)
A proxy function that calls the correspondent function in m_BoardSettings changes the bit-mask of vis...
Definition: board.cpp:709
bool SetLayerType(PCB_LAYER_ID aLayer, LAYER_T aLayerType)
Change the type of the layer given by aLayer.
Definition: board.cpp:610
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition: board.cpp:564
void Remove(BOARD_ITEM *aBoardItem, REMOVE_MODE aMode=REMOVE_MODE::NORMAL) override
Removes an item from the container.
Definition: board.cpp:1020
int GetCount() const
Return the number of objects in the list.
Definition: collector.h:81
A dialog which shows:
wxString GetTextSelection(int aColumn=0)
Return the selected text from aColumn in the wxListCtrl in the dialog.
void SetListLabel(const wxString &aLabel)
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:237
static const std::vector< KICAD_T > FootprintItems
A scan list for primary footprint items.
Definition: collectors.h:252
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
Definition: layer_ids.h:521
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:575
static LSET AllLayersMask()
Definition: lset.cpp:898
static LSET UserDefinedLayers()
Return a mask with all of the allowable user defined layers.
Definition: lset.cpp:967
LSEQ Seq(const PCB_LAYER_ID *aWishListSequence, unsigned aCount) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:418
static LSET InternalCuMask()
Return a complete set of internal copper layers which is all Cu layers except F_Cu and B_Cu.
Definition: lset.cpp:823
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:863
static const wxChar * Name(PCB_LAYER_ID aLayerId)
Return the fixed name association with aLayerId.
Definition: lset.cpp:89
Definition: pad.h:53
static PAGED_DIALOG * GetDialog(wxWindow *aWindow)
void SetError(const wxString &aMessage, const wxString &aPageName, int aCtrlId, int aRow=-1, int aCol=-1)
Class PANEL_SETUP_LAYERS_BASE.
wxScrolledWindow * m_LayersListPanel
wxString GetLayerName(int layer)
PANEL_SETUP_LAYERS_CTLs getCTLs(int aLayerNumber)
void showSelectedLayerCheckBoxes(LSET enableLayerMask)
bool CheckCopperLayerCount(BOARD *aWorkingBoard, BOARD *aImportedBoard)
Check and warn if inner copper layers will be deleted.
void DenyChangeCheckBox(wxCommandEvent &event) override
bool TransferDataToWindow() override
int getLayerTypeIndex(int layer)
virtual void addUserDefinedLayer(wxCommandEvent &aEvent) override
void SyncCopperLayers(int aNumCopperLayers)
Called when switching to this tab to make sure that any changes to the copper layer count made on the...
void setLayerCheckBox(int layer, bool isChecked)
PANEL_SETUP_BOARD_STACKUP * m_physicalStackup
PCB_EDIT_FRAME * m_frame
LSEQ getNonRemovableLayers()
Return a list of layers in use in footprints, and therefore not removable.
void setCopperLayerCheckBoxes(int copperCount)
wxControl * getName(int aLayer)
wxChoice * getChoice(int aLayer)
LSEQ getRemovedLayersWithItems()
Return a list of layers removed from the board that contain items.
bool TransferDataFromWindow() override
void OnCheckBox(wxCommandEvent &event) override
PANEL_SETUP_LAYERS(wxWindow *aParentWindow, PCB_EDIT_FRAME *aFrame)
void ImportSettingsFrom(BOARD *aBoard)
wxCheckBox * getCheckBox(int aLayer)
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: pcb_actions.h:68
BOARD * GetBoard() const
The main frame for Pcbnew.
void OnModify() override
Must be called after a board change to set the modified flag.
Collect all BOARD_ITEM objects on a given layer.
Definition: collectors.h:551
void Collect(BOARD_ITEM *aBoard, const std::vector< KICAD_T > &aTypes)
Test a BOARD_ITEM using this class's Inspector method, which does the collection.
Definition: collectors.cpp:536
void SetLayerId(PCB_LAYER_ID aLayerId)
Definition: collectors.h:557
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
Definition: tools_holder.h:55
bool RunAction(const std::string &aActionName, T aParam)
Run the specified action immediately, pausing the current action to run the new one.
Definition: tool_manager.h:150
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition: confirm.cpp:241
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:161
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition: confirm.cpp:186
This file is part of the common library.
#define _(s)
wxString LayerName(int aLayer)
Returns the default display name for a given layer.
Definition: layer_id.cpp:30
bool IsCopperLayer(int aLayerId)
Tests whether a layer is a copper layer.
Definition: layer_ids.h:881
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
@ In22_Cu
Definition: layer_ids.h:86
@ In11_Cu
Definition: layer_ids.h:75
@ In29_Cu
Definition: layer_ids.h:93
@ In30_Cu
Definition: layer_ids.h:94
@ User_8
Definition: layer_ids.h:130
@ F_CrtYd
Definition: layer_ids.h:117
@ In17_Cu
Definition: layer_ids.h:81
@ B_Adhes
Definition: layer_ids.h:97
@ Edge_Cuts
Definition: layer_ids.h:113
@ Dwgs_User
Definition: layer_ids.h:109
@ F_Paste
Definition: layer_ids.h:101
@ In9_Cu
Definition: layer_ids.h:73
@ Cmts_User
Definition: layer_ids.h:110
@ User_6
Definition: layer_ids.h:128
@ User_7
Definition: layer_ids.h:129
@ In19_Cu
Definition: layer_ids.h:83
@ In7_Cu
Definition: layer_ids.h:71
@ In28_Cu
Definition: layer_ids.h:92
@ In26_Cu
Definition: layer_ids.h:90
@ F_Adhes
Definition: layer_ids.h:98
@ B_Mask
Definition: layer_ids.h:106
@ B_Cu
Definition: layer_ids.h:95
@ User_5
Definition: layer_ids.h:127
@ Eco1_User
Definition: layer_ids.h:111
@ F_Mask
Definition: layer_ids.h:107
@ In21_Cu
Definition: layer_ids.h:85
@ In23_Cu
Definition: layer_ids.h:87
@ B_Paste
Definition: layer_ids.h:100
@ In15_Cu
Definition: layer_ids.h:79
@ In2_Cu
Definition: layer_ids.h:66
@ User_9
Definition: layer_ids.h:131
@ F_Fab
Definition: layer_ids.h:120
@ In10_Cu
Definition: layer_ids.h:74
@ Margin
Definition: layer_ids.h:114
@ F_SilkS
Definition: layer_ids.h:104
@ In4_Cu
Definition: layer_ids.h:68
@ B_CrtYd
Definition: layer_ids.h:116
@ Eco2_User
Definition: layer_ids.h:112
@ In16_Cu
Definition: layer_ids.h:80
@ In24_Cu
Definition: layer_ids.h:88
@ In1_Cu
Definition: layer_ids.h:65
@ Rescue
Definition: layer_ids.h:133
@ User_3
Definition: layer_ids.h:125
@ User_1
Definition: layer_ids.h:123
@ B_SilkS
Definition: layer_ids.h:103
@ In13_Cu
Definition: layer_ids.h:77
@ User_4
Definition: layer_ids.h:126
@ In8_Cu
Definition: layer_ids.h:72
@ In14_Cu
Definition: layer_ids.h:78
@ User_2
Definition: layer_ids.h:124
@ In12_Cu
Definition: layer_ids.h:76
@ In27_Cu
Definition: layer_ids.h:91
@ In6_Cu
Definition: layer_ids.h:70
@ In5_Cu
Definition: layer_ids.h:69
@ In3_Cu
Definition: layer_ids.h:67
@ In20_Cu
Definition: layer_ids.h:84
@ F_Cu
Definition: layer_ids.h:64
@ In18_Cu
Definition: layer_ids.h:82
@ In25_Cu
Definition: layer_ids.h:89
@ B_Fab
Definition: layer_ids.h:119
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
Definition: kicad_algo.h:100
#define RETURN_AUX(x)
#define RETURN_MANDATORY(x)
static LSEQ dlg_layers()
#define RETURN_COPPER(x)
static bool hasOneOf(const wxString &str, const wxString &chars)
The 3 UI control pointers for a single board layer.