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