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