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