KiCad PCB EDA Suite
Loading...
Searching...
No Matches
panel_setup_tracks_and_vias.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
24
25#include <pcb_edit_frame.h>
27#include <pcb_track.h>
28#include <bitmaps.h>
29#include <widgets/wx_grid.h>
31#include <optional>
32#include <grid_tricks.h>
33
35
36
41
47
54
55
57 PCB_EDIT_FRAME* aFrame ) :
59{
60 m_Frame = aFrame;
61 m_Pcb = m_Frame->GetBoard();
62 m_BrdSettings = &m_Pcb->GetDesignSettings();
63
73
74 m_trackWidthsGrid->PushEventHandler( new GRID_TRICKS( m_trackWidthsGrid,
75 [this]( wxCommandEvent& aEvent )
76 {
77 OnAddTrackWidthsClick( aEvent );
78 } ) );
79 m_viaSizesGrid->PushEventHandler( new GRID_TRICKS( m_viaSizesGrid,
80 [this]( wxCommandEvent& aEvent )
81 {
82 OnAddViaSizesClick( aEvent );
83 } ) );
84 m_diffPairsGrid->PushEventHandler( new GRID_TRICKS( m_diffPairsGrid,
85 [this]( wxCommandEvent& aEvent )
86 {
87 OnAddDiffPairsClick( aEvent );
88 } ) );
89
90 m_trackWidthsGrid->SetSelectionMode( wxGrid::wxGridSelectionModes::wxGridSelectRows );
91 m_viaSizesGrid->SetSelectionMode( wxGrid::wxGridSelectionModes::wxGridSelectRows );
92 m_diffPairsGrid->SetSelectionMode( wxGrid::wxGridSelectionModes::wxGridSelectRows );
93
94 m_trackWidthsGrid->SetUnitsProvider( m_Frame );
95 m_viaSizesGrid->SetUnitsProvider( m_Frame );
96 m_diffPairsGrid->SetUnitsProvider( m_Frame );
97
98 m_trackWidthsGrid->SetAutoEvalCols( { 0 } );
99 m_viaSizesGrid->SetAutoEvalCols( { 0, 1 } );
100 m_diffPairsGrid->SetAutoEvalCols( { 0, 1, 2 } );
101
102 m_trackWidthsGrid->SetUseNativeColLabels();
103 m_viaSizesGrid->SetUseNativeColLabels();
104 m_diffPairsGrid->SetUseNativeColLabels();
105
106 // Ensure width of columns is enough to enter any reasonable value
107 WX_GRID* grid_list[] = { m_trackWidthsGrid, m_viaSizesGrid, m_diffPairsGrid, nullptr };
108 int min_linesize = m_trackWidthsGrid->GetTextExtent( wxT( "000.000000 mm " ) ).x;
109
110 for( int ii = 0; grid_list[ii]; ii++ )
111 {
112 WX_GRID* curr_grid = grid_list[ii];
113
114 for( int col = 0; col < curr_grid->GetNumberCols(); col++ )
115 {
116 int min_w = curr_grid->GetVisibleWidth( col, true, true, true );
117 int best_w = std::max( min_linesize, min_w );
118 curr_grid->SetColMinimalWidth( col, best_w );
119 curr_grid->SetColSize( col,best_w );
120 }
121 }
122
123 m_Frame->Bind( EDA_EVT_UNITS_CHANGED, &PANEL_SETUP_TRACKS_AND_VIAS::onUnitsChanged, this );
124}
125
126
128{
129 // Delete the GRID_TRICKS.
130 m_trackWidthsGrid->PopEventHandler( true );
131 m_viaSizesGrid->PopEventHandler( true );
132 m_diffPairsGrid->PopEventHandler( true );
133
134 m_Frame->Unbind( EDA_EVT_UNITS_CHANGED, &PANEL_SETUP_TRACKS_AND_VIAS::onUnitsChanged, this );
135}
136
137
139{
140 if( m_trackWidthsGrid->GetNumberRows() < 2 )
141 return;
142
143 std::vector<int> trackWidths;
144 wxString msg;
145
146 m_trackWidthsGrid->ClearSelection();
147 wxSafeYield();
148
149 wxGridUpdateLocker lock( m_trackWidthsGrid );
150
151 for( int row = 0; row < m_trackWidthsGrid->GetNumberRows(); ++row )
152 {
153 msg = m_trackWidthsGrid->GetCellValue( row, TR_WIDTH_COL );
154
155 if( !msg.IsEmpty() )
156 trackWidths.push_back( m_Frame->ValueFromString( msg ) );
157 }
158
159 std::sort( trackWidths.begin(), trackWidths.end() );
160 m_trackWidthsGrid->ClearRows( false );
161
162 for( int width : trackWidths )
163 AppendTrackWidth( width );
164}
165
166
168{
169 if( m_viaSizesGrid->GetNumberRows() < 2 )
170 return;
171
172 std::vector<VIA_DIMENSION> vias;
173 wxString msg;
174
175 m_viaSizesGrid->ClearSelection();
176 wxSafeYield();
177
178 wxGridUpdateLocker lock( m_viaSizesGrid );
179
180 for( int row = 0; row < m_viaSizesGrid->GetNumberRows(); ++row )
181 {
182 msg = m_viaSizesGrid->GetCellValue( row, VIA_SIZE_COL );
183
184 if( !msg.IsEmpty() )
185 {
186 VIA_DIMENSION via_dim;
187 via_dim.m_Diameter = m_Frame->ValueFromString( msg );
188
189 msg = m_viaSizesGrid->GetCellValue( row, VIA_DRILL_COL );
190
191 if( !msg.IsEmpty() )
192 via_dim.m_Drill = m_Frame->ValueFromString( msg );
193
194 vias.push_back( via_dim );
195 }
196 }
197
198 std::sort( vias.begin(), vias.end() );
199 m_viaSizesGrid->ClearRows( false );
200
201 for( const VIA_DIMENSION& via : vias )
202 AppendViaSize( via.m_Diameter, via.m_Drill );
203}
204
205
207{
208 if( m_diffPairsGrid->GetNumberRows() < 2 )
209 return;
210
211 wxString msg;
212 std::vector<DIFF_PAIR_DIMENSION> diffPairs;
213
214 m_diffPairsGrid->ClearSelection();
215 wxSafeYield();
216
217 wxGridUpdateLocker lock( m_diffPairsGrid );
218
219 for( int row = 0; row < m_diffPairsGrid->GetNumberRows(); ++row )
220 {
221 msg = m_diffPairsGrid->GetCellValue( row, DP_WIDTH_COL );
222
223 if( !msg.IsEmpty() )
224 {
225 DIFF_PAIR_DIMENSION diffPair_dim;
226 diffPair_dim.m_Width = m_Frame->ValueFromString( msg );
227
228 msg = m_diffPairsGrid->GetCellValue( row, DP_GAP_COL );
229 diffPair_dim.m_Gap = m_Frame->ValueFromString( msg );
230
231 msg = m_diffPairsGrid->GetCellValue( row, DP_VIA_GAP_COL );
232
233 if( !msg.IsEmpty() )
234 diffPair_dim.m_ViaGap = m_Frame->ValueFromString( msg );
235
236 diffPairs.push_back( diffPair_dim );
237 }
238 }
239
240 std::sort( diffPairs.begin(), diffPairs.end() );
241 m_diffPairsGrid->ClearRows( false );
242
243 for( const DIFF_PAIR_DIMENSION& dp : diffPairs )
244 AppendDiffPairs( dp.m_Width, dp.m_Gap, dp.m_ViaGap );
245}
246
247
249{
250 BOARD_DESIGN_SETTINGS tempBDS( nullptr, "dummy" );
252
253 m_BrdSettings = &tempBDS; // No, address of stack var does not escape function
254
257
258 m_BrdSettings = saveBDS;
259
260 aEvent.Skip();
261}
262
263
265{
266 m_trackWidthsGrid->ClearRows();
267 m_viaSizesGrid->ClearRows();
268 m_diffPairsGrid->ClearRows();
269
270 // Skip the first item, which is the current netclass value
271 for( unsigned ii = 1; ii < m_BrdSettings->m_TrackWidthList.size(); ii++ )
272 {
273 AppendTrackWidth( m_BrdSettings->m_TrackWidthList[ii] );
274 }
275
276 // Skip the first item, which is the current netclass value
277 for( unsigned ii = 1; ii < m_BrdSettings->m_ViasDimensionsList.size(); ii++ )
278 {
279 AppendViaSize( m_BrdSettings->m_ViasDimensionsList[ii].m_Diameter,
280 m_BrdSettings->m_ViasDimensionsList[ii].m_Drill );
281 }
282
283 // Skip the first item, which is the current netclass value
284 for( unsigned ii = 1; ii < m_BrdSettings->m_DiffPairDimensionsList.size(); ii++ )
285 {
286 AppendDiffPairs( m_BrdSettings->m_DiffPairDimensionsList[ii].m_Width,
287 m_BrdSettings->m_DiffPairDimensionsList[ii].m_Gap,
288 m_BrdSettings->m_DiffPairDimensionsList[ii].m_ViaGap );
289 }
290
291 return true;
292}
293
294
296{
297 if( !commitPendingChanges() )
298 return false;
299
300 std::vector<int> trackWidths;
301 std::vector<VIA_DIMENSION> vias;
302 std::vector<DIFF_PAIR_DIMENSION> diffPairs;
303
304 // Test ONLY for malformed data. Design rules and constraints are the business of DRC.
305
306 for( int row = 0; row < m_trackWidthsGrid->GetNumberRows(); ++row )
307 {
308 if( !m_trackWidthsGrid->GetCellValue( row, TR_WIDTH_COL ).IsEmpty() )
309 trackWidths.push_back( m_trackWidthsGrid->GetUnitValue( row, TR_WIDTH_COL ) );
310 }
311
312 for( int row = 0; row < m_viaSizesGrid->GetNumberRows(); ++row )
313 {
314 if( !m_viaSizesGrid->GetCellValue( row, VIA_SIZE_COL ).IsEmpty() )
315 {
316 VIA_DIMENSION via_dim;
317 via_dim.m_Diameter = m_viaSizesGrid->GetUnitValue( row, VIA_SIZE_COL );
318
319 if( !m_viaSizesGrid->GetCellValue( row, VIA_DRILL_COL ).IsEmpty() )
320 via_dim.m_Drill = m_viaSizesGrid->GetUnitValue( row, VIA_DRILL_COL );
321
322 vias.push_back( via_dim );
323 }
324 }
325
326 for( int row = 0; row < m_diffPairsGrid->GetNumberRows(); ++row )
327 {
328 if( !m_diffPairsGrid->GetCellValue( row, DP_WIDTH_COL ).IsEmpty() )
329 {
330 DIFF_PAIR_DIMENSION diffPair_dim;
331 diffPair_dim.m_Width = m_diffPairsGrid->GetUnitValue( row, DP_WIDTH_COL );
332
333 if( !m_diffPairsGrid->GetCellValue( row, DP_GAP_COL ).IsEmpty() )
334 diffPair_dim.m_Gap = m_diffPairsGrid->GetUnitValue( row, DP_GAP_COL );
335
336 if( !m_diffPairsGrid->GetCellValue( row, DP_VIA_GAP_COL ).IsEmpty() )
337 diffPair_dim.m_ViaGap = m_diffPairsGrid->GetUnitValue( row, DP_VIA_GAP_COL );
338
339 diffPairs.push_back( diffPair_dim );
340 }
341 }
342
343 // Sort lists by increasing value
344 sort( trackWidths.begin(), trackWidths.end() );
345 sort( vias.begin(), vias.end() );
346 sort( diffPairs.begin(), diffPairs.end() );
347
348 // These are all stored in project file, not board, so no need for OnModify()
349
350 trackWidths.insert( trackWidths.begin(), 0 ); // dummy value for "use netclass"
351 m_BrdSettings->m_TrackWidthList = trackWidths;
352
353 vias.insert( vias.begin(), { 0, 0 } ); // dummy value for "use netclass"
354 m_BrdSettings->m_ViasDimensionsList = vias;
355
356 diffPairs.insert( diffPairs.begin(), { 0, 0, 0 } ); // dummy value for "use netclass"
357 m_BrdSettings->m_DiffPairDimensionsList = diffPairs;
358
359 return true;
360}
361
362
364{
365 return m_trackWidthsGrid->CommitPendingChanges( aQuietMode )
366 && m_viaSizesGrid->CommitPendingChanges( aQuietMode )
367 && m_diffPairsGrid->CommitPendingChanges( aQuietMode );
368}
369
370
372{
373 if( !commitPendingChanges() )
374 return false;
375
376 wxString msg;
377
378 // Test vias
379 for( int row = 0; row < m_viaSizesGrid->GetNumberRows(); ++row )
380 {
381 wxString viaDia = m_viaSizesGrid->GetCellValue( row, VIA_SIZE_COL );
382 wxString viaDrill = m_viaSizesGrid->GetCellValue( row, VIA_DRILL_COL );
383
384 std::optional<int> viaDiameter;
385
386 if( !viaDia.IsEmpty() )
387 viaDiameter = m_viaSizesGrid->GetUnitValue( row, VIA_SIZE_COL );
388
389 std::optional<int> viaDrillSize;
390
391 if( !viaDrill.IsEmpty() )
392 viaDrillSize = m_viaSizesGrid->GetUnitValue( row, VIA_DRILL_COL );
393
394 if( std::optional<PCB_VIA::VIA_PARAMETER_ERROR> error =
395 PCB_VIA::ValidateViaParameters( viaDiameter, viaDrillSize ) )
396 {
397 msg = error->m_Message;
398
399 int errorCol = VIA_SIZE_COL;
400
401 if( error->m_Field == PCB_VIA::VIA_PARAMETER_ERROR::FIELD::DRILL )
402 errorCol = VIA_DRILL_COL;
403
404 PAGED_DIALOG::GetDialog( this )->SetError( msg, this, m_viaSizesGrid, row, errorCol );
405 return false;
406 }
407 }
408
409 // Test diff pairs
410 for( int row = 0; row < m_diffPairsGrid->GetNumberRows(); ++row )
411 {
412 wxString dpWidth = m_diffPairsGrid->GetCellValue( row, 0 );
413 wxString dpGap = m_diffPairsGrid->GetCellValue( row, 1 );
414
415 if( !dpWidth.IsEmpty() && dpGap.IsEmpty() )
416 {
417 msg = _( "No differential pair gap defined." );
418 PAGED_DIALOG::GetDialog( this )->SetError( msg, this, m_diffPairsGrid, row, 1 );
419 return false;
420 }
421 }
422
423 return true;
424}
425
426
428{
429 int i = m_trackWidthsGrid->GetNumberRows();
430
431 m_trackWidthsGrid->AppendRows( 1 );
432
433 m_trackWidthsGrid->SetUnitValue( i, TR_WIDTH_COL, aWidth );
434}
435
436
438{
439 int i = m_viaSizesGrid->GetNumberRows();
440
441 m_viaSizesGrid->AppendRows( 1 );
442
443 m_viaSizesGrid->SetUnitValue( i, VIA_SIZE_COL, aSize );
444
445 if( aDrill > 0 )
446 m_viaSizesGrid->SetUnitValue( i, VIA_DRILL_COL, aDrill );
447}
448
449
450void PANEL_SETUP_TRACKS_AND_VIAS::AppendDiffPairs( int aWidth, int aGap, int aViaGap )
451{
452 int i = m_diffPairsGrid->GetNumberRows();
453
454 m_diffPairsGrid->AppendRows( 1 );
455
456 m_diffPairsGrid->SetUnitValue( i, DP_WIDTH_COL, aWidth );
457
458 if( aGap > 0 )
459 m_diffPairsGrid->SetUnitValue( i, DP_GAP_COL, aGap );
460
461 if( aViaGap > 0 )
462 m_diffPairsGrid->SetUnitValue( i, DP_VIA_GAP_COL, aViaGap );
463}
464
465
467{
468 m_trackWidthsGrid->OnAddRow(
469 [&]() -> std::pair<int, int>
470 {
471 AppendTrackWidth( 0 );
472 return { m_trackWidthsGrid->GetNumberRows() - 1, TR_WIDTH_COL };
473 } );
474}
475
476
478{
479 m_trackWidthsGrid->OnDeleteRows(
480 [&]( int row )
481 {
482 m_trackWidthsGrid->DeleteRows( row, 1 );
483 } );
484}
485
486
488{
489 m_viaSizesGrid->OnAddRow(
490 [&]() -> std::pair<int, int>
491 {
492 AppendViaSize( 0, 0 );
493 return { m_viaSizesGrid->GetNumberRows() - 1, VIA_SIZE_COL };
494 } );
495}
496
497
499{
500 m_viaSizesGrid->OnDeleteRows(
501 [&]( int row )
502 {
503 m_viaSizesGrid->DeleteRows( row, 1 );
504 } );
505}
506
507
509{
510 m_diffPairsGrid->OnAddRow(
511 [&]() -> std::pair<int, int>
512 {
513 AppendDiffPairs( 0, 0, 0 );
514 return { m_diffPairsGrid->GetNumberRows() - 1, DP_WIDTH_COL };
515 } );
516}
517
518
520{
521 m_diffPairsGrid->OnDeleteRows(
522 [&]( int row )
523 {
524 m_diffPairsGrid->DeleteRows( row, 1 );
525 } );
526}
527
528
530{
531 commitPendingChanges( true );
532
533 // Note: do not change the board, as we need to get the current nets from it for
534 // netclass memberships. All the netclass definitions and dimension lists are in
535 // the BOARD_DESIGN_SETTINGS.
536
537 BOARD_DESIGN_SETTINGS* savedSettings = m_BrdSettings;
538
539 m_BrdSettings = &aBoard->GetDesignSettings();
541
542 m_BrdSettings = savedSettings;
543}
544
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:110
@ small_sort_desc
Container for design settings for a BOARD object.
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:322
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition board.cpp:1041
Add mouse and command handling (such as cut, copy, and paste) to a WX_GRID instance.
Definition grid_tricks.h:61
static PAGED_DIALOG * GetDialog(wxWindow *aWindow)
void SetError(const wxString &aMessage, const wxString &aPageName, int aCtrlId, int aRow=-1, int aCol=-1)
PANEL_SETUP_TRACKS_AND_VIAS_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 OnRemoveViaSizesClick(wxCommandEvent &event) override
PANEL_SETUP_TRACKS_AND_VIAS(wxWindow *aParentWindow, PCB_EDIT_FRAME *aFrame)
void OnRemoveDiffPairsClick(wxCommandEvent &event) override
void OnSortTrackWidthsClick(wxCommandEvent &event) override
bool commitPendingChanges(bool aQuietMode=false)
void onUnitsChanged(wxCommandEvent &aEvent)
void OnSortViaSizesClick(wxCommandEvent &event) override
void OnAddViaSizesClick(wxCommandEvent &event) override
void OnSortDiffPairsClick(wxCommandEvent &event) override
void OnRemoveTrackWidthsClick(wxCommandEvent &event) override
void OnAddDiffPairsClick(wxCommandEvent &event) override
void AppendDiffPairs(int aWidth, int aGap, int aViaGap)
void OnAddTrackWidthsClick(wxCommandEvent &event) override
void AppendViaSize(int aSize, int aDrill)
The main frame for Pcbnew.
static std::optional< VIA_PARAMETER_ERROR > ValidateViaParameters(std::optional< int > aDiameter, std::optional< int > aDrill, std::optional< PCB_LAYER_ID > aStartLayer=std::nullopt, std::optional< PCB_LAYER_ID > aEndLayer=std::nullopt)
int GetVisibleWidth(int aCol, bool aHeader=true, bool aContents=true, bool aKeep=false)
Calculate the specified column based on the actual size of the text on screen.
Definition wx_grid.cpp:911
#define _(s)
Container to handle a stock of specific differential pairs each with unique track width,...
Container to handle a stock of specific vias each with unique diameter and drill sizes in the BOARD c...