1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2012-2014 Jean-Pierre Charras  jp.charras at wanadoo.fr
5  * Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
23  */
24 
25 /**
26  * @file dialog_select_one_pcb_layer.cpp
27  * @brief Set up a dialog to choose a PCB Layer.
28  */
29 
30 #include <gerbview_frame.h>
31 #include <dialogs/dialog_layers_select_to_pcb.h>
32 
33 #include <wx/radiobox.h>
34 
35 #define NB_PCB_LAYERS PCB_LAYER_ID_COUNT
36 #define FIRST_COPPER_LAYER 0
37 #define LAST_COPPER_LAYER 31
38 
39 // Exported function
40 const wxString GetPCBDefaultLayerName( int aLayerId );
41 
42 
43 enum layer_sel_id {
44     ID_LAYER_SELECT_TOP = 1800,
45     ID_LAYER_SELECT_BOTTOM,
46     ID_LAYER_SELECT
47 };
48 
49 
50 class SELECT_LAYER_DIALOG : public DIALOG_SHIM
51 {
52 public:
53     SELECT_LAYER_DIALOG( GERBVIEW_FRAME* parent, int aDefaultLayer, int aCopperLayerCount,
54                          wxString aGerberName );
~SELECT_LAYER_DIALOG()55     ~SELECT_LAYER_DIALOG() { };
56 
GetSelectedLayer()57     int GetSelectedLayer() { return m_selectedLayer; }
58 
59 protected:
60     bool TransferDataFromWindow() override;
61 
62 private:
63     void OnLayerSelected( wxCommandEvent& event );
64 
65     DECLARE_EVENT_TABLE()
66 
67     int               m_selectedLayer;
68     wxRadioBox*       m_layerRadioBox;
69     std::vector <int> m_layerId;
70 };
71 
72 
BEGIN_EVENT_TABLE(SELECT_LAYER_DIALOG,wxDialog)73 BEGIN_EVENT_TABLE( SELECT_LAYER_DIALOG, wxDialog )
74     EVT_RADIOBOX( ID_LAYER_SELECT, SELECT_LAYER_DIALOG::OnLayerSelected )
75 END_EVENT_TABLE()
76 
77 
78 int GERBVIEW_FRAME::SelectPCBLayer( int aDefaultLayer, int aCopperLayerCount,
79                                     const wxString& aGerberName )
80 {
81     SELECT_LAYER_DIALOG* frame =
82             new SELECT_LAYER_DIALOG( this, aDefaultLayer, aCopperLayerCount, aGerberName );
83 
84     frame->ShowModal();
85     frame->Destroy();
86     return frame->GetSelectedLayer();
87 }
88 
89 
SELECT_LAYER_DIALOG(GERBVIEW_FRAME * parent,int aDefaultLayer,int aCopperLayerCount,wxString aGerberName)90 SELECT_LAYER_DIALOG::SELECT_LAYER_DIALOG( GERBVIEW_FRAME* parent, int aDefaultLayer,
91                                           int aCopperLayerCount, wxString aGerberName )
92     : DIALOG_SHIM( parent, -1, wxString::Format( _( "Select Layer: %s" ), aGerberName ),
93                    wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER )
94 {
95     wxButton* button;
96     int ii;
97     wxArrayString  layerList;
98     int selected = -1;
99 
100     // Store the passed default layer in case the user hits Cancel
101     m_selectedLayer = aDefaultLayer;
102 
103     // Build the layer list; first build copper layers list
104     int layerCount = 0;
105 
106     for( ii = FIRST_COPPER_LAYER; ii <= LAST_COPPER_LAYER; ++ii )
107     {
108         if( ii == FIRST_COPPER_LAYER || ii == LAST_COPPER_LAYER || ii < aCopperLayerCount-1 )
109         {
110             layerList.Add( GetPCBDefaultLayerName( ii ) );
111 
112             if( aDefaultLayer == ii )
113                 selected = layerCount;
114 
115             m_layerId.push_back( ii );
116             layerCount++;
117         }
118     }
119 
120     // Build the layer list; build non copper layers list
121     for( ; ; ++ii )
122     {
123         if( GetPCBDefaultLayerName( ii ) == "" )    // End of list
124             break;
125 
126         layerList.Add( GetPCBDefaultLayerName( ii ) );
127 
128         if( aDefaultLayer == ii )
129             selected = layerCount;
130 
131         m_layerId.push_back( ii );
132         layerCount++;
133     }
134 
135     layerList.Add( _( "Hole data" ) );
136 
137     if( aDefaultLayer == UNDEFINED_LAYER )
138         selected = layerCount;
139 
140     m_layerId.push_back( UNDEFINED_LAYER );
141     layerCount++;
142 
143     layerList.Add( _( "Do not export" ) );
144 
145     if( aDefaultLayer == UNSELECTED_LAYER )
146         selected = layerCount;
147 
148     m_layerId.push_back( UNSELECTED_LAYER );
149     layerCount++;
150 
151     m_layerRadioBox = new wxRadioBox( this, ID_LAYER_SELECT, _( "Layer" ), wxDefaultPosition,
152                                       wxDefaultSize, layerList, std::min( layerCount, 12 ),
153                                       wxRA_SPECIFY_ROWS );
154 
155     if( selected >= 0 )
156         m_layerRadioBox->SetSelection( selected );
157 
158     wxBoxSizer* mainSizer = new wxBoxSizer( wxHORIZONTAL );
159     SetSizer( mainSizer );
160     mainSizer->Add( m_layerRadioBox, 1, wxEXPAND | wxALIGN_TOP | wxALL, 5 );
161     wxBoxSizer* buttonsSizer = new wxBoxSizer( wxVERTICAL );
162     mainSizer->Add( buttonsSizer, 0, wxALIGN_BOTTOM | wxALL, 5 );
163 
164     button = new wxButton( this, wxID_OK, _( "OK" ) );
165     button->SetDefault();
166     buttonsSizer->Add( button, 0, wxGROW | wxALL, 5 );
167 
168     button = new wxButton( this, wxID_CANCEL, _( "Cancel" ) );
169     buttonsSizer->Add( button, 0, wxGROW | wxALL, 5 );
170 
171 #ifdef __WXOSX__
172     // Hack to fix clipped radio buttons on OSX
173     wxSize size = m_layerRadioBox->GetBestSize() + wxSize( 20, 0 );
174     m_layerRadioBox->SetMinSize( size );
175 #endif
176 
177     GetSizer()->SetSizeHints( this );
178 
179     Center();
180 }
181 
182 
OnLayerSelected(wxCommandEvent & event)183 void SELECT_LAYER_DIALOG::OnLayerSelected( wxCommandEvent& event )
184 {
185     wxPostEvent( this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
186 }
187 
188 
TransferDataFromWindow()189 bool SELECT_LAYER_DIALOG::TransferDataFromWindow()
190 {
191     if( !wxDialog::TransferDataFromWindow() )
192         return false;
193 
194     m_selectedLayer = m_layerId[m_layerRadioBox->GetSelection()];
195     return true;
196 }
197 
198 
199 // This function is a duplicate of
200 // const wxChar* LSET::Name( PCB_LAYER_ID aLayerId )
201 // However it avoids a dependency to Pcbnew code.
GetPCBDefaultLayerName(int aLayerId)202 const wxString GetPCBDefaultLayerName( int aLayerId )
203 {
204     const wxChar* txt;
205 
206     // using a switch to explicitly show the mapping more clearly
207     switch( aLayerId )
208     {
209     case F_Cu:              txt = wxT( "F.Cu" );            break;
210     case In1_Cu:            txt = wxT( "In1.Cu" );          break;
211     case In2_Cu:            txt = wxT( "In2.Cu" );          break;
212     case In3_Cu:            txt = wxT( "In3.Cu" );          break;
213     case In4_Cu:            txt = wxT( "In4.Cu" );          break;
214     case In5_Cu:            txt = wxT( "In5.Cu" );          break;
215     case In6_Cu:            txt = wxT( "In6.Cu" );          break;
216     case In7_Cu:            txt = wxT( "In7.Cu" );          break;
217     case In8_Cu:            txt = wxT( "In8.Cu" );          break;
218     case In9_Cu:            txt = wxT( "In9.Cu" );          break;
219     case In10_Cu:           txt = wxT( "In10.Cu" );         break;
220     case In11_Cu:           txt = wxT( "In11.Cu" );         break;
221     case In12_Cu:           txt = wxT( "In12.Cu" );         break;
222     case In13_Cu:           txt = wxT( "In13.Cu" );         break;
223     case In14_Cu:           txt = wxT( "In14.Cu" );         break;
224     case In15_Cu:           txt = wxT( "In15.Cu" );         break;
225     case In16_Cu:           txt = wxT( "In16.Cu" );         break;
226     case In17_Cu:           txt = wxT( "In17.Cu" );         break;
227     case In18_Cu:           txt = wxT( "In18.Cu" );         break;
228     case In19_Cu:           txt = wxT( "In19.Cu" );         break;
229     case In20_Cu:           txt = wxT( "In20.Cu" );         break;
230     case In21_Cu:           txt = wxT( "In21.Cu" );         break;
231     case In22_Cu:           txt = wxT( "In22.Cu" );         break;
232     case In23_Cu:           txt = wxT( "In23.Cu" );         break;
233     case In24_Cu:           txt = wxT( "In24.Cu" );         break;
234     case In25_Cu:           txt = wxT( "In25.Cu" );         break;
235     case In26_Cu:           txt = wxT( "In26.Cu" );         break;
236     case In27_Cu:           txt = wxT( "In27.Cu" );         break;
237     case In28_Cu:           txt = wxT( "In28.Cu" );         break;
238     case In29_Cu:           txt = wxT( "In29.Cu" );         break;
239     case In30_Cu:           txt = wxT( "In30.Cu" );         break;
240     case B_Cu:              txt = wxT( "B.Cu" );            break;
241 
242     // Technicals
243     case B_Adhes:           txt = wxT( "B.Adhes" );         break;
244     case F_Adhes:           txt = wxT( "F.Adhes" );         break;
245     case B_Paste:           txt = wxT( "B.Paste" );         break;
246     case F_Paste:           txt = wxT( "F.Paste" );         break;
247     case B_SilkS:           txt = wxT( "B.SilkS" );         break;
248     case F_SilkS:           txt = wxT( "F.SilkS" );         break;
249     case B_Mask:            txt = wxT( "B.Mask" );          break;
250     case F_Mask:            txt = wxT( "F.Mask" );          break;
251 
252     // Users
253     case Dwgs_User:         txt = wxT( "Dwgs.User" );       break;
254     case Cmts_User:         txt = wxT( "Cmts.User" );       break;
255     case Eco1_User:         txt = wxT( "Eco1.User" );       break;
256     case Eco2_User:         txt = wxT( "Eco2.User" );       break;
257     case Edge_Cuts:         txt = wxT( "Edge.Cuts" );       break;
258 
259     // Pcbnew knows some other layers, but any other layer is not suitable for export.
260 
261     default:    // Sentinel
262         txt = wxT( "" ); break;
263     }
264 
265     return wxString( txt );
266 }
267