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, see <https://www.gnu.org/licenses/>.
18 */
19
20
21#include <pcb_edit_frame.h>
23#include <pcb_track.h>
24#include <bitmaps.h>
25#include <widgets/wx_grid.h>
27#include <optional>
28#include <grid_tricks.h>
29
31
32
37
43
50
51
53 PCB_EDIT_FRAME* aFrame ) :
55{
56 m_Frame = aFrame;
57 m_Pcb = m_Frame->GetBoard();
58 m_BrdSettings = &m_Pcb->GetDesignSettings();
59
69
70 m_trackWidthsGrid->PushEventHandler( new GRID_TRICKS( m_trackWidthsGrid,
71 [this]( wxCommandEvent& aEvent )
72 {
73 OnAddTrackWidthsClick( aEvent );
74 } ) );
75 m_viaSizesGrid->PushEventHandler( new GRID_TRICKS( m_viaSizesGrid,
76 [this]( wxCommandEvent& aEvent )
77 {
78 OnAddViaSizesClick( aEvent );
79 } ) );
80 m_diffPairsGrid->PushEventHandler( new GRID_TRICKS( m_diffPairsGrid,
81 [this]( wxCommandEvent& aEvent )
82 {
83 OnAddDiffPairsClick( aEvent );
84 } ) );
85
86 m_trackWidthsGrid->SetSelectionMode( wxGrid::wxGridSelectionModes::wxGridSelectRows );
87 m_viaSizesGrid->SetSelectionMode( wxGrid::wxGridSelectionModes::wxGridSelectRows );
88 m_diffPairsGrid->SetSelectionMode( wxGrid::wxGridSelectionModes::wxGridSelectRows );
89
90 m_trackWidthsGrid->SetUnitsProvider( m_Frame );
91 m_viaSizesGrid->SetUnitsProvider( m_Frame );
92 m_diffPairsGrid->SetUnitsProvider( m_Frame );
93
94 m_trackWidthsGrid->SetAutoEvalCols( { 0 } );
95 m_viaSizesGrid->SetAutoEvalCols( { 0, 1 } );
96 m_diffPairsGrid->SetAutoEvalCols( { 0, 1, 2 } );
97
98 m_trackWidthsGrid->SetUseNativeColLabels();
99 m_viaSizesGrid->SetUseNativeColLabels();
100 m_diffPairsGrid->SetUseNativeColLabels();
101
102 // Ensure width of columns is enough to enter any reasonable value
103 WX_GRID* grid_list[] = { m_trackWidthsGrid, m_viaSizesGrid, m_diffPairsGrid, nullptr };
104 int min_linesize = m_trackWidthsGrid->GetTextExtent( wxT( "000.000000 mm " ) ).x;
105
106 for( int ii = 0; grid_list[ii]; ii++ )
107 {
108 WX_GRID* curr_grid = grid_list[ii];
109
110 for( int col = 0; col < curr_grid->GetNumberCols(); col++ )
111 {
112 int min_w = curr_grid->GetVisibleWidth( col, true, true, true );
113 int best_w = std::max( min_linesize, min_w );
114 curr_grid->SetColMinimalWidth( col, best_w );
115 curr_grid->SetColSize( col,best_w );
116 }
117 }
118
119 m_Frame->Bind( EDA_EVT_UNITS_CHANGED, &PANEL_SETUP_TRACKS_AND_VIAS::onUnitsChanged, this );
120}
121
122
124{
125 // Delete the GRID_TRICKS.
126 m_trackWidthsGrid->PopEventHandler( true );
127 m_viaSizesGrid->PopEventHandler( true );
128 m_diffPairsGrid->PopEventHandler( true );
129
130 m_Frame->Unbind( EDA_EVT_UNITS_CHANGED, &PANEL_SETUP_TRACKS_AND_VIAS::onUnitsChanged, this );
131}
132
133
135{
136 if( m_trackWidthsGrid->GetNumberRows() < 2 )
137 return;
138
139 std::vector<int> trackWidths;
140 wxString msg;
141
142 m_trackWidthsGrid->ClearSelection();
143 wxSafeYield();
144
145 wxGridUpdateLocker lock( m_trackWidthsGrid );
146
147 for( int row = 0; row < m_trackWidthsGrid->GetNumberRows(); ++row )
148 {
149 msg = m_trackWidthsGrid->GetCellValue( row, TR_WIDTH_COL );
150
151 if( !msg.IsEmpty() )
152 trackWidths.push_back( m_Frame->ValueFromString( msg ) );
153 }
154
155 std::sort( trackWidths.begin(), trackWidths.end() );
156 m_trackWidthsGrid->ClearRows( false );
157
158 for( int width : trackWidths )
159 AppendTrackWidth( width );
160}
161
162
164{
165 if( m_viaSizesGrid->GetNumberRows() < 2 )
166 return;
167
168 std::vector<VIA_DIMENSION> vias;
169 wxString msg;
170
171 m_viaSizesGrid->ClearSelection();
172 wxSafeYield();
173
174 wxGridUpdateLocker lock( m_viaSizesGrid );
175
176 for( int row = 0; row < m_viaSizesGrid->GetNumberRows(); ++row )
177 {
178 msg = m_viaSizesGrid->GetCellValue( row, VIA_SIZE_COL );
179
180 if( !msg.IsEmpty() )
181 {
182 VIA_DIMENSION via_dim;
183 via_dim.m_Diameter = m_Frame->ValueFromString( msg );
184
185 msg = m_viaSizesGrid->GetCellValue( row, VIA_DRILL_COL );
186
187 if( !msg.IsEmpty() )
188 via_dim.m_Drill = m_Frame->ValueFromString( msg );
189
190 vias.push_back( via_dim );
191 }
192 }
193
194 std::sort( vias.begin(), vias.end() );
195 m_viaSizesGrid->ClearRows( false );
196
197 for( const VIA_DIMENSION& via : vias )
198 AppendViaSize( via.m_Diameter, via.m_Drill );
199}
200
201
203{
204 if( m_diffPairsGrid->GetNumberRows() < 2 )
205 return;
206
207 wxString msg;
208 std::vector<DIFF_PAIR_DIMENSION> diffPairs;
209
210 m_diffPairsGrid->ClearSelection();
211 wxSafeYield();
212
213 wxGridUpdateLocker lock( m_diffPairsGrid );
214
215 for( int row = 0; row < m_diffPairsGrid->GetNumberRows(); ++row )
216 {
217 msg = m_diffPairsGrid->GetCellValue( row, DP_WIDTH_COL );
218
219 if( !msg.IsEmpty() )
220 {
221 DIFF_PAIR_DIMENSION diffPair_dim;
222 diffPair_dim.m_Width = m_Frame->ValueFromString( msg );
223
224 msg = m_diffPairsGrid->GetCellValue( row, DP_GAP_COL );
225 diffPair_dim.m_Gap = m_Frame->ValueFromString( msg );
226
227 msg = m_diffPairsGrid->GetCellValue( row, DP_VIA_GAP_COL );
228
229 if( !msg.IsEmpty() )
230 diffPair_dim.m_ViaGap = m_Frame->ValueFromString( msg );
231
232 diffPairs.push_back( diffPair_dim );
233 }
234 }
235
236 std::sort( diffPairs.begin(), diffPairs.end() );
237 m_diffPairsGrid->ClearRows( false );
238
239 for( const DIFF_PAIR_DIMENSION& dp : diffPairs )
240 AppendDiffPairs( dp.m_Width, dp.m_Gap, dp.m_ViaGap );
241}
242
243
245{
246 BOARD_DESIGN_SETTINGS tempBDS( nullptr, "dummy" );
248
249 m_BrdSettings = &tempBDS; // No, address of stack var does not escape function
250
253
254 m_BrdSettings = saveBDS;
255
256 aEvent.Skip();
257}
258
259
261{
262 m_trackWidthsGrid->ClearRows();
263 m_viaSizesGrid->ClearRows();
264 m_diffPairsGrid->ClearRows();
265
266 // Skip the first item, which is the current netclass value
267 for( unsigned ii = 1; ii < m_BrdSettings->m_TrackWidthList.size(); ii++ )
268 {
269 AppendTrackWidth( m_BrdSettings->m_TrackWidthList[ii] );
270 }
271
272 // Skip the first item, which is the current netclass value
273 for( unsigned ii = 1; ii < m_BrdSettings->m_ViasDimensionsList.size(); ii++ )
274 {
275 AppendViaSize( m_BrdSettings->m_ViasDimensionsList[ii].m_Diameter,
276 m_BrdSettings->m_ViasDimensionsList[ii].m_Drill );
277 }
278
279 // Skip the first item, which is the current netclass value
280 for( unsigned ii = 1; ii < m_BrdSettings->m_DiffPairDimensionsList.size(); ii++ )
281 {
282 AppendDiffPairs( m_BrdSettings->m_DiffPairDimensionsList[ii].m_Width,
283 m_BrdSettings->m_DiffPairDimensionsList[ii].m_Gap,
284 m_BrdSettings->m_DiffPairDimensionsList[ii].m_ViaGap );
285 }
286
287 return true;
288}
289
290
292{
293 if( !commitPendingChanges() )
294 return false;
295
296 std::vector<int> trackWidths;
297 std::vector<VIA_DIMENSION> vias;
298 std::vector<DIFF_PAIR_DIMENSION> diffPairs;
299
300 // Test ONLY for malformed data. Design rules and constraints are the business of DRC.
301
302 for( int row = 0; row < m_trackWidthsGrid->GetNumberRows(); ++row )
303 {
304 if( !m_trackWidthsGrid->GetCellValue( row, TR_WIDTH_COL ).IsEmpty() )
305 trackWidths.push_back( m_trackWidthsGrid->GetUnitValue( row, TR_WIDTH_COL ) );
306 }
307
308 for( int row = 0; row < m_viaSizesGrid->GetNumberRows(); ++row )
309 {
310 if( !m_viaSizesGrid->GetCellValue( row, VIA_SIZE_COL ).IsEmpty() )
311 {
312 VIA_DIMENSION via_dim;
313 via_dim.m_Diameter = m_viaSizesGrid->GetUnitValue( row, VIA_SIZE_COL );
314
315 if( !m_viaSizesGrid->GetCellValue( row, VIA_DRILL_COL ).IsEmpty() )
316 via_dim.m_Drill = m_viaSizesGrid->GetUnitValue( row, VIA_DRILL_COL );
317
318 vias.push_back( via_dim );
319 }
320 }
321
322 for( int row = 0; row < m_diffPairsGrid->GetNumberRows(); ++row )
323 {
324 if( !m_diffPairsGrid->GetCellValue( row, DP_WIDTH_COL ).IsEmpty() )
325 {
326 DIFF_PAIR_DIMENSION diffPair_dim;
327 diffPair_dim.m_Width = m_diffPairsGrid->GetUnitValue( row, DP_WIDTH_COL );
328
329 if( !m_diffPairsGrid->GetCellValue( row, DP_GAP_COL ).IsEmpty() )
330 diffPair_dim.m_Gap = m_diffPairsGrid->GetUnitValue( row, DP_GAP_COL );
331
332 if( !m_diffPairsGrid->GetCellValue( row, DP_VIA_GAP_COL ).IsEmpty() )
333 diffPair_dim.m_ViaGap = m_diffPairsGrid->GetUnitValue( row, DP_VIA_GAP_COL );
334
335 diffPairs.push_back( diffPair_dim );
336 }
337 }
338
339 // Sort lists by increasing value
340 sort( trackWidths.begin(), trackWidths.end() );
341 sort( vias.begin(), vias.end() );
342 sort( diffPairs.begin(), diffPairs.end() );
343
344 // These are all stored in project file, not board, so no need for OnModify()
345
346 trackWidths.insert( trackWidths.begin(), 0 ); // dummy value for "use netclass"
347 m_BrdSettings->m_TrackWidthList = trackWidths;
348
349 vias.insert( vias.begin(), { 0, 0 } ); // dummy value for "use netclass"
350 m_BrdSettings->m_ViasDimensionsList = vias;
351
352 diffPairs.insert( diffPairs.begin(), { 0, 0, 0 } ); // dummy value for "use netclass"
353 m_BrdSettings->m_DiffPairDimensionsList = diffPairs;
354
355 return true;
356}
357
358
360{
361 return m_trackWidthsGrid->CommitPendingChanges( aQuietMode )
362 && m_viaSizesGrid->CommitPendingChanges( aQuietMode )
363 && m_diffPairsGrid->CommitPendingChanges( aQuietMode );
364}
365
366
368{
369 if( !commitPendingChanges() )
370 return false;
371
372 wxString msg;
373
374 // Test vias
375 for( int row = 0; row < m_viaSizesGrid->GetNumberRows(); ++row )
376 {
377 wxString viaDia = m_viaSizesGrid->GetCellValue( row, VIA_SIZE_COL );
378 wxString viaDrill = m_viaSizesGrid->GetCellValue( row, VIA_DRILL_COL );
379
380 std::optional<int> viaDiameter;
381
382 if( !viaDia.IsEmpty() )
383 viaDiameter = m_viaSizesGrid->GetUnitValue( row, VIA_SIZE_COL );
384
385 std::optional<int> viaDrillSize;
386
387 if( !viaDrill.IsEmpty() )
388 viaDrillSize = m_viaSizesGrid->GetUnitValue( row, VIA_DRILL_COL );
389
390 if( std::optional<PCB_VIA::VIA_PARAMETER_ERROR> error =
391 PCB_VIA::ValidateViaParameters( viaDiameter, viaDrillSize,
392 std::nullopt, // primary start layer
393 std::nullopt, // primary end layer
394 std::nullopt, // secondary drill
395 std::nullopt, // secondary start layer
396 std::nullopt, // secondary end layer
397 std::nullopt, // tertiary drill
398 std::nullopt, // tertiary start layer
399 std::nullopt, // tertiary end layer
400 m_Pcb ? m_Pcb->GetCopperLayerCount() : 0 ) )
401 {
402 msg = error->m_Message;
403
404 int errorCol = VIA_SIZE_COL;
405
406 if( error->m_Field == PCB_VIA::VIA_PARAMETER_ERROR::FIELD::DRILL )
407 errorCol = VIA_DRILL_COL;
408
409 PAGED_DIALOG::GetDialog( this )->SetError( msg, this, m_viaSizesGrid, row, errorCol );
410 return false;
411 }
412 }
413
414 // Test diff pairs using backend validation.
415 BOARD_DESIGN_SETTINGS tempSettings( *m_BrdSettings );
416
417 tempSettings.m_DiffPairDimensionsList.clear();
418 tempSettings.m_DiffPairDimensionsList.emplace_back( 0, 0, 0 );
419
420 for( int row = 0; row < m_diffPairsGrid->GetNumberRows(); ++row )
421 {
422 if( !m_diffPairsGrid->GetCellValue( row, DP_WIDTH_COL ).IsEmpty() )
423 {
424 DIFF_PAIR_DIMENSION diffPair;
425
426 diffPair.m_Width = m_diffPairsGrid->GetUnitValue( row, DP_WIDTH_COL );
427
428 if( !m_diffPairsGrid->GetCellValue( row, DP_GAP_COL ).IsEmpty() )
429 diffPair.m_Gap = m_diffPairsGrid->GetUnitValue( row, DP_GAP_COL );
430
431 if( !m_diffPairsGrid->GetCellValue( row, DP_VIA_GAP_COL ).IsEmpty() )
432 diffPair.m_ViaGap = m_diffPairsGrid->GetUnitValue( row, DP_VIA_GAP_COL );
433
434 tempSettings.m_DiffPairDimensionsList.push_back( diffPair );
435 }
436 }
437
438 const wxString diffPairPrefix = wxS( "diff_pair_dimensions_list[" );
439
441 tempSettings.ValidateDesignRules( m_Frame->GetUserUnits() ) )
442 {
443 if( !error.setting_name.StartsWith( diffPairPrefix ) )
444 continue;
445
446 wxString remainder = error.setting_name.Mid( diffPairPrefix.length() );
447 long listIndex = -1;
448
449 if( !remainder.BeforeFirst( ']' ).ToLong( &listIndex ) || listIndex <= 0 )
450 {
451 PAGED_DIALOG::GetDialog( this )->SetError( error.error_message, this, m_diffPairsGrid );
452 return false;
453 }
454
455 int row = static_cast<int>( listIndex ) - 1;
456 int col = DP_GAP_COL;
457
458 if( error.setting_name.EndsWith( wxS( ".width" ) ) )
459 col = DP_WIDTH_COL;
460 else if( error.setting_name.EndsWith( wxS( ".via_gap" ) ) )
461 col = DP_VIA_GAP_COL;
462
463 if( row >= 0 && row < m_diffPairsGrid->GetNumberRows() )
464 PAGED_DIALOG::GetDialog( this )->SetError( error.error_message, this, m_diffPairsGrid, row, col );
465 else
466 PAGED_DIALOG::GetDialog( this )->SetError( error.error_message, this, m_diffPairsGrid );
467
468 return false;
469 }
470
471 return true;
472}
473
474
476{
477 int i = m_trackWidthsGrid->GetNumberRows();
478
479 m_trackWidthsGrid->AppendRows( 1 );
480
481 m_trackWidthsGrid->SetUnitValue( i, TR_WIDTH_COL, aWidth );
482}
483
484
486{
487 int i = m_viaSizesGrid->GetNumberRows();
488
489 m_viaSizesGrid->AppendRows( 1 );
490
491 m_viaSizesGrid->SetUnitValue( i, VIA_SIZE_COL, aSize );
492
493 if( aDrill > 0 )
494 m_viaSizesGrid->SetUnitValue( i, VIA_DRILL_COL, aDrill );
495}
496
497
498void PANEL_SETUP_TRACKS_AND_VIAS::AppendDiffPairs( int aWidth, int aGap, int aViaGap )
499{
500 int i = m_diffPairsGrid->GetNumberRows();
501
502 m_diffPairsGrid->AppendRows( 1 );
503
504 m_diffPairsGrid->SetUnitValue( i, DP_WIDTH_COL, aWidth );
505
506 if( aGap > 0 )
507 m_diffPairsGrid->SetUnitValue( i, DP_GAP_COL, aGap );
508
509 if( aViaGap > 0 )
510 m_diffPairsGrid->SetUnitValue( i, DP_VIA_GAP_COL, aViaGap );
511}
512
513
515{
516 m_trackWidthsGrid->OnAddRow(
517 [&]() -> std::pair<int, int>
518 {
519 AppendTrackWidth( 0 );
520 return { m_trackWidthsGrid->GetNumberRows() - 1, TR_WIDTH_COL };
521 } );
522}
523
524
526{
527 m_trackWidthsGrid->OnDeleteRows(
528 [&]( int row )
529 {
530 m_trackWidthsGrid->DeleteRows( row, 1 );
531 } );
532}
533
534
536{
537 m_viaSizesGrid->OnAddRow(
538 [&]() -> std::pair<int, int>
539 {
540 AppendViaSize( 0, 0 );
541 return { m_viaSizesGrid->GetNumberRows() - 1, VIA_SIZE_COL };
542 } );
543}
544
545
547{
548 m_viaSizesGrid->OnDeleteRows(
549 [&]( int row )
550 {
551 m_viaSizesGrid->DeleteRows( row, 1 );
552 } );
553}
554
555
557{
558 m_diffPairsGrid->OnAddRow(
559 [&]() -> std::pair<int, int>
560 {
561 AppendDiffPairs( 0, 0, 0 );
562 return { m_diffPairsGrid->GetNumberRows() - 1, DP_WIDTH_COL };
563 } );
564}
565
566
568{
569 m_diffPairsGrid->OnDeleteRows(
570 [&]( int row )
571 {
572 m_diffPairsGrid->DeleteRows( row, 1 );
573 } );
574}
575
576
578{
579 commitPendingChanges( true );
580
581 // Note: do not change the board, as we need to get the current nets from it for
582 // netclass memberships. All the netclass definitions and dimension lists are in
583 // the BOARD_DESIGN_SETTINGS.
584
585 BOARD_DESIGN_SETTINGS* savedSettings = m_BrdSettings;
586
587 m_BrdSettings = &aBoard->GetDesignSettings();
589
590 m_BrdSettings = savedSettings;
591}
592
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:106
@ small_sort_desc
Container for design settings for a BOARD object.
std::vector< DIFF_PAIR_DIMENSION > m_DiffPairDimensionsList
std::vector< VALIDATION_ERROR > ValidateDesignRules(std::optional< EDA_UNITS > aUnits=std::nullopt) const
Validate design settings values and return per-field errors.
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:372
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition board.cpp:1149
Add mouse and command handling (such as cut, copy, and paste) to a WX_GRID instance.
Definition grid_tricks.h:57
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 > aPrimaryDrill, std::optional< PCB_LAYER_ID > aPrimaryStartLayer=std::nullopt, std::optional< PCB_LAYER_ID > aPrimaryEndLayer=std::nullopt, std::optional< int > aSecondaryDrill=std::nullopt, std::optional< PCB_LAYER_ID > aSecondaryStartLayer=std::nullopt, std::optional< PCB_LAYER_ID > aSecondaryEndLayer=std::nullopt, std::optional< int > aTertiaryDrill=std::nullopt, std::optional< PCB_LAYER_ID > aTertiaryStartLayer=std::nullopt, std::optional< PCB_LAYER_ID > aTertiaryEndLayer=std::nullopt, int aCopperLayerCount=0)
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:982
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...