KiCad PCB EDA Suite
Loading...
Searching...
No Matches
panel_fp_user_layer_names.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 The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
25
26#include <pgm_base.h>
30#include <template_fieldnames.h>
32#include <grid_tricks.h>
35#include <bitmaps.h>
36#include <confirm.h>
37
38
39class LAYER_NAMES_GRID_TABLE : public wxGridTableBase
40{
41 std::vector<TEXT_ITEM_INFO> m_items;
42
43public:
45
46 int GetNumberRows() override { return m_items.size(); }
47 int GetNumberCols() override { return 2; }
48
49 wxString GetColLabelValue( int aCol ) override
50 {
51 switch( aCol )
52 {
53 case 0: return _( "Layer" );
54 case 1: return _( "Name" );
55 default: return wxEmptyString;
56 }
57 }
58
59 bool CanGetValueAs( int aRow, int aCol, const wxString& aTypeName ) override
60 {
61 switch( aCol )
62 {
63 case 0: return aTypeName == wxGRID_VALUE_NUMBER;
64 case 1: return aTypeName == wxGRID_VALUE_STRING;
65 default: wxFAIL; return false;
66 }
67 }
68
69 bool CanSetValueAs( int aRow, int aCol, const wxString& aTypeName ) override
70 {
71 return CanGetValueAs( aRow, aCol, aTypeName );
72 }
73
74 wxString GetValue( int row, int col ) override { return m_items[row].m_Text; }
75 void SetValue( int row, int col, const wxString& value ) override
76 {
77 if( col == 1 )
78 m_items[row].m_Text = value;
79 }
80
81 long GetValueAsLong( int row, int col ) override { return m_items[row].m_Layer; }
82 void SetValueAsLong( int row, int col, long value ) override
83 {
84 if( col == 0 )
85 m_items[row].m_Layer = static_cast<PCB_LAYER_ID>( value );
86 }
87
88 bool AppendRows( size_t aNumRows = 1 ) override
89 {
90 std::set<int> layers;
91 int layer = User_1;
92
93 for( const TEXT_ITEM_INFO& item : m_items )
94 layers.insert( item.m_Layer );
95
96 for( size_t i = 0; i < aNumRows; ++i )
97 {
98 while( layers.contains( layer ) )
99 layer = layer + 2;
100
101 if( IsUserLayer( static_cast<PCB_LAYER_ID>( layer ) ) )
102 {
103 layers.insert( layer );
104 m_items.emplace_back( wxT( "" ), true, static_cast<PCB_LAYER_ID>( layer ) );
105 }
106 else
107 {
108 return false;
109 }
110 }
111
112 if( GetView() )
113 {
114 wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, aNumRows );
115 GetView()->ProcessTableMessage( msg );
116 }
117
118 return true;
119 }
120
121 bool DeleteRows( size_t aPos, size_t aNumRows ) override
122 {
123 // aPos may be a large positive, e.g. size_t(-1), and the sum of
124 // aPos+aNumRows may wrap here, so both ends of the range are tested.
125 if( aPos < m_items.size() && aPos + aNumRows <= m_items.size() )
126 {
127 m_items.erase( m_items.begin() + aPos, m_items.begin() + aPos + aNumRows );
128
129 if( GetView() )
130 {
131 wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_DELETED, aPos, aNumRows );
132 GetView()->ProcessTableMessage( msg );
133 }
134
135 return true;
136 }
137
138 return false;
139 }
140};
141
142
147
148
151 m_designSettings( GetPgmSettings().m_DesignSettings )
152{
153 m_layerNamesGrid->SetDefaultRowSize( m_layerNamesGrid->GetDefaultRowSize() + 4 );
154
155 m_layerNamesGrid->SetTable( new LAYER_NAMES_GRID_TABLE(), true );
156 m_layerNamesGrid->PushEventHandler( new GRID_TRICKS( m_layerNamesGrid ) );
157 m_layerNamesGrid->SetSelectionMode( wxGrid::wxGridSelectRows );
158
159 wxGridCellAttr* attr = new wxGridCellAttr;
160 attr->SetRenderer( new GRID_CELL_LAYER_RENDERER( nullptr ) );
161 LSET forbiddenLayers = LSET::AllCuMask() | LSET::AllTechMask();
162 forbiddenLayers.set( Edge_Cuts );
163 forbiddenLayers.set( Margin );
164 attr->SetEditor( new GRID_CELL_LAYER_SELECTOR( nullptr, forbiddenLayers ) );
165 m_layerNamesGrid->SetColAttr( 0, attr );
166
167 attr = new wxGridCellAttr;
168 m_layerNamesGrid->SetColAttr( 1, attr );
169
172}
173
174
179
180
182{
183 int userLayerCount = aCfg->m_DesignSettings.GetUserDefinedLayerCount();
184
185 if( userLayerCount >= 0 && userLayerCount < (int) m_choiceUserLayers->GetCount() )
186 m_choiceUserLayers->SetSelection( userLayerCount );
187 else
188 m_choiceUserLayers->SetSelection( 0 );
189
190 wxGridTableBase* table = m_layerNamesGrid->GetTable();
191 table->DeleteRows( 0, m_layerNamesGrid->GetNumberRows() );
192
193 for( const auto& [canonicalName, userName] : aCfg->m_DesignSettings.m_UserLayerNames )
194 {
195 wxString orig_name = canonicalName;
196 int layer = LSET::NameToLayer( orig_name );
197
198 if( !IsUserLayer( static_cast<PCB_LAYER_ID>( layer ) ) )
199 continue;
200
201 int row = m_layerNamesGrid->GetNumberRows();
202 table->AppendRows( 1 );
203 table->SetValueAsLong( row, 0, layer );
204 table->SetValue( row, 1, userName );
205 }
206
207 Layout();
208}
209
210
212{
214
215 loadFPSettings( &cfg );
216
217 return true;
218}
219
220
222{
223 bool retVal = wxPanel::Show( aShow );
224
225 if( aShow )
226 {
229 }
230
231 return retVal;
232}
233
234
236{
237 if( !m_layerNamesGrid->CommitPendingChanges() )
238 return false;
239
241
242 int userLayerCount = m_choiceUserLayers->GetSelection();
243 cfg.SetUserDefinedLayerCount( userLayerCount );
244
245 cfg.m_UserLayerNames.clear();
246 wxGridTableBase* table = m_layerNamesGrid->GetTable();
247
248 for( int i = 0; i < m_layerNamesGrid->GetNumberRows(); ++i )
249 {
250 PCB_LAYER_ID layer = static_cast<PCB_LAYER_ID>( table->GetValueAsLong( i, 0 ) );
251 wxString orig_name = LSET::Name( static_cast<PCB_LAYER_ID>( layer ) );
252 wxString name = table->GetValue( i, 1 );
253
254 if( layer >= 0 && IsUserLayer( layer ) && !name.IsEmpty() )
255 cfg.m_UserLayerNames.emplace( orig_name.ToStdString(), name );
256 }
257
258 return true;
259}
260
261
263{
264 // Nothing to do here - just update the selection. The value is saved in TransferDataFromWindow.
265}
266
267
269{
270 wxGridTableBase* table = m_layerNamesGrid->GetTable();
271
272 if( event.GetCol() == 0 )
273 {
274 int layer = static_cast<int>( table->GetValueAsLong( event.GetRow(), 0 ) );
275
276 for( int i = 0; i < m_layerNamesGrid->GetNumberRows(); ++i )
277 {
278 if( i != event.GetRow() && table->GetValueAsLong( i, 0 ) == layer )
279 {
280 table->SetValueAsLong( event.GetRow(), 0, getNextAvailableLayer() );
281 return;
282 }
283 }
284 }
285
286 for( int ii = 0; ii < m_layerNamesGrid->GetNumberRows(); ++ii )
287 {
288 wxString layerName = table->GetValue( ii, 1 );
289
290 if( ii != event.GetRow() && layerName == table->GetValue( event.GetRow(), 1 ) )
291 {
292 wxString msg = wxString::Format( _( "Layer name %s already in use." ), layerName );
293 PAGED_DIALOG::GetDialog( this )->SetError( msg, this, m_layerNamesGrid, ii, 1 );
294 return;
295 }
296 }
297}
298
299
301{
302 std::set<int> usedLayers;
303
304 for( int i = 0; i < m_layerNamesGrid->GetNumberRows(); ++i )
305 usedLayers.insert( (int) m_layerNamesGrid->GetTable()->GetValueAsLong( i, 0 ) );
306
307 for( int ii = User_1; ii < User_45; ++ii )
308 {
309 if( !usedLayers.contains( ii ) )
310 return ii;
311 }
312
313 return -1;
314}
315
316
317void PANEL_FP_USER_LAYER_NAMES::OnAddLayerItem( wxCommandEvent& event )
318{
319 m_layerNamesGrid->OnAddRow(
320 [&]() -> std::pair<int, int>
321 {
322 m_layerNamesGrid->GetTable()->AppendRows( 1 );
323 return { m_layerNamesGrid->GetNumberRows() - 1, -1 };
324 } );
325}
326
327
329{
330 m_layerNamesGrid->OnDeleteRows(
331 [&]( int row )
332 {
333 m_layerNamesGrid->GetTable()->DeleteRows( row, 1 );
334 } );
335}
336
337
339{
341 cfg.Load();
342
343 loadFPSettings( &cfg );
344}
const char * name
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:110
BASE_SET & set(size_t pos)
Definition base_set.h:116
Container for design settings for a BOARD object.
std::map< std::string, wxString > m_UserLayerNames
void SetUserDefinedLayerCount(int aNewLayerCount)
Set the number of user defined layers to aNewLayerCount.
BOARD_DESIGN_SETTINGS m_DesignSettings
Only some of these settings are actually used for footprint editing.
Add mouse and command handling (such as cut, copy, and paste) to a WX_GRID instance.
Definition grid_tricks.h:61
virtual void Load()
Updates the parameters of this object based on the current JSON document contents.
bool DeleteRows(size_t aPos, size_t aNumRows) override
void SetValue(int row, int col, const wxString &value) override
std::vector< TEXT_ITEM_INFO > m_items
bool CanGetValueAs(int aRow, int aCol, const wxString &aTypeName) override
wxString GetColLabelValue(int aCol) override
bool AppendRows(size_t aNumRows=1) override
wxString GetValue(int row, int col) override
bool CanSetValueAs(int aRow, int aCol, const wxString &aTypeName) override
void SetValueAsLong(int row, int col, long value) override
long GetValueAsLong(int row, int col) override
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
static int NameToLayer(wxString &aName)
Return the layer number from a layer name.
Definition lset.cpp:117
static const LSET & AllTechMask()
Return a mask holding all technical layers (no CU layer) on both side.
Definition lset.cpp:676
static LSET AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
Definition lset.cpp:608
static wxString Name(PCB_LAYER_ID aLayerId)
Return the fixed name association with aLayerId.
Definition lset.cpp:188
static PAGED_DIALOG * GetDialog(wxWindow *aWindow)
void SetError(const wxString &aMessage, const wxString &aPageName, int aCtrlId, int aRow=-1, int aCol=-1)
PANEL_FP_USER_LAYER_NAMES_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(-1,-1), long style=wxTAB_TRAVERSAL, const wxString &name=wxEmptyString)
void onUserLayerCountChange(wxCommandEvent &event) override
BOARD_DESIGN_SETTINGS & m_designSettings
void ResetPanel() override
Reset the contents of this panel.
void onLayerChange(wxGridEvent &event) override
void OnAddLayerItem(wxCommandEvent &event) override
void loadFPSettings(const FOOTPRINT_EDITOR_SETTINGS *aCfg)
void OnDeleteLayerItem(wxCommandEvent &event) override
This file is part of the common library.
#define _(s)
bool IsUserLayer(PCB_LAYER_ID aLayerId)
Test whether a layer is a non copper and a non tech layer.
Definition layer_ids.h:759
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:60
@ User_45
Definition layer_ids.h:168
@ Edge_Cuts
Definition layer_ids.h:112
@ Margin
Definition layer_ids.h:113
@ User_1
Definition layer_ids.h:124
static FOOTPRINT_EDITOR_SETTINGS & GetPgmSettings()
static FOOTPRINT_EDITOR_SETTINGS & GetPgmSettings()
see class PGM_BASE
T * GetAppSettings(const char *aFilename)