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
128// returns a mask of existing layers in dialog list
130{
131 static const LSET saved( dlg_layers() );
132 return saved;
133}
134
135
136PANEL_SETUP_LAYERS::PANEL_SETUP_LAYERS( wxWindow* aParentWindow, PCB_EDIT_FRAME* aFrame ) :
137 PANEL_SETUP_LAYERS_BASE( aParentWindow ),
138 m_frame( aFrame ),
139 m_physicalStackup( nullptr ),
140 m_initialized( false )
141{
142 m_pcb = aFrame->GetBoard();
143}
144
145
147{
148#define RETURN_COPPER( x ) return PANEL_SETUP_LAYERS_CTLs( x##Name, x##CheckBox, x##Choice )
149#define RETURN_AUX( x ) return PANEL_SETUP_LAYERS_CTLs( x##Name, x##CheckBox, x##StaticText )
150#define RETURN_MANDATORY( x ) return PANEL_SETUP_LAYERS_CTLs( x##Name, nullptr, x##StaticText )
151#define RETURN_USER( x ) return PANEL_SETUP_LAYERS_CTLs( x##Name, x##CheckBox, x##Type )
152
153 switch( aLayerNumber )
154 {
155 case F_CrtYd: RETURN_MANDATORY( m_CrtYdFront );
156 case F_Fab: RETURN_AUX( m_FabFront );
157 case F_Adhes: RETURN_AUX( m_AdhesFront );
158 case F_Paste: RETURN_AUX( m_SoldPFront );
159 case F_SilkS: RETURN_AUX( m_SilkSFront );
160 case F_Mask: RETURN_AUX( m_MaskFront );
161 case F_Cu: RETURN_COPPER( m_Front );
162
163 case In1_Cu: RETURN_COPPER( m_In1 );
164 case In2_Cu: RETURN_COPPER( m_In2 );
165 case In3_Cu: RETURN_COPPER( m_In3 );
166 case In4_Cu: RETURN_COPPER( m_In4 );
167 case In5_Cu: RETURN_COPPER( m_In5 );
168 case In6_Cu: RETURN_COPPER( m_In6 );
169 case In7_Cu: RETURN_COPPER( m_In7 );
170 case In8_Cu: RETURN_COPPER( m_In8 );
171 case In9_Cu: RETURN_COPPER( m_In9 );
172 case In10_Cu: RETURN_COPPER( m_In10 );
173 case In11_Cu: RETURN_COPPER( m_In11 );
174 case In12_Cu: RETURN_COPPER( m_In12 );
175 case In13_Cu: RETURN_COPPER( m_In13 );
176 case In14_Cu: RETURN_COPPER( m_In14 );
177 case In15_Cu: RETURN_COPPER( m_In15 );
178
179 case In16_Cu: RETURN_COPPER( m_In16 );
180 case In17_Cu: RETURN_COPPER( m_In17 );
181 case In18_Cu: RETURN_COPPER( m_In18 );
182 case In19_Cu: RETURN_COPPER( m_In19 );
183 case In20_Cu: RETURN_COPPER( m_In20 );
184 case In21_Cu: RETURN_COPPER( m_In21 );
185 case In22_Cu: RETURN_COPPER( m_In22 );
186 case In23_Cu: RETURN_COPPER( m_In23 );
187 case In24_Cu: RETURN_COPPER( m_In24 );
188 case In25_Cu: RETURN_COPPER( m_In25 );
189 case In26_Cu: RETURN_COPPER( m_In26 );
190 case In27_Cu: RETURN_COPPER( m_In27 );
191 case In28_Cu: RETURN_COPPER( m_In28 );
192 case In29_Cu: RETURN_COPPER( m_In29 );
193 case In30_Cu: RETURN_COPPER( m_In30 );
194
195 case B_Cu: RETURN_COPPER( m_Back );
196 case B_Mask: RETURN_AUX( m_MaskBack );
197 case B_SilkS: RETURN_AUX( m_SilkSBack );
198 case B_Paste: RETURN_AUX( m_SoldPBack );
199 case B_Adhes: RETURN_AUX( m_AdhesBack );
200 case B_Fab: RETURN_AUX( m_FabBack );
201 case B_CrtYd: RETURN_MANDATORY( m_CrtYdBack );
202
203 case Edge_Cuts: RETURN_MANDATORY( m_PCBEdges );
204 case Margin: RETURN_AUX( m_Margin );
205 case Eco2_User: RETURN_AUX( m_Eco2 );
206 case Eco1_User: RETURN_AUX( m_Eco1 );
207 case Cmts_User: RETURN_AUX( m_Comments );
208 case Dwgs_User: RETURN_AUX( m_Drawings );
209
210 case User_1: RETURN_USER( m_User1 );
211 case User_2: RETURN_USER( m_User2 );
212 case User_3: RETURN_USER( m_User3 );
213 case User_4: RETURN_USER( m_User4 );
214 case User_5: RETURN_USER( m_User5 );
215 case User_6: RETURN_USER( m_User6 );
216 case User_7: RETURN_USER( m_User7 );
217 case User_8: RETURN_USER( m_User8 );
218 case User_9: RETURN_USER( m_User9 );
219
220 default:
221 wxASSERT_MSG( 0, wxT( "bad layer id" ) );
222 return PANEL_SETUP_LAYERS_CTLs( nullptr, nullptr, nullptr );
223 }
224}
225
226
227wxControl* PANEL_SETUP_LAYERS::getName( int aLayer )
228{
229 return getCTLs( aLayer ).name;
230}
231
232
233wxCheckBox* PANEL_SETUP_LAYERS::getCheckBox( int aLayer )
234{
235 return getCTLs( aLayer ).checkbox;
236}
237
238
239wxChoice* PANEL_SETUP_LAYERS::getChoice( int aLayer )
240{
241 return (wxChoice*) getCTLs( aLayer ).choice;
242}
243
244
246{
248
249 // Rescue may be enabled, but should not be shown in this dialog
251
253
255
258
262
263 m_initialized = true;
264
265 return true;
266}
267
268
269void PANEL_SETUP_LAYERS::SyncCopperLayers( int aNumCopperLayers )
270{
271 setCopperLayerCheckBoxes( aNumCopperLayers );
272}
273
274
276{
277 for( int layer : { F_CrtYd, B_CrtYd, Edge_Cuts, Margin } )
278 setLayerCheckBox( layer, true );
279}
280
281
283{
284 for( PCB_LAYER_ID layer : LSET::UserDefinedLayers().Seq() )
285 {
286 bool state = m_pcb->IsLayerEnabled( layer );
287
288#ifdef HIDE_INACTIVE_LAYERS
289 // This code hides inactive copper layers, or redisplays hidden layers which are now needed.
290 PANEL_SETUP_LAYERS_CTLs ctl = getCTLs( layer );
291
292 // All user-defined layers should have a checkbox
293 wxASSERT( ctl.checkbox );
294
295 ctl.name->Show( state );
296 ctl.checkbox->Show( state );
297 ctl.choice->Show( state );
298#endif
299
300 setLayerCheckBox( layer, state );
301 }
302
303#ifdef HIDE_INACTIVE_LAYERS
304 // Send an size event to force sizers to be updated,
305 // because the number of copper layers can have changed.
306 wxSizeEvent evt_size( m_LayersListPanel->GetSize() );
307 m_LayersListPanel->GetEventHandler()->ProcessEvent( evt_size );
308#endif
309}
310
311
313{
314 // Set all the board's layer names into the dialog by calling BOARD::GetLayerName(),
315 // which will call BOARD::GetStandardLayerName() for non-coppers.
316
317 for( PCB_LAYER_ID layer : dlg_layers() )
318 {
319 wxControl* ctl = getName( layer );
320
321 if( ctl )
322 {
323 wxString lname = m_pcb->GetLayerName( layer );
324
325 if( auto textCtl = dynamic_cast<wxTextCtrl*>( ctl ) )
326 textCtl->ChangeValue( lname ); // wxTextCtrl
327 else
328 ctl->SetLabel( lname ); // wxStaticText
329 }
330 }
331}
332
333
335{
336 // The check boxes
337 for( PCB_LAYER_ID layer : dlg_layers() )
338 setLayerCheckBox( layer, enabledLayers[layer] );
339}
340
341
343{
344 for( PCB_LAYER_ID cu_layer : LSET::AllCuMask().Seq() )
345 {
346 wxChoice* ctl = getChoice( cu_layer );
347 ctl->SetStringSelection( LAYER::ShowType( m_pcb->GetLayerType( cu_layer ) ) );
348 }
349
350 for( int ii = User_1; ii <= User_9; ++ii )
351 {
352 switch( m_pcb->GetLayerType( ToLAYER_ID( ii ) ) )
353 {
354 case LT_AUX: getChoice( ii )->SetSelection( 0 ); break;
355 case LT_FRONT: getChoice( ii )->SetSelection( 1 ); break;
356 case LT_BACK: getChoice( ii )->SetSelection( 2 ); break;
357 default: getChoice( ii )->SetSelection( 0 ); break;
358 }
359 }
360}
361
362
364{
365 LSET layerMaskResult;
366
367 for( PCB_LAYER_ID layer : dlg_layers() )
368 {
369 wxCheckBox* ctl = getCheckBox( layer );
370
371 if( !ctl || ctl->GetValue() )
372 layerMaskResult.set( layer );
373 }
374
375 return layerMaskResult;
376}
377
378
379void PANEL_SETUP_LAYERS::setLayerCheckBox( int aLayer, bool isChecked )
380{
381 PANEL_SETUP_LAYERS_CTLs ctl = getCTLs( aLayer );
382
383 if( !ctl.checkbox )
384 return;
385
386 ctl.checkbox->SetValue( isChecked );
387}
388
389
391{
392 if( copperCount > 0 )
393 {
394 setLayerCheckBox( F_Cu, true );
395 --copperCount;
396 }
397
398 if( copperCount > 0 )
399 {
400 setLayerCheckBox( B_Cu, true );
401 --copperCount;
402 }
403
404 for( PCB_LAYER_ID layer : LSET::InternalCuMask().Seq() )
405 {
406 bool state = copperCount > 0;
407
408#ifdef HIDE_INACTIVE_LAYERS
409 // This code hides inactive copper layers, or redisplays hidden layers which are now needed.
410 PANEL_SETUP_LAYERS_CTLs ctl = getCTLs( layer );
411
412 // Inner layers should have a checkbox
413 wxASSERT( ctl.checkbox );
414
415 ctl.name->Show( state );
416 ctl.checkbox->Show( state );
417 ctl.choice->Show( state );
418#endif
419
420 setLayerCheckBox( layer, state );
421 --copperCount;
422 }
423
424#ifdef HIDE_INACTIVE_LAYERS
425 // Send an size event to force sizers to be updated,
426 // because the number of copper layers can have changed.
427 wxSizeEvent evt_size( m_LayersListPanel->GetSize() );
428 m_LayersListPanel->GetEventHandler()->ProcessEvent( evt_size );
429#endif
430}
431
432
433void PANEL_SETUP_LAYERS::OnCheckBox( wxCommandEvent& event )
434{
436}
437
438
439void PANEL_SETUP_LAYERS::DenyChangeCheckBox( wxCommandEvent& event )
440{
441 wxObject* source = event.GetEventObject();
442
443 for( PCB_LAYER_ID layer : LSET::AllCuMask().Seq() )
444 {
445 wxCheckBox* copper = getCheckBox( layer );
446
447 if( source == copper )
448 {
449 DisplayError( wxGetTopLevelParent( this ),
450 _( "Use the Physical Stackup page to change the number of "
451 "copper layers." ) );
452
453 copper->SetValue( true );
454 return;
455 }
456 }
457}
458
459
461{
462 if( !testLayerNames() )
463 return false;
464
465 // Make sure we have the latest copper layer count
468
469 wxString msg;
470 bool modified = false;
471
472 // Check for removed layers with items which will get deleted from the board.
473 LSEQ removedLayers = getRemovedLayersWithItems();
474
475 // Check for non-copper layers in use in footprints, and therefore not removable.
476 LSEQ notremovableLayers = getNonRemovableLayers();
477
478 if( !notremovableLayers.empty() )
479 {
480 for( unsigned int ii = 0; ii < notremovableLayers.size(); ii++ )
481 msg << m_pcb->GetLayerName( notremovableLayers[ii] ) << wxT( "\n" );
482
483 if( !IsOK( wxGetTopLevelParent( this ),
484 wxString::Format( _( "Footprints have some items on removed layers:\n"
485 "%s\n"
486 "These items will be no longer accessible\n"
487 "Do you wish to continue?" ), msg ) ) )
488 {
489 return false;
490 }
491 }
492
493 if( !removedLayers.empty()
494 && !IsOK( wxGetTopLevelParent( this ),
495 _( "Items have been found on removed layers. This operation will "
496 "delete all items from removed layers and cannot be undone.\n"
497 "Do you wish to continue?" ) ) )
498 {
499 return false;
500 }
501
502 // Delete all objects on layers that have been removed. Leaving them in copper layers
503 // can (will?) result in DRC errors and it pollutes the board file with cruft.
504 bool hasRemovedBoardItems = false;
505
506 if( !removedLayers.empty() )
507 {
509
510 PCB_LAYER_COLLECTOR collector;
511
512 for( PCB_LAYER_ID layer_id : removedLayers )
513 {
514 collector.SetLayerId( layer_id );
516
517 // Bye-bye items on removed layer.
518 for( int i = 0; i < collector.GetCount(); i++ )
519 {
520 BOARD_ITEM* item = collector[i];
521
522 // Do not remove/change an item owned by a footprint
523 if( item->GetParentFootprint() )
524 continue;
525
526 // Do not remove footprints
527 if( item->Type() == PCB_FOOTPRINT_T )
528 continue;
529
530 // Vias are also specific
531 // Note: vias are specific. They are only on copper layers, and
532 // do not use a layer set, only store the copper top and the copper bottom.
533 // So reinit the layer set does not work with vias
534 if( item->Type() == PCB_VIA_T )
535 {
536 PCB_VIA* via = static_cast<PCB_VIA*>( item );
537
538 if( via->GetViaType() == VIATYPE::THROUGH )
539 continue;
540 else
541 {
542 PCB_LAYER_ID top_layer;
543 PCB_LAYER_ID bottom_layer;
544 via->LayerPair( &top_layer, &bottom_layer );
545
546 if( top_layer != layer_id && bottom_layer != layer_id )
547 continue;
548 }
549 // blind/buried vias with a top or bottom layer on a removed layer
550 // are removed. Perhaps one could just modify the top/bottom layer,
551 // but I am not sure this is better.
552 m_pcb->Remove( item );
553 delete item;
554 }
555 else
556 {
557 LSET layers = item->GetLayerSet();
558
559 layers.reset( layer_id );
560 hasRemovedBoardItems = true;
561 modified = true;
562
563 if( layers.any() )
564 {
565 item->SetLayerSet( layers );
566 }
567 else
568 {
569 m_pcb->Remove( item );
570 delete item;
571 }
572 }
573 }
574 }
575
576 // Undo state may have copies of pointers deleted above
578 }
579
581
582 LSET previousEnabled = m_pcb->GetEnabledLayers();
583
584 if( m_enabledLayers != previousEnabled )
585 {
587
588 LSET changedLayers = m_enabledLayers ^ previousEnabled;
589
590 /*
591 * Ensure enabled layers are also visible. This is mainly to avoid mistakes if some
592 * enabled layers are not visible when exiting this dialog.
593 */
594 m_pcb->SetVisibleLayers( m_pcb->GetVisibleLayers() | changedLayers );
595
596 /*
597 * Ensure items with through holes have all inner copper layers. (For historical reasons
598 * this is NOT trimmed to the currently-enabled inner layers.)
599 */
600 for( FOOTPRINT* fp : m_pcb->Footprints() )
601 {
602 for( PAD* pad : fp->Pads() )
603 {
604 if( pad->HasHole() && pad->IsOnCopperLayer() )
605 pad->SetLayerSet( pad->GetLayerSet() | LSET::InternalCuMask() );
606 }
607 }
608
609 // Tracks do not change their layer
610 // Vias layers are defined by the starting layer and the ending layer, so
611 // they are not modified by adding a layer.
612 // So do nothing for tracks/vias
613
614 modified = true;
615 }
616
617 for( PCB_LAYER_ID layer : LSET::AllLayersMask().Seq() )
618 {
619 if( m_enabledLayers[layer] )
620 {
621 const wxString& newLayerName = GetLayerName( layer );
622
623 if( m_pcb->GetLayerName( layer ) != newLayerName )
624 {
625 m_pcb->SetLayerName( layer, newLayerName );
626 modified = true;
627 }
628
629 if( IsCopperLayer( layer ) )
630 {
631 LAYER_T t;
632
633 switch( getChoice( layer )->GetCurrentSelection() )
634 {
635 case 0: t = LT_SIGNAL; break;
636 case 1: t = LT_POWER; break;
637 case 2: t = LT_MIXED; break;
638 case 3: t = LT_JUMPER; break;
639 default: t = LT_UNDEFINED; break;
640 }
641
642 if( m_pcb->GetLayerType( layer ) != t )
643 {
644 m_pcb->SetLayerType( layer, t );
645 modified = true;
646 }
647 }
648 else if( layer >= User_1 && layer <= User_9 )
649 {
650 LAYER_T t;
651
652 switch( getChoice( layer )->GetCurrentSelection() )
653 {
654 case 0: t = LT_AUX; break;
655 case 1: t = LT_FRONT; break;
656 case 2: t = LT_BACK; break;
657 default: t = LT_UNDEFINED; break;
658 }
659
660 if( m_pcb->GetLayerType( layer ) != t )
661 {
662 m_pcb->SetLayerType( layer, t );
663 modified = true;
664 }
665 }
666 }
667 }
668
669 for( PCB_LAYER_ID layer : LSET::UserDefinedLayers().Seq() )
670 {
671 const wxString& newLayerName = GetLayerName( layer );
672
673 if( m_enabledLayers[ layer ] && m_pcb->GetLayerName( layer ) != newLayerName )
674 {
675 m_pcb->SetLayerName( layer, newLayerName );
676 modified = true;
677 }
678 }
679
680 // If some board items are deleted: Rebuild the connectivity, because it is likely some
681 // tracks and vias were removed
682 if( hasRemovedBoardItems )
684
685 if( modified )
686 m_frame->OnModify();
687
688 return true;
689}
690
691
693{
694 wxControl* control = getName( aLayer );
695
696 if( auto textCtl = dynamic_cast<wxTextCtrl*>( control ) )
697 return textCtl->GetValue().Trim();
698 else
699 return control->GetLabel();
700}
701
702
703static bool hasOneOf( const wxString& str, const wxString& chars )
704{
705 for( unsigned i=0; i<chars.Len(); ++i )
706 {
707 if( str.Find( chars[i] ) != wxNOT_FOUND )
708 return true;
709 }
710
711 return false;
712}
713
714
716{
717 std::vector<wxString> names;
718 wxTextCtrl* ctl;
719
720 for( PCB_LAYER_ID layer : LSET::AllLayersMask().Seq() )
721 {
722 // we _can_ rely on m_enabledLayers being current here:
723
724 if( !m_enabledLayers[layer] )
725 continue;
726
727 wxString name = GetLayerName( layer );
728
729 ctl = (wxTextCtrl*) getName( layer );
730
731 // Check name for legality:
732 // 1) Cannot be blank.
733 // 2) Cannot have blanks.
734 // 3) Cannot have " chars
735 // 4) Cannot be 'signal'
736 // 5) Must be unique.
737 // 6) Cannot have illegal chars in filenames ( some filenames are built from layer names )
738 // like : % $ \ " / :
739 wxString badchars = wxFileName::GetForbiddenChars( wxPATH_DOS );
740 badchars.Append( '%' );
741
742 if( !name )
743 {
744 PAGED_DIALOG::GetDialog( this )->SetError( _( "Layer must have a name." ), this, ctl );
745 return false;
746 }
747
748 if( hasOneOf( name, badchars ) )
749 {
750 wxString msg = wxString::Format(_( "%s are forbidden in layer names." ), badchars );
751 PAGED_DIALOG::GetDialog( this )->SetError( msg, this, ctl );
752 return false;
753 }
754
755 if( name == wxT( "signal" ) )
756 {
757 PAGED_DIALOG::GetDialog( this )->SetError( _( "Layer name \"signal\" is reserved." ),
758 this, ctl );
759 return false;
760 }
761
762 for( const wxString& existingName : names )
763 {
764 if( name == existingName )
765 {
766 wxString msg = wxString::Format(_( "Layer name '%s' already in use." ), name );
767 PAGED_DIALOG::GetDialog( this )->SetError( msg, this, ctl );
768 return false;
769 }
770 }
771
772 names.push_back( name );
773 }
774
775 return true;
776}
777
778
780{
781 LSEQ removedLayers;
782 LSET newLayers = GetUILayerMask();
783 LSET curLayers = m_pcb->GetEnabledLayers();
784
785 if( newLayers == curLayers ) // Return an empty list if no change
786 return removedLayers;
787
788 PCB_LAYER_COLLECTOR collector;
789 LSEQ newLayerSeq = newLayers.Seq();
790
791 for( PCB_LAYER_ID layer_id : curLayers.Seq() )
792 {
793 if( !alg::contains( newLayerSeq, layer_id ) )
794 {
795 collector.SetLayerId( layer_id );
797
798 if( collector.GetCount() != 0 )
799 {
800 // Skip items owned by footprints and footprints when building
801 // the actual list of removed layers: these items are not removed
802 for( int i = 0; i < collector.GetCount(); i++ )
803 {
804 BOARD_ITEM* item = collector[i];
805
806 if( item->Type() == PCB_FOOTPRINT_T || item->GetParentFootprint() )
807 continue;
808
809 // Vias are on multiple adjacent layers, but only the top and
810 // the bottom layers are stored. So there are issues only if one
811 // is on a removed layer
812 if( item->Type() == PCB_VIA_T )
813 {
814 PCB_VIA* via = static_cast<PCB_VIA*>( item );
815
816 if( via->GetViaType() == VIATYPE::THROUGH )
817 continue;
818 else
819 {
820 PCB_LAYER_ID top_layer;
821 PCB_LAYER_ID bottom_layer;
822 via->LayerPair( &top_layer, &bottom_layer );
823
824 if( top_layer != layer_id && bottom_layer != layer_id )
825 continue;
826 }
827 }
828
829 removedLayers.push_back( layer_id );
830 break;
831 }
832 }
833 }
834 }
835
836 return removedLayers;
837}
838
839
841{
842 // Build the list of non-copper layers in use in footprints.
843 LSEQ inUseLayers;
844 LSET newLayers = GetUILayerMask();
845 LSET curLayers = m_pcb->GetEnabledLayers();
846
847 if( newLayers == curLayers ) // Return an empty list if no change
848 return inUseLayers;
849
850 PCB_LAYER_COLLECTOR collector;
851 LSEQ newLayerSeq = newLayers.Seq();
852
853 for( PCB_LAYER_ID layer_id : curLayers.Seq() )
854 {
855 if( IsCopperLayer( layer_id ) ) // Copper layers are not taken into account here
856 continue;
857
858 if( !alg::contains( newLayerSeq, layer_id ) )
859 {
860 collector.SetLayerId( layer_id );
862
863 if( collector.GetCount() != 0 )
864 inUseLayers.push_back( layer_id );
865 }
866 }
867
868 return inUseLayers;
869}
870
871
873{
874 BOARD* savedBoard = m_pcb;
875
876 m_pcb = aBoard;
878
879 m_pcb = savedBoard;
880}
881
882
883bool PANEL_SETUP_LAYERS::CheckCopperLayerCount( BOARD* aWorkingBoard, BOARD* aImportedBoard )
884{
885 /*
886 * This function warns users if they are going to delete inner copper layers because
887 * they're importing settings from a board with less copper layers than the board
888 * already loaded. We want to return "true" as default on the assumption no layer will
889 * actually be deleted.
890 */
891 bool okToDeleteCopperLayers = true;
892
893 // Get the number of copper layers in the loaded board and the "import settings" board
894 int currNumLayers = aWorkingBoard->GetCopperLayerCount();
895 int newNumLayers = aImportedBoard->GetCopperLayerCount();
896
897 if( newNumLayers < currNumLayers )
898 {
899 wxString msg = wxString::Format( _( "Imported settings have fewer copper layers than "
900 "the current board (%i instead of %i).\n\n"
901 "Continue and delete the extra inner copper layers "
902 "from the current board?" ),
903 newNumLayers,
904 currNumLayers );
905
906 wxWindow* topLevelParent = wxGetTopLevelParent( this );
907
908 wxMessageDialog dlg( topLevelParent, msg, _( "Inner Layers to Be Deleted" ),
909 wxICON_WARNING | wxSTAY_ON_TOP | wxYES | wxNO | wxNO_DEFAULT );
910
911 if( wxID_NO == dlg.ShowModal() )
912 okToDeleteCopperLayers = false;
913 }
914
915 return okToDeleteCopperLayers;
916}
917
918
919void PANEL_SETUP_LAYERS::addUserDefinedLayer( wxCommandEvent& aEvent )
920{
921 wxArrayString headers;
922 headers.Add( _( "Layers" ) );
923
924 // Build the available user-defined layers list:
925 std::vector<wxArrayString> list;
926
927 for( PCB_LAYER_ID layer : LSET::UserDefinedLayers().Seq() )
928 {
929 wxCheckBox* checkBox = getCheckBox( layer );
930
931 if( checkBox && checkBox->IsShown() )
932 continue;
933
934 wxArrayString available_user_layer;
935 available_user_layer.Add( LayerName( layer ) );
936
937 list.emplace_back( available_user_layer );
938 }
939
940 if( list.empty() )
941 {
943 _( "All user-defined layers have already been added." ) );
944 return;
945 }
946
947 EDA_LIST_DIALOG dlg( PAGED_DIALOG::GetDialog( this ), _( "Add User-defined Layer" ),
948 headers, list );
949 dlg.SetListLabel( _( "Select layer to add:" ) );
950 dlg.HideFilter();
951
952 if( dlg.ShowModal() == wxID_CANCEL || dlg.GetTextSelection().IsEmpty() )
953 return;
954
956
957 for( PCB_LAYER_ID layer2 : LSET::UserDefinedLayers().Seq() )
958 {
959 if( LayerName( layer2 ) == dlg.GetTextSelection() )
960 {
961 layer = layer2;
962 break;
963 }
964 }
965
966 wxCHECK( layer >= User_1 && layer <= User_9, /* void */ );
967
968 LSET newLayer( { layer } );
969
970 m_enabledLayers |= newLayer;
971
972 PANEL_SETUP_LAYERS_CTLs ctl = getCTLs( layer );
973
974 // All user-defined layers should have a checkbox
975 wxASSERT( ctl.checkbox );
976 ctl.checkbox->SetValue( true );
977
978 wxTextCtrl* textCtrl = dynamic_cast<wxTextCtrl*>( ctl.name );
979
980 wxCHECK( textCtrl, /* void */ );
981 textCtrl->ChangeValue( LSET::Name( layer ) );
982
983 wxChoice* userLayerType = dynamic_cast<wxChoice*>( ctl.choice );
984
985 wxCHECK( userLayerType, /* void */ );
986 userLayerType->SetSelection( 0 );
987
988 ctl.name->Show( true );
989 ctl.checkbox->Show( true );
990 ctl.choice->Show( true );
991
992 wxSizeEvent evt_size( m_LayersListPanel->GetSize() );
993 m_LayersListPanel->GetEventHandler()->ProcessEvent( evt_size );
994}
995
996
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:153
@ LT_POWER
Definition: board.h:156
@ LT_FRONT
Definition: board.h:160
@ LT_MIXED
Definition: board.h:157
@ LT_BACK
Definition: board.h:161
@ LT_UNDEFINED
Definition: board.h:154
@ LT_JUMPER
Definition: board.h:158
@ LT_AUX
Definition: board.h:159
@ LT_SIGNAL
Definition: board.h:155
BASE_SET & reset(size_t pos)
Definition: base_set.h:142
BASE_SET & set(size_t pos)
Definition: base_set.h:115
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:79
virtual void SetLayerSet(const LSET &aLayers)
Definition: board_item.h:265
FOOTPRINT * GetParentFootprint() const
Definition: board_item.cpp:299
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition: board_item.h:257
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:290
LSET GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition: board.cpp:775
LSET GetVisibleLayers() const
A proxy function that calls the correspondent function in m_BoardSettings.
Definition: board.cpp:789
void SetEnabledLayers(LSET aLayerMask)
A proxy function that calls the correspondent function in m_BoardSettings.
Definition: board.cpp:795
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:187
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:801
LAYER_T GetLayerType(PCB_LAYER_ID aLayer) const
Return the type of the copper layer given by aLayer.
Definition: board.cpp:615
bool SetLayerName(PCB_LAYER_ID aLayer, const wxString &aLayerName)
Changes the name of the layer given by aLayer.
Definition: board.cpp:595
int GetCopperLayerCount() const
Definition: board.cpp:738
const FOOTPRINTS & Footprints() const
Definition: board.h:331
void SetVisibleLayers(LSET aLayerMask)
A proxy function that calls the correspondent function in m_BoardSettings changes the bit-mask of vis...
Definition: board.cpp:807
bool SetLayerType(PCB_LAYER_ID aLayer, LAYER_T aLayerType)
Change the type of the layer given by aLayer.
Definition: board.cpp:629
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition: board.cpp:579
void Remove(BOARD_ITEM *aBoardItem, REMOVE_MODE aMode=REMOVE_MODE::NORMAL) override
Removes an item from the container.
Definition: board.cpp:1138
int GetCount() const
Return the number of objects in the list.
Definition: collector.h:81
int ShowModal() override
virtual void ClearUndoRedoList()
Clear the undo and redo list using ClearUndoORRedoList()
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:101
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:233
static const std::vector< KICAD_T > FootprintItems
A scan list for primary footprint items.
Definition: collectors.h:248
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:36
static LSET AllLayersMask()
Definition: lset.cpp:701
static LSET UserDefinedLayers()
Return a mask with all of the allowable user defined layers.
Definition: lset.cpp:763
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:665
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:676
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:410
static wxString Name(PCB_LAYER_ID aLayerId)
Return the fixed name association with aLayerId.
Definition: lset.cpp:183
Definition: pad.h:54
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
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:539
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:545
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:250
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:170
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition: confirm.cpp:195
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:31
bool IsCopperLayer(int aLayerId)
Tests whether a layer is a copper layer.
Definition: layer_ids.h:531
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
@ In22_Cu
Definition: layer_ids.h:87
@ In11_Cu
Definition: layer_ids.h:76
@ In29_Cu
Definition: layer_ids.h:94
@ In30_Cu
Definition: layer_ids.h:95
@ User_8
Definition: layer_ids.h:131
@ F_CrtYd
Definition: layer_ids.h:116
@ In17_Cu
Definition: layer_ids.h:82
@ B_Adhes
Definition: layer_ids.h:103
@ Edge_Cuts
Definition: layer_ids.h:112
@ Dwgs_User
Definition: layer_ids.h:107
@ F_Paste
Definition: layer_ids.h:104
@ In9_Cu
Definition: layer_ids.h:74
@ Cmts_User
Definition: layer_ids.h:108
@ User_6
Definition: layer_ids.h:129
@ User_7
Definition: layer_ids.h:130
@ In19_Cu
Definition: layer_ids.h:84
@ In7_Cu
Definition: layer_ids.h:72
@ In28_Cu
Definition: layer_ids.h:93
@ In26_Cu
Definition: layer_ids.h:91
@ F_Adhes
Definition: layer_ids.h:102
@ B_Mask
Definition: layer_ids.h:98
@ B_Cu
Definition: layer_ids.h:65
@ User_5
Definition: layer_ids.h:128
@ Eco1_User
Definition: layer_ids.h:109
@ F_Mask
Definition: layer_ids.h:97
@ In21_Cu
Definition: layer_ids.h:86
@ In23_Cu
Definition: layer_ids.h:88
@ B_Paste
Definition: layer_ids.h:105
@ In15_Cu
Definition: layer_ids.h:80
@ In2_Cu
Definition: layer_ids.h:67
@ User_9
Definition: layer_ids.h:132
@ F_Fab
Definition: layer_ids.h:119
@ In10_Cu
Definition: layer_ids.h:75
@ Margin
Definition: layer_ids.h:113
@ F_SilkS
Definition: layer_ids.h:100
@ In4_Cu
Definition: layer_ids.h:69
@ B_CrtYd
Definition: layer_ids.h:115
@ UNDEFINED_LAYER
Definition: layer_ids.h:61
@ Eco2_User
Definition: layer_ids.h:110
@ In16_Cu
Definition: layer_ids.h:81
@ In24_Cu
Definition: layer_ids.h:89
@ In1_Cu
Definition: layer_ids.h:66
@ Rescue
Definition: layer_ids.h:121
@ User_3
Definition: layer_ids.h:126
@ User_1
Definition: layer_ids.h:124
@ B_SilkS
Definition: layer_ids.h:101
@ In13_Cu
Definition: layer_ids.h:78
@ User_4
Definition: layer_ids.h:127
@ In8_Cu
Definition: layer_ids.h:73
@ In14_Cu
Definition: layer_ids.h:79
@ User_2
Definition: layer_ids.h:125
@ In12_Cu
Definition: layer_ids.h:77
@ In27_Cu
Definition: layer_ids.h:92
@ In6_Cu
Definition: layer_ids.h:71
@ In5_Cu
Definition: layer_ids.h:70
@ In3_Cu
Definition: layer_ids.h:68
@ In20_Cu
Definition: layer_ids.h:85
@ F_Cu
Definition: layer_ids.h:64
@ In18_Cu
Definition: layer_ids.h:83
@ In25_Cu
Definition: layer_ids.h:90
@ B_Fab
Definition: layer_ids.h:118
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition: lset.cpp:810
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)
static LSET AllExistingLayersInDlgMask()
#define RETURN_MANDATORY(x)
static LSEQ dlg_layers()
#define RETURN_COPPER(x)
#define RETURN_USER(x)
static bool hasOneOf(const wxString &str, const wxString &chars)
std::deque< BOARD_ITEM * > GetCurrentSelection()
Get the list of selected objects.
static const char * ShowType(LAYER_T aType)
Convert a LAYER_T enum to a string representation of the layer type.
Definition: board.cpp:642
The 3 UI control pointers for a single board layer.
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:97
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
Definition: typeinfo.h:86