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