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.

655 lines
18 KiB

16 years ago
16 years ago
16 years ago
16 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 Kicad Developers, see change_log.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 "common.h"
  27. #include "class_drawpanel.h"
  28. #include "confirm.h"
  29. #include "pcbnew.h"
  30. #include "wxPcbStruct.h"
  31. #include "dialog_layers_setup_base.h"
  32. #include "class_board_design_settings.h"
  33. /**
  34. * Struct CTLs
  35. * holds the 3 ui control pointers for a single board layer.
  36. */
  37. struct CTLs
  38. {
  39. CTLs( wxControl* aName, wxCheckBox* aCheckBox, wxControl* aChoiceOrDesc )
  40. {
  41. name = aName;
  42. checkbox = aCheckBox;
  43. choice = aChoiceOrDesc;
  44. }
  45. wxControl* name;
  46. wxCheckBox* checkbox;
  47. wxControl* choice;
  48. };
  49. class DIALOG_LAYERS_SETUP : public DIALOG_LAYERS_SETUP_BASE
  50. {
  51. private:
  52. static wxPoint s_LastPos;
  53. static wxSize s_LastSize;
  54. WinEDA_PcbFrame* m_Parent;
  55. int m_CopperLayerCount;
  56. int m_EnabledLayers;
  57. BOARD* m_Pcb;
  58. wxStaticText* m_NameStaticText;
  59. wxStaticText* m_EnabledStaticText;
  60. wxStaticText* m_TypeStaticText;
  61. void setLayerCheckBox( int layer, bool isChecked );
  62. void setCopperLayerCheckBoxes( int copperCount );
  63. void showCopperChoice( int copperCount );
  64. void showBoardLayerNames();
  65. void showSelectedLayerCheckBoxes( int enableLayerMask );
  66. void showLayerTypes();
  67. void showPresets( int enabledLayerMask );
  68. /** return the selected layer mask within the UI checkboxes */
  69. int getUILayerMask();
  70. wxString getLayerName( int layer );
  71. int getLayerTypeIndex( int layer );
  72. void OnCancelButtonClick( wxCommandEvent& event );
  73. void OnOkButtonClick( wxCommandEvent& event );
  74. void OnCheckBox( wxCommandEvent& event );
  75. void DenyChangeCheckBox( wxCommandEvent& event );
  76. void OnPresetsChoice( wxCommandEvent& event );
  77. void OnCopperLayersChoice( wxCommandEvent& event );
  78. bool testLayerNames();
  79. /**
  80. * Function getCTLs
  81. * maps \a aLayerNumber to the wx IDs for that layer which are
  82. * the layer name control ID, checkbox control ID, and choice control ID
  83. */
  84. CTLs getCTLs( int aLayerNumber );
  85. wxControl* getName( int aLayer )
  86. {
  87. return getCTLs( aLayer ).name;
  88. }
  89. wxCheckBox* getCheckBox( int aLayer )
  90. {
  91. return getCTLs( aLayer ).checkbox;
  92. }
  93. wxChoice* getChoice( int aLayer )
  94. {
  95. return (wxChoice*) getCTLs( aLayer ).choice;
  96. }
  97. void moveTitles()
  98. {
  99. wxArrayInt widths = m_LayerListFlexGridSizer->GetColWidths();
  100. int offset = 0;
  101. wxSize txtz;
  102. txtz = m_NameStaticText->GetSize();
  103. m_NameStaticText->Move( offset + (widths[0] - txtz.x)/2, 5 );
  104. offset += widths[0];
  105. txtz = m_EnabledStaticText->GetSize();
  106. m_EnabledStaticText->Move( offset + (widths[1] - txtz.x)/2, 5 );
  107. offset += widths[1];
  108. txtz = m_TypeStaticText->GetSize();
  109. m_TypeStaticText->Move( offset + (widths[2] - txtz.x)/2, 5 );
  110. }
  111. public:
  112. DIALOG_LAYERS_SETUP( WinEDA_PcbFrame* parent );
  113. ~DIALOG_LAYERS_SETUP( ) { };
  114. bool Show( bool show ); // overload stock function
  115. /**
  116. * Function Layout
  117. * overrides the standard Layout() function so that the column titles can
  118. * be positioned using information in the flexgridsizer.
  119. */
  120. bool Layout()
  121. {
  122. bool ret = DIALOG_LAYERS_SETUP_BASE::Layout();
  123. moveTitles();
  124. return ret;
  125. }
  126. };
  127. // We want our dialog to remember its previous screen position
  128. wxPoint DIALOG_LAYERS_SETUP::s_LastPos( -1, -1 );
  129. wxSize DIALOG_LAYERS_SETUP::s_LastSize;
  130. // Layer bit masks for each defined "Preset Layer Grouping"
  131. static const int presets[] =
  132. {
  133. #define FRONT_AUX (SILKSCREEN_LAYER_CMP | SOLDERMASK_LAYER_CMP | ADHESIVE_LAYER_CMP | SOLDERPASTE_LAYER_CMP)
  134. #define BACK_AUX (SILKSCREEN_LAYER_CU | SOLDERMASK_LAYER_CU | ADHESIVE_LAYER_CU | SOLDERPASTE_LAYER_CU)
  135. 0, // shift the array index up by one, matches with "Custom".
  136. // "Two layers, parts on Front only"
  137. EDGE_LAYER | LAYER_FRONT | LAYER_BACK | FRONT_AUX,
  138. // "Two layers, parts on Back only",
  139. EDGE_LAYER | LAYER_FRONT | LAYER_BACK | BACK_AUX,
  140. // "Two layers, parts on Front and Back",
  141. EDGE_LAYER | LAYER_FRONT | LAYER_BACK | BACK_AUX | FRONT_AUX,
  142. // "Four layers, parts on Front only"
  143. EDGE_LAYER | LAYER_FRONT | LAYER_BACK | LAYER_2 | LAYER_3 | FRONT_AUX,
  144. // "Four layers, parts on Front and Back"
  145. EDGE_LAYER | LAYER_FRONT | LAYER_BACK | LAYER_2 | LAYER_3 | FRONT_AUX | BACK_AUX,
  146. // "All layers on",
  147. ALL_LAYERS,
  148. };
  149. CTLs DIALOG_LAYERS_SETUP::getCTLs( int aLayerNumber )
  150. {
  151. #define RETCOP(x) return CTLs( x##Name, x##CheckBox, x##Choice );
  152. #define RETAUX(x) return CTLs( x##Name, x##CheckBox, x##StaticText );
  153. switch( aLayerNumber )
  154. {
  155. case ADHESIVE_N_CMP: RETAUX( m_AdhesFront );
  156. case SOLDERPASTE_N_CMP: RETAUX( m_SoldPFront );
  157. case SILKSCREEN_N_CMP: RETAUX( m_SilkSFront );
  158. case SOLDERMASK_N_CMP: RETAUX( m_MaskFront );
  159. case LAYER_N_FRONT: RETCOP( m_Front );
  160. case LAYER_N_2: RETCOP( m_Inner2 );
  161. case LAYER_N_3: RETCOP( m_Inner3 );
  162. case LAYER_N_4: RETCOP( m_Inner4 );
  163. case LAYER_N_5: RETCOP( m_Inner5 );
  164. case LAYER_N_6: RETCOP( m_Inner6 );
  165. case LAYER_N_7: RETCOP( m_Inner7 );
  166. case LAYER_N_8: RETCOP( m_Inner8 );
  167. case LAYER_N_9: RETCOP( m_Inner9 );
  168. case LAYER_N_10: RETCOP( m_Inner10 );
  169. case LAYER_N_11: RETCOP( m_Inner11 );
  170. case LAYER_N_12: RETCOP( m_Inner12 );
  171. case LAYER_N_13: RETCOP( m_Inner13 );
  172. case LAYER_N_14: RETCOP( m_Inner14 );
  173. case LAYER_N_15: RETCOP( m_Inner15 );
  174. case LAYER_N_BACK: RETCOP( m_Back );
  175. case SOLDERMASK_N_CU: RETAUX( m_MaskBack );
  176. case SILKSCREEN_N_CU: RETAUX( m_SilkSBack );
  177. case SOLDERPASTE_N_CU: RETAUX( m_SoldPBack );
  178. case ADHESIVE_N_CU: RETAUX( m_AdhesBack );
  179. case EDGE_N: RETAUX( m_PCBEdges );
  180. case ECO2_N: RETAUX( m_Eco2 );
  181. case ECO1_N: RETAUX( m_Eco1 );
  182. case COMMENT_N: RETAUX( m_Comments );
  183. case DRAW_N: RETAUX( m_Drawings );
  184. default:
  185. // wxDEBUGMSG( "bad layer id" );
  186. return CTLs( 0, 0, 0 );
  187. }
  188. #undef RETCOP
  189. #undef RETAUX
  190. }
  191. /***********************************************************************************/
  192. DIALOG_LAYERS_SETUP::DIALOG_LAYERS_SETUP( WinEDA_PcbFrame* parent ) :
  193. DIALOG_LAYERS_SETUP_BASE( parent )
  194. /***********************************************************************************/
  195. {
  196. m_Parent = parent;
  197. m_Pcb = m_Parent->GetBoard();
  198. m_CopperLayerCount = m_Pcb->GetCopperLayerCount();
  199. showCopperChoice( m_CopperLayerCount );
  200. showBoardLayerNames();
  201. m_EnabledLayers = m_Pcb->GetEnabledLayers();
  202. showSelectedLayerCheckBoxes( m_EnabledLayers );
  203. showPresets( m_EnabledLayers );
  204. showLayerTypes();
  205. SetAutoLayout( true );
  206. // these 3 controls are handled outside wxformbuilder so that we can add
  207. // them without a sizer. Then we position them manually based on the column
  208. // widths from m_LayerListFlexGridSizer->GetColWidths()
  209. m_NameStaticText = new wxStaticText( m_TitlePanel, wxID_ANY, _("Name"), wxDefaultPosition, wxDefaultSize, 0 );
  210. m_EnabledStaticText = new wxStaticText( m_TitlePanel, wxID_ANY, _("Enabled"), wxDefaultPosition, wxDefaultSize, 0 );
  211. m_TypeStaticText = new wxStaticText( m_TitlePanel, wxID_ANY, _("Type"), wxDefaultPosition, wxDefaultSize, 0 );
  212. // set the height of the title panel to be the size of any wxStaticText object
  213. // plus 10 so we can have a border of 5 on both top and bottom.
  214. m_TitlePanel->SetMinSize( wxSize( -1, m_AdhesFrontName->GetSize().y+10 ) );
  215. Layout();
  216. Center();
  217. m_sdbSizer2OK->SetFocus();
  218. }
  219. bool DIALOG_LAYERS_SETUP::Show( bool show )
  220. {
  221. bool ret;
  222. if( show )
  223. {
  224. if( s_LastPos.x != -1 )
  225. {
  226. SetSize( s_LastPos.x, s_LastPos.y, s_LastSize.x, s_LastSize.y, 0 );
  227. }
  228. ret = DIALOG_LAYERS_SETUP_BASE::Show( show );
  229. }
  230. else
  231. {
  232. // Save the dialog's position before hiding
  233. s_LastPos = GetPosition();
  234. s_LastSize = GetSize();
  235. ret = DIALOG_LAYERS_SETUP_BASE::Show( show );
  236. }
  237. return ret;
  238. }
  239. void DIALOG_LAYERS_SETUP::showCopperChoice( int copperCount )
  240. {
  241. static const int copperCounts[] = { 2,4,6,8,10,12,14,16 };
  242. D(printf("boardsCopperCount=%d\n", copperCount );)
  243. for( unsigned i = 0; i<sizeof(copperCounts); ++i )
  244. {
  245. // note this will change a one layer board to 2:
  246. if( copperCount <= copperCounts[i] )
  247. {
  248. m_CopperLayersChoice->SetSelection(i);
  249. break;
  250. }
  251. }
  252. }
  253. void DIALOG_LAYERS_SETUP::showBoardLayerNames()
  254. {
  255. // Establish all the board's layer names into the dialog presentation, by
  256. // obtaining them from BOARD::GetLayerName() which calls
  257. // BOARD::GetDefaultLayerName() for non-coppers.
  258. for( int layer=0; layer<NB_LAYERS; ++layer )
  259. {
  260. wxControl* ctl = getName( layer );
  261. wxASSERT( ctl );
  262. if( ctl )
  263. {
  264. wxString lname = m_Pcb->GetLayerName( layer );
  265. D(printf("layerName[%d]=%s\n", layer, CONV_TO_UTF8( lname ) );)
  266. if( ctl->IsKindOf( CLASSINFO(wxTextCtrl) ) )
  267. ((wxTextCtrl*)ctl)->SetValue( lname ); // wxTextCtrl
  268. else
  269. ctl->SetLabel( lname ); // wxStaticText
  270. }
  271. }
  272. }
  273. void DIALOG_LAYERS_SETUP::showSelectedLayerCheckBoxes( int enabledLayers )
  274. {
  275. for( int layer=0; layer<NB_LAYERS; ++layer )
  276. {
  277. setLayerCheckBox( layer, (1<<layer) & enabledLayers );
  278. }
  279. }
  280. void DIALOG_LAYERS_SETUP::showPresets( int enabledLayers )
  281. {
  282. int presetsNdx = 0; // the "Custom" setting, matches nothing
  283. for( unsigned i=1; i<DIM(presets); ++i )
  284. {
  285. if( enabledLayers == presets[i] )
  286. {
  287. presetsNdx = i;
  288. break;
  289. }
  290. }
  291. m_PresetsChoice->SetSelection( presetsNdx );
  292. }
  293. void DIALOG_LAYERS_SETUP::showLayerTypes()
  294. {
  295. for( int copperLayer = FIRST_COPPER_LAYER;
  296. copperLayer <= LAST_COPPER_LAYER; ++copperLayer )
  297. {
  298. wxChoice* ctl = getChoice( copperLayer );
  299. ctl->SetSelection( m_Pcb->GetLayerType( copperLayer ) );
  300. }
  301. }
  302. int DIALOG_LAYERS_SETUP::getUILayerMask()
  303. {
  304. int layerMaskResult = 0;
  305. for( int layer=0; layer<NB_LAYERS; ++layer )
  306. {
  307. wxCheckBox* ctl = getCheckBox( layer );
  308. if( ctl->GetValue() )
  309. {
  310. layerMaskResult |= (1 << layer);
  311. }
  312. }
  313. return layerMaskResult;
  314. }
  315. void DIALOG_LAYERS_SETUP::setLayerCheckBox( int aLayer, bool isChecked )
  316. {
  317. wxCheckBox* ctl = getCheckBox( aLayer );
  318. ctl->SetValue( isChecked );
  319. }
  320. void DIALOG_LAYERS_SETUP::setCopperLayerCheckBoxes( int copperCount )
  321. {
  322. if( copperCount > 0 )
  323. {
  324. setLayerCheckBox( LAYER_N_BACK, true );
  325. --copperCount;
  326. }
  327. if( copperCount > 0 )
  328. {
  329. setLayerCheckBox( LAYER_N_FRONT, true );
  330. --copperCount;
  331. }
  332. else
  333. {
  334. setLayerCheckBox( LAYER_N_FRONT, false );
  335. }
  336. int layer;
  337. for( layer=LAYER_N_2; copperCount > 0; ++layer, --copperCount )
  338. {
  339. setLayerCheckBox( layer, true );
  340. }
  341. for( ; layer < NB_COPPER_LAYERS-1; ++layer )
  342. {
  343. setLayerCheckBox( layer, false );
  344. }
  345. }
  346. void DIALOG_LAYERS_SETUP::OnCheckBox( wxCommandEvent& event )
  347. {
  348. m_EnabledLayers = getUILayerMask();
  349. showPresets( m_EnabledLayers );
  350. }
  351. void DIALOG_LAYERS_SETUP::DenyChangeCheckBox( wxCommandEvent& event )
  352. {
  353. // user may not change copper layer checkboxes from anything other than
  354. // either presets choice or the copper layer choice controls.
  355. // I tried to simply diable the copper CheckBoxes but they look like crap,
  356. // so leave them enabled and reverse the user's attempt to toggle them.
  357. setCopperLayerCheckBoxes( m_CopperLayerCount );
  358. }
  359. void DIALOG_LAYERS_SETUP::OnPresetsChoice( wxCommandEvent& event )
  360. {
  361. unsigned presetNdx = m_PresetsChoice->GetCurrentSelection();
  362. if( presetNdx == 0 ) // the Custom setting controls nothing.
  363. return;
  364. if( presetNdx < DIM(presets) )
  365. {
  366. m_EnabledLayers = presets[ presetNdx ];
  367. int coppersMask = m_EnabledLayers & ALL_CU_LAYERS;
  368. int copperCount = 0;
  369. while( coppersMask )
  370. {
  371. if( coppersMask & 1 )
  372. ++copperCount;
  373. coppersMask >>= 1;
  374. }
  375. m_CopperLayerCount = copperCount;
  376. showCopperChoice( m_CopperLayerCount );
  377. showSelectedLayerCheckBoxes( m_EnabledLayers );
  378. }
  379. }
  380. void DIALOG_LAYERS_SETUP::OnCopperLayersChoice( wxCommandEvent& event )
  381. {
  382. m_CopperLayerCount = m_CopperLayersChoice->GetCurrentSelection() * 2 + 2;
  383. setCopperLayerCheckBoxes( m_CopperLayerCount );
  384. m_EnabledLayers = getUILayerMask();
  385. showPresets( m_EnabledLayers );
  386. }
  387. /*****************************************************************/
  388. void DIALOG_LAYERS_SETUP::OnCancelButtonClick( wxCommandEvent& event )
  389. /*****************************************************************/
  390. {
  391. EndModal( 0 );
  392. }
  393. /**************************************************************************/
  394. void DIALOG_LAYERS_SETUP::OnOkButtonClick( wxCommandEvent& event )
  395. /**************************************************************************/
  396. {
  397. if( testLayerNames() )
  398. {
  399. wxString name;
  400. m_EnabledLayers = getUILayerMask();
  401. m_Pcb->SetEnabledLayers( m_EnabledLayers );
  402. /* Ensure enabled layers are also visible
  403. * This is mainly to avoid mistakes if some enabled
  404. * layers are not visible when exiting this dialog
  405. */
  406. m_Pcb->SetVisibleLayers( m_EnabledLayers );
  407. for( int layer = FIRST_COPPER_LAYER;
  408. layer <= LAST_COPPER_LAYER; ++layer )
  409. {
  410. if( (1<<layer) & m_EnabledLayers )
  411. {
  412. name = getLayerName( layer );
  413. m_Pcb->SetLayerName( layer, name );
  414. LAYER_T t = (LAYER_T) getLayerTypeIndex(layer);
  415. m_Pcb->SetLayerType( layer, t );
  416. }
  417. }
  418. m_Parent->ReCreateLayerBox( NULL );
  419. EndModal( wxID_OK );
  420. }
  421. }
  422. int DIALOG_LAYERS_SETUP::getLayerTypeIndex( int aLayer )
  423. {
  424. wxChoice* ctl = getChoice( aLayer );
  425. int ret = ctl->GetCurrentSelection(); // indices must have same sequence as LAYER_T
  426. return ret;
  427. }
  428. wxString DIALOG_LAYERS_SETUP::getLayerName( int aLayer )
  429. {
  430. wxString ret;
  431. wxASSERT( aLayer >= FIRST_COPPER_LAYER && aLayer <= LAST_COPPER_LAYER );
  432. wxTextCtrl* ctl = (wxTextCtrl*) getName( aLayer );
  433. ret = ctl->GetValue().Trim();
  434. return ret;
  435. }
  436. static bool hasOneOf( const wxString& str, const wxString& chars )
  437. {
  438. for( unsigned i=0; i<chars.Len(); ++i )
  439. if( str.Find( chars[i] ) != wxNOT_FOUND )
  440. return true;
  441. return false;
  442. }
  443. bool DIALOG_LAYERS_SETUP::testLayerNames()
  444. {
  445. std::vector<wxString> names;
  446. wxTextCtrl* ctl;
  447. for( int layer=0; layer<=LAST_COPPER_LAYER; ++layer )
  448. {
  449. // we _can_ rely on m_EnabledLayers being current here:
  450. if( !(m_EnabledLayers & (1<<layer)) )
  451. continue;
  452. wxString name = getLayerName( layer );
  453. //D(printf("name[%d]=%s\n", layer, CONV_TO_UTF8(name) );)
  454. ctl = (wxTextCtrl*) getName( layer );
  455. // check name for legality.
  456. // 1) cannot be blank.
  457. // 2) cannot have blanks.
  458. // 3) cannot have " chars
  459. // 4) cannot be 'signal'
  460. // 5) must be unique.
  461. static const wxString badchars( wxT("%$\" ") );
  462. if( name == wxEmptyString )
  463. {
  464. DisplayError( this, _("Layer name may not be empty" ) );
  465. ctl->SetFocus(); // on the bad name
  466. return false;
  467. }
  468. if( hasOneOf( name, badchars ) )
  469. {
  470. DisplayError( this, _("Layer name has an illegal character, one of: '") + badchars + wxT("'") );
  471. ctl->SetFocus(); // on the bad name
  472. return false;
  473. }
  474. if( name == wxT("signal") )
  475. {
  476. DisplayError( this, _("'signal' is a reserved layer name") );
  477. ctl->SetFocus(); // on the bad name
  478. return false;
  479. }
  480. for( std::vector<wxString>::iterator it = names.begin(); it != names.end(); ++it )
  481. {
  482. if( name == *it )
  483. {
  484. DisplayError( this, _("Layer name is a duplicate of another") );
  485. ctl->SetFocus(); // on the bad name
  486. return false;
  487. }
  488. }
  489. names.push_back( name );
  490. }
  491. return true;
  492. }
  493. void DisplayDialogLayerSetup( WinEDA_PcbFrame* parent )
  494. {
  495. DIALOG_LAYERS_SETUP frame( parent );
  496. frame.ShowModal();
  497. frame.Destroy();
  498. }