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.

831 lines
23 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 <invoke_pcb_dialog.h>
  30. #include <class_board.h>
  31. #include <collectors.h>
  32. #include <dialog_layers_setup_base.h>
  33. // some define to choose how copper layers widgets are shown
  34. // if defined, display only active copper layers
  35. // if not displays always 1=the full set (32 copper layers)
  36. #define HIDE_INACTIVE_LAYERS
  37. // if defined, use the layer manager copper layers order (from FRONT to BACK)
  38. // to display inner layers.
  39. // if not, use the default order (from BACK to FRONT)
  40. #define USE_LAYER_MANAGER_COPPER_LAYERS_ORDER
  41. /**
  42. * Holds the 3 UI control pointers for a single board layer.
  43. */
  44. struct CTLs
  45. {
  46. CTLs( wxControl* aName, wxCheckBox* aCheckBox, wxControl* aChoiceOrDesc,
  47. wxPanel* aPanel = NULL )
  48. {
  49. name = aName;
  50. checkbox = aCheckBox;
  51. choice = aChoiceOrDesc;
  52. panel = aPanel;
  53. }
  54. wxControl* name;
  55. wxCheckBox* checkbox;
  56. wxControl* choice;
  57. wxPanel * panel;
  58. };
  59. static LSEQ dlg_layers()
  60. {
  61. // layers that are put out into the dialog UI, coordinate with wxformbuilder and
  62. // getCTLs( LAYER_NUM aLayerNumber )
  63. static const PCB_LAYER_ID layers[] = {
  64. F_CrtYd,
  65. F_Fab,
  66. F_Adhes,
  67. F_Paste,
  68. F_SilkS,
  69. F_Mask,
  70. F_Cu,
  71. In1_Cu,
  72. In2_Cu,
  73. In3_Cu,
  74. In4_Cu,
  75. In5_Cu,
  76. In6_Cu,
  77. In7_Cu,
  78. In8_Cu,
  79. In9_Cu,
  80. In10_Cu,
  81. In11_Cu,
  82. In12_Cu,
  83. In13_Cu,
  84. In14_Cu,
  85. In15_Cu,
  86. In16_Cu,
  87. In17_Cu,
  88. In18_Cu,
  89. In19_Cu,
  90. In20_Cu,
  91. In21_Cu,
  92. In22_Cu,
  93. In23_Cu,
  94. In24_Cu,
  95. In25_Cu,
  96. In26_Cu,
  97. In27_Cu,
  98. In28_Cu,
  99. In29_Cu,
  100. In30_Cu,
  101. B_Cu,
  102. B_Mask,
  103. B_SilkS,
  104. B_Paste,
  105. B_Adhes,
  106. B_Fab,
  107. B_CrtYd,
  108. Edge_Cuts,
  109. Margin,
  110. Eco2_User,
  111. Eco1_User,
  112. Cmts_User,
  113. Dwgs_User,
  114. };
  115. return LSEQ( layers, layers + DIM( layers ) );
  116. }
  117. class DIALOG_LAYERS_SETUP : public DIALOG_LAYERS_SETUP_BASE
  118. {
  119. public:
  120. DIALOG_LAYERS_SETUP( wxTopLevelWindow* aCaller, BOARD* aBoard );
  121. private:
  122. int m_copperLayerCount;
  123. LSET m_enabledLayers;
  124. BOARD* m_pcb;
  125. wxStaticText* m_nameStaticText;
  126. wxStaticText* m_enabledStaticText;
  127. wxStaticText* m_typeStaticText;
  128. void setLayerCheckBox( LAYER_NUM layer, bool isChecked );
  129. void setCopperLayerCheckBoxes( int copperCount );
  130. void showCopperChoice( int copperCount );
  131. void showBoardLayerNames();
  132. void showSelectedLayerCheckBoxes( LSET enableLayerMask );
  133. void showLayerTypes();
  134. void showPresets( LSET enabledLayerMask );
  135. /** Return the selected layer mask within the UI checkboxes */
  136. LSET getUILayerMask();
  137. wxString getLayerName( LAYER_NUM layer );
  138. int getLayerTypeIndex( LAYER_NUM layer );
  139. void OnInitDialog( wxInitDialogEvent& aEvent ) override;
  140. void OnCheckBox( wxCommandEvent& event ) override;
  141. void DenyChangeCheckBox( wxCommandEvent& event ) override;
  142. void OnPresetsChoice( wxCommandEvent& event ) override;
  143. void OnCopperLayersChoice( wxCommandEvent& event ) override;
  144. bool TransferDataToWindow() override;
  145. bool TransferDataFromWindow() override;
  146. bool testLayerNames();
  147. /**
  148. * Return a list of layers removed from the board that contain items.
  149. */
  150. LSEQ getRemovedLayersWithItems();
  151. /**
  152. * Map \a aLayerNumber to the wx IDs for that layer which are
  153. * the layer name control ID, checkbox control ID, and choice control ID
  154. */
  155. CTLs getCTLs( LAYER_NUM aLayerNumber );
  156. wxControl* getName( LAYER_NUM aLayer )
  157. {
  158. return getCTLs( aLayer ).name;
  159. }
  160. wxCheckBox* getCheckBox( LAYER_NUM aLayer )
  161. {
  162. return getCTLs( aLayer ).checkbox;
  163. }
  164. wxChoice* getChoice( LAYER_NUM aLayer )
  165. {
  166. return (wxChoice*) getCTLs( aLayer ).choice;
  167. }
  168. void moveTitles()
  169. {
  170. wxArrayInt widths = m_LayerListFlexGridSizer->GetColWidths();
  171. int offset = 0;
  172. wxSize txtz;
  173. wxSize panel_sz = m_TitlePanel->GetSize();
  174. int voffset = panel_sz.y/2 - VertPixelsFromDU( 4 );
  175. txtz = m_nameStaticText->GetSize();
  176. m_nameStaticText->Move( offset + (widths[0] - txtz.x)/2, voffset );
  177. offset += widths[0];
  178. txtz = m_enabledStaticText->GetSize();
  179. m_enabledStaticText->Move( offset + (widths[1] - txtz.x)/2, voffset );
  180. offset += widths[1];
  181. txtz = m_typeStaticText->GetSize();
  182. m_typeStaticText->Move( offset + (widths[2] - txtz.x)/2, voffset );
  183. }
  184. void OnSize( wxSizeEvent& event ) override;
  185. };
  186. // Layer bit masks for each defined "Preset Layer Grouping"
  187. static const LSET presets[] =
  188. {
  189. LSET(), // shift the array index up by one, matches with "Custom".
  190. // "Two layers, parts on Front only"
  191. LSET( 2, F_Cu, B_Cu ) | LSET::FrontTechMask() | LSET::UserMask(),
  192. // "Two layers, parts on Back only",
  193. LSET( 2, F_Cu, B_Cu ) | LSET::BackTechMask() | LSET::UserMask(),
  194. // "Two layers, parts on Front and Back",
  195. LSET( 2, F_Cu, B_Cu ) | LSET::FrontTechMask() | LSET::BackTechMask() | LSET::UserMask(),
  196. // "Four layers, parts on Front only"
  197. LSET( 4, F_Cu, B_Cu, In1_Cu, In2_Cu ) | LSET::FrontTechMask() | LSET::UserMask(),
  198. // "Four layers, parts on Front and Back"
  199. LSET( 4, F_Cu, B_Cu, In1_Cu, In2_Cu ) | LSET::FrontTechMask() | LSET::BackTechMask() |
  200. LSET::UserMask(),
  201. // "All layers on",
  202. LSET().set(),
  203. };
  204. CTLs DIALOG_LAYERS_SETUP::getCTLs( LAYER_NUM aLayerNumber )
  205. {
  206. #define RETCOP(x) return CTLs( x##Name, x##CheckBox, x##Choice, x##Panel );
  207. #define RETAUX(x) return CTLs( x##Name, x##CheckBox, x##StaticText, x##Panel );
  208. switch( aLayerNumber )
  209. {
  210. case F_CrtYd: RETAUX( m_CrtYdFront );
  211. case F_Fab: RETAUX( m_FabFront );
  212. case F_Adhes: RETAUX( m_AdhesFront );
  213. case F_Paste: RETAUX( m_SoldPFront );
  214. case F_SilkS: RETAUX( m_SilkSFront );
  215. case F_Mask: RETAUX( m_MaskFront );
  216. case F_Cu: RETCOP( m_Front );
  217. case In1_Cu: RETCOP( m_In1 );
  218. case In2_Cu: RETCOP( m_In2 );
  219. case In3_Cu: RETCOP( m_In3 );
  220. case In4_Cu: RETCOP( m_In4 );
  221. case In5_Cu: RETCOP( m_In5 );
  222. case In6_Cu: RETCOP( m_In6 );
  223. case In7_Cu: RETCOP( m_In7 );
  224. case In8_Cu: RETCOP( m_In8 );
  225. case In9_Cu: RETCOP( m_In9 );
  226. case In10_Cu: RETCOP( m_In10 );
  227. case In11_Cu: RETCOP( m_In11 );
  228. case In12_Cu: RETCOP( m_In12 );
  229. case In13_Cu: RETCOP( m_In13 );
  230. case In14_Cu: RETCOP( m_In14 );
  231. case In15_Cu: RETCOP( m_In15 );
  232. case In16_Cu: RETCOP( m_In16 );
  233. case In17_Cu: RETCOP( m_In17 );
  234. case In18_Cu: RETCOP( m_In18 );
  235. case In19_Cu: RETCOP( m_In19 );
  236. case In20_Cu: RETCOP( m_In20 );
  237. case In21_Cu: RETCOP( m_In21 );
  238. case In22_Cu: RETCOP( m_In22 );
  239. case In23_Cu: RETCOP( m_In23 );
  240. case In24_Cu: RETCOP( m_In24 );
  241. case In25_Cu: RETCOP( m_In25 );
  242. case In26_Cu: RETCOP( m_In26 );
  243. case In27_Cu: RETCOP( m_In27 );
  244. case In28_Cu: RETCOP( m_In28 );
  245. case In29_Cu: RETCOP( m_In29 );
  246. case In30_Cu: RETCOP( m_In30 );
  247. case B_Cu: RETCOP( m_Back );
  248. case B_Mask: RETAUX( m_MaskBack );
  249. case B_SilkS: RETAUX( m_SilkSBack );
  250. case B_Paste: RETAUX( m_SoldPBack );
  251. case B_Adhes: RETAUX( m_AdhesBack );
  252. case B_Fab: RETAUX( m_FabBack );
  253. case B_CrtYd: RETAUX( m_CrtYdBack );
  254. case Edge_Cuts: RETAUX( m_PCBEdges );
  255. case Margin: RETAUX( m_Margin );
  256. case Eco2_User: RETAUX( m_Eco2 );
  257. case Eco1_User: RETAUX( m_Eco1 );
  258. case Cmts_User: RETAUX( m_Comments );
  259. case Dwgs_User: RETAUX( m_Drawings );
  260. default:
  261. wxASSERT_MSG( 0, wxT( "bad layer id" ) );
  262. return CTLs( 0, 0, 0 );
  263. }
  264. #undef RETCOP
  265. #undef RETAUX
  266. }
  267. DIALOG_LAYERS_SETUP::DIALOG_LAYERS_SETUP( wxTopLevelWindow* aParent, BOARD* aBoard ) :
  268. DIALOG_LAYERS_SETUP_BASE( aParent )
  269. {
  270. m_pcb = aBoard;
  271. m_copperLayerCount = m_pcb->GetCopperLayerCount();
  272. m_enabledLayers = m_pcb->GetEnabledLayers();
  273. SetAutoLayout( true );
  274. // these 3 controls are handled outside wxformbuilder so that we can add
  275. // them without a sizer. Then we position them manually based on the column
  276. // widths from m_LayerListFlexGridSizer->GetColWidths()
  277. m_nameStaticText = new wxStaticText( m_TitlePanel, wxID_ANY, _( "Name" ),
  278. wxDefaultPosition, wxDefaultSize, 0 );
  279. m_enabledStaticText = new wxStaticText( m_TitlePanel, wxID_ANY, _( "Enabled" ),
  280. wxDefaultPosition, wxDefaultSize, 0 );
  281. m_typeStaticText = new wxStaticText( m_TitlePanel, wxID_ANY, _( "Type" ),
  282. wxDefaultPosition, wxDefaultSize, 0 );
  283. }
  284. void DIALOG_LAYERS_SETUP::OnInitDialog( wxInitDialogEvent& aEvent )
  285. {
  286. wxWindowBase::OnInitDialog( aEvent );
  287. m_TitlePanel->SetMinSize( wxSize( -1, VertPixelsFromDU( 10 ) ) );
  288. m_LayersListPanel->ShowScrollbars( wxSHOW_SB_ALWAYS, wxSHOW_SB_ALWAYS );
  289. Layout();
  290. SetSizeInDU( 240, 240 );
  291. Center();
  292. m_sdbSizerOK->SetFocus();
  293. m_sdbSizerOK->SetDefault();
  294. // OnSize() will fix the title spacing.
  295. QueueEvent( new wxSizeEvent( GetSize() ) );
  296. }
  297. bool DIALOG_LAYERS_SETUP::TransferDataToWindow()
  298. {
  299. if( !wxDialog::TransferDataToWindow() )
  300. return false;
  301. showCopperChoice( m_copperLayerCount );
  302. setCopperLayerCheckBoxes( m_copperLayerCount );
  303. m_staticTextBrdThicknessUnit->SetLabel( GetAbbreviatedUnitsLabel( g_UserUnit ) );
  304. PutValueInLocalUnits( *m_textCtrlBrdThickness,
  305. m_pcb->GetDesignSettings().GetBoardThickness() );
  306. showBoardLayerNames();
  307. showSelectedLayerCheckBoxes( m_enabledLayers );
  308. showPresets( m_enabledLayers );
  309. showLayerTypes();
  310. // All widgets are now initialized. Fix the min sizes:
  311. GetSizer()->SetSizeHints( this );
  312. return true;
  313. }
  314. void DIALOG_LAYERS_SETUP::OnSize( wxSizeEvent& event )
  315. {
  316. moveTitles();
  317. event.Skip();
  318. }
  319. void DIALOG_LAYERS_SETUP::showCopperChoice( int copperCount )
  320. {
  321. if( copperCount > MAX_CU_LAYERS )
  322. copperCount = MAX_CU_LAYERS;
  323. if( copperCount < 2 )
  324. copperCount = 2;
  325. for( int lyrCnt = 2; lyrCnt <= MAX_CU_LAYERS; lyrCnt += 2 )
  326. {
  327. // note this will change a one layer board to 2:
  328. if( copperCount <= lyrCnt )
  329. {
  330. int idx = lyrCnt/2 - 1;
  331. m_CopperLayersChoice->SetSelection(idx);
  332. break;
  333. }
  334. }
  335. }
  336. void DIALOG_LAYERS_SETUP::showBoardLayerNames()
  337. {
  338. // Establish all the board's layer names into the dialog presentation, by
  339. // obtaining them from BOARD::GetLayerName() which calls
  340. // BOARD::GetStandardLayerName() for non-coppers.
  341. for( LSEQ seq = dlg_layers(); seq; ++seq )
  342. {
  343. PCB_LAYER_ID layer = *seq;
  344. wxControl* ctl = getName( layer );
  345. wxASSERT( ctl );
  346. if( ctl )
  347. {
  348. wxString lname = m_pcb->GetLayerName( layer );
  349. if( ctl->IsKindOf( CLASSINFO( wxTextCtrl ) ) )
  350. ((wxTextCtrl*)ctl)->SetValue( lname ); // wxTextCtrl
  351. else
  352. ctl->SetLabel( lname ); // wxStaticText
  353. }
  354. }
  355. }
  356. void DIALOG_LAYERS_SETUP::showSelectedLayerCheckBoxes( LSET enabledLayers )
  357. {
  358. // the check boxes
  359. for( LSEQ seq = dlg_layers(); seq; ++seq )
  360. {
  361. PCB_LAYER_ID layer = *seq;
  362. setLayerCheckBox( layer, enabledLayers[layer] );
  363. }
  364. }
  365. void DIALOG_LAYERS_SETUP::showPresets( LSET enabledLayers )
  366. {
  367. int presetsNdx = 0; // the "Custom" setting, matches nothing
  368. for( unsigned i=1; i<DIM( presets ); ++i )
  369. {
  370. if( enabledLayers == presets[i] )
  371. {
  372. presetsNdx = i;
  373. break;
  374. }
  375. }
  376. m_PresetsChoice->SetSelection( presetsNdx );
  377. }
  378. void DIALOG_LAYERS_SETUP::showLayerTypes()
  379. {
  380. for( LSEQ seq = LSET::AllCuMask().Seq(); seq; ++seq )
  381. {
  382. PCB_LAYER_ID cu_layer = *seq;
  383. wxChoice* ctl = getChoice( cu_layer );
  384. ctl->SetSelection( m_pcb->GetLayerType( cu_layer ) );
  385. }
  386. }
  387. LSET DIALOG_LAYERS_SETUP::getUILayerMask()
  388. {
  389. LSET layerMaskResult;
  390. for( LSEQ seq = dlg_layers(); seq; ++seq )
  391. {
  392. PCB_LAYER_ID layer = *seq;
  393. wxCheckBox* ctl = getCheckBox( layer );
  394. if( ctl->GetValue() )
  395. {
  396. layerMaskResult.set( layer );
  397. }
  398. }
  399. return layerMaskResult;
  400. }
  401. void DIALOG_LAYERS_SETUP::setLayerCheckBox( LAYER_NUM aLayer, bool isChecked )
  402. {
  403. wxCheckBox* ctl = getCheckBox( aLayer );
  404. ctl->SetValue( isChecked );
  405. }
  406. void DIALOG_LAYERS_SETUP::setCopperLayerCheckBoxes( int copperCount )
  407. {
  408. if( copperCount > 0 )
  409. {
  410. setLayerCheckBox( F_Cu, true );
  411. --copperCount;
  412. }
  413. if( copperCount > 0 )
  414. {
  415. setLayerCheckBox( B_Cu, true );
  416. --copperCount;
  417. }
  418. for( LSEQ seq = LSET::InternalCuMask().Seq(); seq; ++seq, --copperCount )
  419. {
  420. PCB_LAYER_ID layer = *seq;
  421. bool state = copperCount > 0;
  422. #ifdef HIDE_INACTIVE_LAYERS
  423. // This code hides non-active copper layers, or redisplays hidden
  424. // layers which are now needed.
  425. CTLs ctl = getCTLs( layer );
  426. ctl.name->Show( state );
  427. ctl.checkbox->Show( state );
  428. ctl.choice->Show( state );
  429. if( ctl.panel )
  430. ctl.panel->Show( state );
  431. #endif
  432. setLayerCheckBox( layer, state );
  433. }
  434. #ifdef HIDE_INACTIVE_LAYERS
  435. // Send an size event to force sizers to be updated,
  436. // because the number of copper layers can have changed.
  437. wxSizeEvent evt_size( m_LayersListPanel->GetSize() );
  438. m_LayersListPanel->GetEventHandler()->ProcessEvent( evt_size );
  439. #endif
  440. }
  441. void DIALOG_LAYERS_SETUP::OnCheckBox( wxCommandEvent& event )
  442. {
  443. m_enabledLayers = getUILayerMask();
  444. showPresets( m_enabledLayers );
  445. }
  446. void DIALOG_LAYERS_SETUP::DenyChangeCheckBox( wxCommandEvent& event )
  447. {
  448. // user may not change copper layer checkboxes from anything other than
  449. // either presets choice or the copper layer choice controls.
  450. // I tried to simply disable the copper CheckBoxes but they look like crap,
  451. // so leave them enabled and reverse the user's attempt to toggle them.
  452. setCopperLayerCheckBoxes( m_copperLayerCount );
  453. }
  454. void DIALOG_LAYERS_SETUP::OnPresetsChoice( wxCommandEvent& event )
  455. {
  456. unsigned presetNdx = m_PresetsChoice->GetCurrentSelection();
  457. if( presetNdx == 0 ) // the Custom setting controls nothing.
  458. return;
  459. if( presetNdx < DIM(presets) )
  460. {
  461. m_enabledLayers = presets[ presetNdx ];
  462. LSET copperSet = m_enabledLayers & LSET::AllCuMask();
  463. int copperCount = copperSet.count();
  464. m_copperLayerCount = copperCount;
  465. showCopperChoice( m_copperLayerCount );
  466. showSelectedLayerCheckBoxes( m_enabledLayers );
  467. setCopperLayerCheckBoxes( m_copperLayerCount );
  468. }
  469. }
  470. void DIALOG_LAYERS_SETUP::OnCopperLayersChoice( wxCommandEvent& event )
  471. {
  472. m_copperLayerCount = m_CopperLayersChoice->GetCurrentSelection() * 2 + 2;
  473. setCopperLayerCheckBoxes( m_copperLayerCount );
  474. m_enabledLayers = getUILayerMask();
  475. showPresets( m_enabledLayers );
  476. }
  477. bool DIALOG_LAYERS_SETUP::TransferDataFromWindow()
  478. {
  479. if( !wxWindow::TransferDataFromWindow() || !testLayerNames() )
  480. return false;
  481. wxString msg;
  482. // Make sure the board thickness is sane.
  483. int thickness = ValueFromTextCtrl( *m_textCtrlBrdThickness );
  484. if( thickness < Millimeter2iu( 0.1 ) || thickness > Millimeter2iu( 10.0 ) )
  485. {
  486. msg.Printf( _( "Board thickness %s is out of range." ),
  487. StringFromValue( g_UserUnit, thickness, true ) );
  488. DisplayError( this, msg );
  489. return false;
  490. }
  491. // Check for removed layers with items which will get deleted from the board.
  492. LSEQ removedLayers = getRemovedLayersWithItems();
  493. if( !removedLayers.empty()
  494. && !IsOK( this, _( "Items have been found on removed layers. This operation will delete "
  495. "all items from removed layers and cannot be undone. Do you wish to "
  496. "continue?" ) ) )
  497. return false;
  498. // Delete all objects on layers that have been removed. Leaving them in copper layers
  499. // can (will?) result in DRC errors and it pollutes the board file with cruft.
  500. if( !removedLayers.empty() )
  501. {
  502. PCB_LAYER_COLLECTOR collector;
  503. for( auto layer_id : removedLayers )
  504. {
  505. collector.SetLayerId( layer_id );
  506. collector.Collect( m_pcb, GENERAL_COLLECTOR::BoardLevelItems );
  507. // Bye-bye items on on removed layer.
  508. if( collector.GetCount() != 0 )
  509. {
  510. for( int i = 0; i < collector.GetCount(); i++ )
  511. m_pcb->Remove( collector[i] );
  512. }
  513. }
  514. }
  515. wxString name;
  516. m_enabledLayers = getUILayerMask();
  517. m_pcb->SetEnabledLayers( m_enabledLayers );
  518. /* Ensure enabled layers are also visible
  519. * This is mainly to avoid mistakes if some enabled
  520. * layers are not visible when exiting this dialog
  521. */
  522. m_pcb->SetVisibleLayers( m_enabledLayers );
  523. for( LSEQ seq = LSET::AllCuMask().Seq(); seq; ++seq )
  524. {
  525. PCB_LAYER_ID layer = *seq;
  526. if( m_enabledLayers[layer] )
  527. {
  528. name = getLayerName( layer );
  529. m_pcb->SetLayerName( layer, name );
  530. LAYER_T t = (LAYER_T) getLayerTypeIndex( layer );
  531. m_pcb->SetLayerType( layer, t );
  532. }
  533. }
  534. m_pcb->GetDesignSettings().SetBoardThickness( thickness );
  535. return true;
  536. }
  537. int DIALOG_LAYERS_SETUP::getLayerTypeIndex( LAYER_NUM aLayer )
  538. {
  539. wxChoice* ctl = getChoice( aLayer );
  540. int ret = ctl->GetCurrentSelection(); // indices must have same sequence as LAYER_T
  541. return ret;
  542. }
  543. wxString DIALOG_LAYERS_SETUP::getLayerName( LAYER_NUM aLayer )
  544. {
  545. wxString ret;
  546. wxASSERT( IsCopperLayer( aLayer ) );
  547. wxTextCtrl* ctl = (wxTextCtrl*) getName( aLayer );
  548. ret = ctl->GetValue().Trim();
  549. return ret;
  550. }
  551. static bool hasOneOf( const wxString& str, const wxString& chars )
  552. {
  553. for( unsigned i=0; i<chars.Len(); ++i )
  554. {
  555. if( str.Find( chars[i] ) != wxNOT_FOUND )
  556. return true;
  557. }
  558. return false;
  559. }
  560. bool DIALOG_LAYERS_SETUP::testLayerNames()
  561. {
  562. std::vector<wxString> names;
  563. wxTextCtrl* ctl;
  564. for( LSEQ seq = LSET::AllCuMask().Seq(); seq; ++seq )
  565. {
  566. PCB_LAYER_ID layer = *seq;
  567. // we _can_ rely on m_enabledLayers being current here:
  568. if( !m_enabledLayers[layer] )
  569. continue;
  570. wxString name = getLayerName( layer );
  571. ctl = (wxTextCtrl*) getName( layer );
  572. // check name for legality.
  573. // 1) cannot be blank.
  574. // 2) cannot have blanks.
  575. // 3) cannot have " chars
  576. // 4) cannot be 'signal'
  577. // 5) must be unique.
  578. // 6) cannot have illegal chars in filenames ( some filenames are built from layer names )
  579. // like : % $ \ " / :
  580. wxString badchars = wxFileName::GetForbiddenChars( wxPATH_DOS );
  581. badchars.Append( '%' );
  582. if( !name )
  583. {
  584. DisplayError( this, _( "Layer name may not be empty." ) );
  585. ctl->SetFocus(); // on the bad name
  586. return false;
  587. }
  588. if( hasOneOf( name, badchars ) )
  589. {
  590. DisplayError( this, _( "Layer name has an illegal character, one of: '" ) +
  591. badchars + wxT( "'" ) );
  592. ctl->SetFocus(); // on the bad name
  593. return false;
  594. }
  595. if( name == wxT( "signal" ) )
  596. {
  597. DisplayError( this, _( "Layer name 'signal' is reserved." ) );
  598. ctl->SetFocus(); // on the bad name
  599. return false;
  600. }
  601. for( std::vector<wxString>::iterator it = names.begin(); it != names.end(); ++it )
  602. {
  603. if( name == *it )
  604. {
  605. DisplayError( this, _( "Duplicate layer names are not permitted." ) );
  606. ctl->SetFocus(); // on the bad name
  607. return false;
  608. }
  609. }
  610. names.push_back( name );
  611. }
  612. return true;
  613. }
  614. LSEQ DIALOG_LAYERS_SETUP::getRemovedLayersWithItems()
  615. {
  616. LSEQ removedLayers;
  617. LSET newLayers = getUILayerMask();
  618. LSET curLayers = m_pcb->GetEnabledLayers();
  619. if( newLayers == curLayers )
  620. return removedLayers;
  621. PCB_LAYER_COLLECTOR collector;
  622. LSEQ newLayerSeq = newLayers.Seq();
  623. std::vector< PCB_LAYER_ID >::iterator it;
  624. for( auto layer_id : curLayers.Seq() )
  625. {
  626. if( std::find( newLayerSeq.begin(), newLayerSeq.end(), layer_id ) == newLayerSeq.end() )
  627. {
  628. collector.SetLayerId( layer_id );
  629. collector.Collect( m_pcb, GENERAL_COLLECTOR::BoardLevelItems );
  630. if( collector.GetCount() != 0 )
  631. removedLayers.push_back( layer_id );
  632. }
  633. }
  634. return removedLayers;
  635. }
  636. bool InvokeLayerSetup( wxTopLevelWindow* aCaller, BOARD* aBoard )
  637. {
  638. DIALOG_LAYERS_SETUP dlg( aCaller, aBoard );
  639. return dlg.ShowModal() == wxID_OK;
  640. }