You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

767 lines
22 KiB

14 years ago
  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-2018 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. #include <fctsys.h>
  26. #include <macros.h>
  27. #include <confirm.h>
  28. #include <pcbnew.h>
  29. #include <pcb_edit_frame.h>
  30. #include <view/view.h>
  31. #include <invoke_pcb_dialog.h>
  32. #include <class_board.h>
  33. #include <collectors.h>
  34. #include <panel_setup_layers.h>
  35. // some define to choose how copper layers widgets are shown
  36. // if defined, display only active copper layers
  37. // if not displays always 1=the full set (32 copper layers)
  38. #define HIDE_INACTIVE_LAYERS
  39. static LSEQ dlg_layers()
  40. {
  41. // layers that are put out into the dialog UI, coordinate with wxformbuilder and
  42. // getCTLs( LAYER_NUM aLayerNumber )
  43. static const PCB_LAYER_ID layers[] = {
  44. F_CrtYd,
  45. F_Fab,
  46. F_Adhes,
  47. F_Paste,
  48. F_SilkS,
  49. F_Mask,
  50. F_Cu,
  51. In1_Cu,
  52. In2_Cu,
  53. In3_Cu,
  54. In4_Cu,
  55. In5_Cu,
  56. In6_Cu,
  57. In7_Cu,
  58. In8_Cu,
  59. In9_Cu,
  60. In10_Cu,
  61. In11_Cu,
  62. In12_Cu,
  63. In13_Cu,
  64. In14_Cu,
  65. In15_Cu,
  66. In16_Cu,
  67. In17_Cu,
  68. In18_Cu,
  69. In19_Cu,
  70. In20_Cu,
  71. In21_Cu,
  72. In22_Cu,
  73. In23_Cu,
  74. In24_Cu,
  75. In25_Cu,
  76. In26_Cu,
  77. In27_Cu,
  78. In28_Cu,
  79. In29_Cu,
  80. In30_Cu,
  81. B_Cu,
  82. B_Mask,
  83. B_SilkS,
  84. B_Paste,
  85. B_Adhes,
  86. B_Fab,
  87. B_CrtYd,
  88. Edge_Cuts,
  89. Margin,
  90. Eco2_User,
  91. Eco1_User,
  92. Cmts_User,
  93. Dwgs_User,
  94. };
  95. return LSEQ( layers, layers + DIM( layers ) );
  96. }
  97. // Layer bit masks for each defined "Preset Layer Grouping"
  98. static const LSET presets[] =
  99. {
  100. LSET(), // shift the array index up by one, matches with "Custom".
  101. // "Two layers, parts on Front only"
  102. LSET( 2, F_Cu, B_Cu ) | LSET::FrontTechMask() | LSET::UserMask(),
  103. // "Two layers, parts on Back only",
  104. LSET( 2, F_Cu, B_Cu ) | LSET::BackTechMask() | LSET::UserMask(),
  105. // "Two layers, parts on Front and Back",
  106. LSET( 2, F_Cu, B_Cu ) | LSET::FrontTechMask() | LSET::BackTechMask() | LSET::UserMask(),
  107. // "Four layers, parts on Front only"
  108. LSET( 4, F_Cu, B_Cu, In1_Cu, In2_Cu ) | LSET::FrontTechMask() | LSET::UserMask(),
  109. // "Four layers, parts on Front and Back"
  110. LSET( 4, F_Cu, B_Cu, In1_Cu, In2_Cu ) | LSET::FrontTechMask() | LSET::BackTechMask() |
  111. LSET::UserMask(),
  112. // "All layers on",
  113. LSET().set(),
  114. };
  115. PANEL_SETUP_LAYERS::PANEL_SETUP_LAYERS( PAGED_DIALOG* aParent, PCB_EDIT_FRAME* aFrame ) :
  116. PANEL_SETUP_LAYERS_BASE( aParent->GetTreebook() ),
  117. m_Parent( aParent ),
  118. m_pcbThickness( aFrame, m_thicknessLabel, m_thicknessCtrl, m_thicknessUnits, true,
  119. Millimeter2iu( 0.1 ), Millimeter2iu( 10.0 ) )
  120. {
  121. m_pcb = aFrame->GetBoard();
  122. m_LayersListPanel->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_LISTBOX) );
  123. }
  124. PANEL_SETUP_LAYERS_CTLs PANEL_SETUP_LAYERS::getCTLs( LAYER_NUM aLayerNumber )
  125. {
  126. #define RETURN_COPPER(x) return PANEL_SETUP_LAYERS_CTLs( x##Name, x##CheckBox, x##Choice )
  127. #define RETURN_AUX(x) return PANEL_SETUP_LAYERS_CTLs( x##Name, x##CheckBox, x##StaticText )
  128. switch( aLayerNumber )
  129. {
  130. case F_CrtYd: RETURN_AUX( m_CrtYdFront );
  131. case F_Fab: RETURN_AUX( m_FabFront );
  132. case F_Adhes: RETURN_AUX( m_AdhesFront );
  133. case F_Paste: RETURN_AUX( m_SoldPFront );
  134. case F_SilkS: RETURN_AUX( m_SilkSFront );
  135. case F_Mask: RETURN_AUX( m_MaskFront );
  136. case F_Cu: RETURN_COPPER( m_Front );
  137. case In1_Cu: RETURN_COPPER( m_In1 );
  138. case In2_Cu: RETURN_COPPER( m_In2 );
  139. case In3_Cu: RETURN_COPPER( m_In3 );
  140. case In4_Cu: RETURN_COPPER( m_In4 );
  141. case In5_Cu: RETURN_COPPER( m_In5 );
  142. case In6_Cu: RETURN_COPPER( m_In6 );
  143. case In7_Cu: RETURN_COPPER( m_In7 );
  144. case In8_Cu: RETURN_COPPER( m_In8 );
  145. case In9_Cu: RETURN_COPPER( m_In9 );
  146. case In10_Cu: RETURN_COPPER( m_In10 );
  147. case In11_Cu: RETURN_COPPER( m_In11 );
  148. case In12_Cu: RETURN_COPPER( m_In12 );
  149. case In13_Cu: RETURN_COPPER( m_In13 );
  150. case In14_Cu: RETURN_COPPER( m_In14 );
  151. case In15_Cu: RETURN_COPPER( m_In15 );
  152. case In16_Cu: RETURN_COPPER( m_In16 );
  153. case In17_Cu: RETURN_COPPER( m_In17 );
  154. case In18_Cu: RETURN_COPPER( m_In18 );
  155. case In19_Cu: RETURN_COPPER( m_In19 );
  156. case In20_Cu: RETURN_COPPER( m_In20 );
  157. case In21_Cu: RETURN_COPPER( m_In21 );
  158. case In22_Cu: RETURN_COPPER( m_In22 );
  159. case In23_Cu: RETURN_COPPER( m_In23 );
  160. case In24_Cu: RETURN_COPPER( m_In24 );
  161. case In25_Cu: RETURN_COPPER( m_In25 );
  162. case In26_Cu: RETURN_COPPER( m_In26 );
  163. case In27_Cu: RETURN_COPPER( m_In27 );
  164. case In28_Cu: RETURN_COPPER( m_In28 );
  165. case In29_Cu: RETURN_COPPER( m_In29 );
  166. case In30_Cu: RETURN_COPPER( m_In30 );
  167. case B_Cu: RETURN_COPPER( m_Back );
  168. case B_Mask: RETURN_AUX( m_MaskBack );
  169. case B_SilkS: RETURN_AUX( m_SilkSBack );
  170. case B_Paste: RETURN_AUX( m_SoldPBack );
  171. case B_Adhes: RETURN_AUX( m_AdhesBack );
  172. case B_Fab: RETURN_AUX( m_FabBack );
  173. case B_CrtYd: RETURN_AUX( m_CrtYdBack );
  174. case Edge_Cuts: RETURN_AUX( m_PCBEdges );
  175. case Margin: RETURN_AUX( m_Margin );
  176. case Eco2_User: RETURN_AUX( m_Eco2 );
  177. case Eco1_User: RETURN_AUX( m_Eco1 );
  178. case Cmts_User: RETURN_AUX( m_Comments );
  179. case Dwgs_User: RETURN_AUX( m_Drawings );
  180. default:
  181. wxASSERT_MSG( 0, wxT( "bad layer id" ) );
  182. return PANEL_SETUP_LAYERS_CTLs( nullptr, nullptr, nullptr );
  183. }
  184. }
  185. wxControl* PANEL_SETUP_LAYERS::getName( LAYER_NUM aLayer )
  186. {
  187. return getCTLs( aLayer ).name;
  188. }
  189. wxCheckBox* PANEL_SETUP_LAYERS::getCheckBox( LAYER_NUM aLayer )
  190. {
  191. return getCTLs( aLayer ).checkbox;
  192. }
  193. wxChoice* PANEL_SETUP_LAYERS::getChoice( LAYER_NUM aLayer )
  194. {
  195. return (wxChoice*) getCTLs( aLayer ).choice;
  196. }
  197. bool PANEL_SETUP_LAYERS::TransferDataToWindow()
  198. {
  199. m_enabledLayers = m_pcb->GetEnabledLayers();
  200. showCopperChoice( m_pcb->GetCopperLayerCount() );
  201. setCopperLayerCheckBoxes( m_pcb->GetCopperLayerCount() );
  202. m_pcbThickness.SetValue( m_pcb->GetDesignSettings().GetBoardThickness() );
  203. showBoardLayerNames();
  204. showSelectedLayerCheckBoxes( m_enabledLayers );
  205. showPresets( m_enabledLayers );
  206. showLayerTypes();
  207. setMandatoryLayerCheckBoxes();
  208. return true;
  209. }
  210. void PANEL_SETUP_LAYERS::setMandatoryLayerCheckBoxes()
  211. {
  212. for( int layer : { F_CrtYd, B_CrtYd, Edge_Cuts, Margin } )
  213. setLayerCheckBox( layer, true );
  214. }
  215. void PANEL_SETUP_LAYERS::showCopperChoice( int copperCount )
  216. {
  217. if( copperCount > MAX_CU_LAYERS )
  218. copperCount = MAX_CU_LAYERS;
  219. if( copperCount < 2 )
  220. copperCount = 2;
  221. for( int lyrCnt = 2; lyrCnt <= MAX_CU_LAYERS; lyrCnt += 2 )
  222. {
  223. // note this will change a one layer board to 2:
  224. if( copperCount <= lyrCnt )
  225. {
  226. int idx = lyrCnt/2 - 1;
  227. m_CopperLayersChoice->SetSelection(idx);
  228. break;
  229. }
  230. }
  231. }
  232. void PANEL_SETUP_LAYERS::showBoardLayerNames()
  233. {
  234. // Set all the board's layer names into the dialog by calling BOARD::GetLayerName(),
  235. // which will call BOARD::GetStandardLayerName() for non-coppers.
  236. for( LSEQ seq = dlg_layers(); seq; ++seq )
  237. {
  238. PCB_LAYER_ID layer = *seq;
  239. wxControl* ctl = getName( layer );
  240. if( ctl )
  241. {
  242. wxString lname = m_pcb->GetLayerName( layer );
  243. if( dynamic_cast<wxTextCtrl*>( ctl ) )
  244. dynamic_cast<wxTextCtrl*>( ctl )->SetValue( lname ); // wxTextCtrl
  245. else
  246. ctl->SetLabel( lname ); // wxStaticText
  247. }
  248. }
  249. }
  250. void PANEL_SETUP_LAYERS::showSelectedLayerCheckBoxes( LSET enabledLayers )
  251. {
  252. // the check boxes
  253. for( LSEQ seq = dlg_layers(); seq; ++seq )
  254. {
  255. PCB_LAYER_ID layer = *seq;
  256. setLayerCheckBox( layer, enabledLayers[layer] );
  257. }
  258. }
  259. void PANEL_SETUP_LAYERS::showPresets( LSET enabledLayers )
  260. {
  261. int presetsNdx = 0; // the "Custom" setting, matches nothing
  262. for( unsigned i=1; i<DIM( presets ); ++i )
  263. {
  264. if( enabledLayers == presets[i] )
  265. {
  266. presetsNdx = i;
  267. break;
  268. }
  269. }
  270. m_PresetsChoice->SetSelection( presetsNdx );
  271. }
  272. void PANEL_SETUP_LAYERS::showLayerTypes()
  273. {
  274. for( LSEQ seq = LSET::AllCuMask().Seq(); seq; ++seq )
  275. {
  276. PCB_LAYER_ID cu_layer = *seq;
  277. wxChoice* ctl = getChoice( cu_layer );
  278. ctl->SetSelection( m_pcb->GetLayerType( cu_layer ) );
  279. }
  280. }
  281. LSET PANEL_SETUP_LAYERS::getUILayerMask()
  282. {
  283. LSET layerMaskResult;
  284. for( LSEQ seq = dlg_layers(); seq; ++seq )
  285. {
  286. PCB_LAYER_ID layer = *seq;
  287. wxCheckBox* ctl = getCheckBox( layer );
  288. if( ctl->GetValue() )
  289. layerMaskResult.set( layer );
  290. }
  291. return layerMaskResult;
  292. }
  293. void PANEL_SETUP_LAYERS::setLayerCheckBox( LAYER_NUM aLayer, bool isChecked )
  294. {
  295. PANEL_SETUP_LAYERS_CTLs ctl = getCTLs( aLayer );
  296. ctl.checkbox->SetValue( isChecked );
  297. ctl.name->Enable( isChecked );
  298. ctl.choice->Enable( isChecked );
  299. }
  300. void PANEL_SETUP_LAYERS::setCopperLayerCheckBoxes( int copperCount )
  301. {
  302. if( copperCount > 0 )
  303. {
  304. setLayerCheckBox( F_Cu, true );
  305. --copperCount;
  306. }
  307. if( copperCount > 0 )
  308. {
  309. setLayerCheckBox( B_Cu, true );
  310. --copperCount;
  311. }
  312. for( LSEQ seq = LSET::InternalCuMask().Seq(); seq; ++seq, --copperCount )
  313. {
  314. PCB_LAYER_ID layer = *seq;
  315. bool state = copperCount > 0;
  316. #ifdef HIDE_INACTIVE_LAYERS
  317. // This code hides non-active copper layers, or redisplays hidden
  318. // layers which are now needed.
  319. PANEL_SETUP_LAYERS_CTLs ctl = getCTLs( layer );
  320. ctl.name->Show( state );
  321. ctl.checkbox->Show( state );
  322. ctl.choice->Show( state );
  323. #endif
  324. setLayerCheckBox( layer, state );
  325. }
  326. #ifdef HIDE_INACTIVE_LAYERS
  327. // Send an size event to force sizers to be updated,
  328. // because the number of copper layers can have changed.
  329. wxSizeEvent evt_size( m_LayersListPanel->GetSize() );
  330. m_LayersListPanel->GetEventHandler()->ProcessEvent( evt_size );
  331. #endif
  332. }
  333. void PANEL_SETUP_LAYERS::OnCheckBox( wxCommandEvent& event )
  334. {
  335. for( LSEQ seq = dlg_layers(); seq; ++seq )
  336. {
  337. PANEL_SETUP_LAYERS_CTLs ctl = getCTLs( *seq );
  338. ctl.name->Enable( ctl.checkbox->GetValue() );
  339. ctl.choice->Enable( ctl.checkbox->GetValue() );
  340. }
  341. m_enabledLayers = getUILayerMask();
  342. showPresets( m_enabledLayers );
  343. }
  344. void PANEL_SETUP_LAYERS::DenyChangeCheckBox( wxCommandEvent& event )
  345. {
  346. wxObject* source = event.GetEventObject();
  347. wxString msg;
  348. for( LSEQ seq = LSET::AllCuMask().Seq(); seq; ++seq )
  349. {
  350. wxCheckBox* copper = getCheckBox( *seq );
  351. if( source == copper )
  352. {
  353. wxString controlLabel = m_staticTextCopperLayers->GetLabel();
  354. // knock the ':' off the end
  355. controlLabel = controlLabel.substr( 0, controlLabel.size() - 1 );
  356. msg.Printf( _( "Use the \"%s\" control to change the number of copper layers." ),
  357. controlLabel );
  358. DisplayError( this, msg );
  359. copper->SetValue( true );
  360. return;
  361. }
  362. }
  363. for( int layer : { F_CrtYd, B_CrtYd, Edge_Cuts, Margin } )
  364. {
  365. wxCheckBox* mandatory = getCheckBox( layer );
  366. if( source == mandatory )
  367. {
  368. msg.Printf( _( "The %s layer is mandatory." ), getLayerName( layer ) );
  369. DisplayError( this, msg );
  370. mandatory->SetValue( true );
  371. return;
  372. }
  373. }
  374. }
  375. void PANEL_SETUP_LAYERS::OnPresetsChoice( wxCommandEvent& event )
  376. {
  377. int presetNdx = m_PresetsChoice->GetCurrentSelection();
  378. if( presetNdx <= 0 ) // the Custom setting controls nothing.
  379. return;
  380. if( presetNdx < (int) DIM(presets) )
  381. {
  382. m_enabledLayers = presets[ presetNdx ];
  383. LSET copperSet = m_enabledLayers & LSET::AllCuMask();
  384. int copperCount = copperSet.count();
  385. showCopperChoice( copperCount );
  386. showSelectedLayerCheckBoxes( m_enabledLayers );
  387. setCopperLayerCheckBoxes( copperCount );
  388. }
  389. // Ensure mandatory layers are activated
  390. setMandatoryLayerCheckBoxes();
  391. }
  392. void PANEL_SETUP_LAYERS::OnCopperLayersChoice( wxCommandEvent& event )
  393. {
  394. setCopperLayerCheckBoxes( m_CopperLayersChoice->GetCurrentSelection() * 2 + 2 );
  395. m_enabledLayers = getUILayerMask();
  396. showPresets( m_enabledLayers );
  397. }
  398. bool PANEL_SETUP_LAYERS::TransferDataFromWindow()
  399. {
  400. if( !m_pcbThickness.Validate( true ) )
  401. return false;
  402. if( !testLayerNames() )
  403. return false;
  404. wxString msg;
  405. int thickness = m_pcbThickness.GetValue();
  406. // Check for removed layers with items which will get deleted from the board.
  407. LSEQ removedLayers = getRemovedLayersWithItems();
  408. // Check for non copper layers in use in footprints, and therefore not removable.
  409. LSEQ notremovableLayers = getNonRemovableLayers();
  410. if( !notremovableLayers.empty() )
  411. {
  412. for( unsigned int ii = 0; ii < notremovableLayers.size(); ii++ )
  413. msg << m_pcb->GetLayerName( notremovableLayers[ii] ) << "\n";
  414. if( !IsOK( this, wxString::Format( _( "Footprints have some items on removed layers:\n"
  415. "%s\n"
  416. "These items will be no longer accessible\n"
  417. "Do you wish to continue?" ), msg ) ) )
  418. return false;
  419. }
  420. if( !removedLayers.empty() &&
  421. !IsOK( this, _( "Items have been found on removed layers. This operation will delete "
  422. "all items from removed layers and cannot be undone. Do you wish to "
  423. "continue?" ) ) )
  424. return false;
  425. // Delete all objects on layers that have been removed. Leaving them in copper layers
  426. // can (will?) result in DRC errors and it pollutes the board file with cruft.
  427. bool hasRemovedBoardItems = false;
  428. if( !removedLayers.empty() )
  429. {
  430. PCB_LAYER_COLLECTOR collector;
  431. for( auto layer_id : removedLayers )
  432. {
  433. collector.SetLayerId( layer_id );
  434. collector.Collect( m_pcb, GENERAL_COLLECTOR::BoardLevelItems );
  435. // Bye-bye items on on removed layer.
  436. if( collector.GetCount() != 0 )
  437. {
  438. hasRemovedBoardItems = true;
  439. for( int i = 0; i < collector.GetCount(); i++ )
  440. {
  441. BOARD_ITEM* item = collector[i];
  442. m_pcb->Remove( item );
  443. delete item;
  444. }
  445. }
  446. }
  447. }
  448. m_enabledLayers = getUILayerMask();
  449. if( m_enabledLayers != m_pcb->GetEnabledLayers() )
  450. {
  451. m_pcb->SetEnabledLayers( m_enabledLayers );
  452. /* Ensure enabled layers are also visible
  453. * This is mainly to avoid mistakes if some enabled
  454. * layers are not visible when exiting this dialog
  455. */
  456. m_pcb->SetVisibleLayers( m_enabledLayers );
  457. }
  458. for( LSEQ seq = LSET::AllCuMask().Seq(); seq; ++seq )
  459. {
  460. PCB_LAYER_ID layer = *seq;
  461. if( m_enabledLayers[layer] )
  462. {
  463. m_pcb->SetLayerName( layer, getLayerName( layer ) );
  464. LAYER_T t = (LAYER_T) getLayerTypeIndex( layer );
  465. m_pcb->SetLayerType( layer, t );
  466. }
  467. }
  468. m_pcb->GetDesignSettings().SetBoardThickness( thickness );
  469. // If some board items are deleted: rebuild the connectivity,
  470. // because it is likely some tracks and vias where removed
  471. if( hasRemovedBoardItems )
  472. {
  473. PCB_EDIT_FRAME* editFrame = static_cast<PCB_EDIT_FRAME*>( GetParent() );
  474. // Rebuild list of nets (full ratsnest rebuild)
  475. editFrame->Compile_Ratsnest( NULL, true );
  476. m_pcb->BuildConnectivity();
  477. }
  478. return true;
  479. }
  480. int PANEL_SETUP_LAYERS::getLayerTypeIndex( LAYER_NUM aLayer )
  481. {
  482. wxChoice* ctl = getChoice( aLayer );
  483. int ret = ctl->GetCurrentSelection(); // indices must have same sequence as LAYER_T
  484. return ret;
  485. }
  486. wxString PANEL_SETUP_LAYERS::getLayerName( LAYER_NUM aLayer )
  487. {
  488. wxControl* control = getName( aLayer );
  489. if( dynamic_cast<wxTextCtrl*>( control ) )
  490. return dynamic_cast<wxTextCtrl*>( control )->GetValue().Trim();
  491. else
  492. return dynamic_cast<wxStaticText*>( control )->GetLabel();
  493. }
  494. static bool hasOneOf( const wxString& str, const wxString& chars )
  495. {
  496. for( unsigned i=0; i<chars.Len(); ++i )
  497. {
  498. if( str.Find( chars[i] ) != wxNOT_FOUND )
  499. return true;
  500. }
  501. return false;
  502. }
  503. bool PANEL_SETUP_LAYERS::testLayerNames()
  504. {
  505. std::vector<wxString> names;
  506. wxTextCtrl* ctl;
  507. for( LSEQ seq = LSET::AllCuMask().Seq(); seq; ++seq )
  508. {
  509. PCB_LAYER_ID layer = *seq;
  510. // we _can_ rely on m_enabledLayers being current here:
  511. if( !m_enabledLayers[layer] )
  512. continue;
  513. wxString name = getLayerName( layer );
  514. ctl = (wxTextCtrl*) getName( layer );
  515. // check name for legality.
  516. // 1) cannot be blank.
  517. // 2) cannot have blanks.
  518. // 3) cannot have " chars
  519. // 4) cannot be 'signal'
  520. // 5) must be unique.
  521. // 6) cannot have illegal chars in filenames ( some filenames are built from layer names )
  522. // like : % $ \ " / :
  523. wxString badchars = wxFileName::GetForbiddenChars( wxPATH_DOS );
  524. badchars.Append( '%' );
  525. if( !name )
  526. {
  527. m_Parent->SetError( _( "Layer must have a name." ), this, ctl );
  528. return false;
  529. }
  530. if( hasOneOf( name, badchars ) )
  531. {
  532. auto msg = wxString::Format(_( "\"%s\" are forbidden in layer names." ), badchars );
  533. m_Parent->SetError( msg, this, ctl );
  534. return false;
  535. }
  536. if( name == wxT( "signal" ) )
  537. {
  538. m_Parent->SetError( _( "Layer name \"signal\" is reserved." ), this, ctl );
  539. return false;
  540. }
  541. for( const wxString& existingName : names )
  542. {
  543. if( name == existingName )
  544. {
  545. auto msg = wxString::Format(_( "Layer name \"%s\" is already in use." ), name );
  546. m_Parent->SetError( msg, this, ctl );
  547. return false;
  548. }
  549. }
  550. names.push_back( name );
  551. }
  552. return true;
  553. }
  554. LSEQ PANEL_SETUP_LAYERS::getRemovedLayersWithItems()
  555. {
  556. LSEQ removedLayers;
  557. LSET newLayers = getUILayerMask();
  558. LSET curLayers = m_pcb->GetEnabledLayers();
  559. if( newLayers == curLayers ) // return a empty list if no change
  560. return removedLayers;
  561. PCB_LAYER_COLLECTOR collector;
  562. LSEQ newLayerSeq = newLayers.Seq();
  563. std::vector< PCB_LAYER_ID >::iterator it;
  564. for( auto layer_id : curLayers.Seq() )
  565. {
  566. if( std::find( newLayerSeq.begin(), newLayerSeq.end(), layer_id ) == newLayerSeq.end() )
  567. {
  568. collector.SetLayerId( layer_id );
  569. collector.Collect( m_pcb, GENERAL_COLLECTOR::BoardLevelItems );
  570. if( collector.GetCount() != 0 )
  571. removedLayers.push_back( layer_id );
  572. }
  573. }
  574. return removedLayers;
  575. }
  576. LSEQ PANEL_SETUP_LAYERS::getNonRemovableLayers()
  577. {
  578. //Build the list of non copper layers in use in footprints.
  579. LSEQ inUseLayers;
  580. LSET newLayers = getUILayerMask();
  581. LSET curLayers = m_pcb->GetEnabledLayers();
  582. if( newLayers == curLayers ) // return a empty list if no change
  583. return inUseLayers;
  584. PCB_LAYER_COLLECTOR collector;
  585. LSEQ newLayerSeq = newLayers.Seq();
  586. std::vector< PCB_LAYER_ID >::iterator it;
  587. for( auto layer_id : curLayers.Seq() )
  588. {
  589. if( IsCopperLayer( layer_id ) ) // Copper layers are not taken in account here
  590. continue;
  591. if( std::find( newLayerSeq.begin(), newLayerSeq.end(), layer_id ) == newLayerSeq.end() )
  592. {
  593. collector.SetLayerId( layer_id );
  594. collector.Collect( m_pcb, GENERAL_COLLECTOR::ModuleItems );
  595. if( collector.GetCount() != 0 )
  596. inUseLayers.push_back( layer_id );
  597. }
  598. }
  599. return inUseLayers;
  600. }
  601. void PANEL_SETUP_LAYERS::ImportSettingsFrom( BOARD* aBoard )
  602. {
  603. BOARD* savedBoard = m_pcb;
  604. m_pcb = aBoard;
  605. TransferDataToWindow();
  606. m_pcb = savedBoard;
  607. }