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