KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pcb_net_inspector_panel.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 modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
22
23#include <advanced_config.h>
25#include <confirm.h>
28#include <footprint.h>
31#include <pad.h>
32#include <pcb_edit_frame.h>
33#include <pcb_painter.h>
34#include <pgm_base.h>
36#include <validators.h>
38#include <eda_pattern_match.h>
39
40#include <wx/wupdlock.h>
41#include <wx/filedlg.h>
42
43#include <algorithm>
44#include <thread_pool.h>
45
47 NET_INSPECTOR_PANEL( parent, aFrame ),
48 m_frame( aFrame ),
49 m_dataModel( new DATA_MODEL( *this ) )
50{
52
53 m_netsList->AssociateModel( &*m_dataModel );
54
55 // Rebuild nets list
56 buildNetsList( true );
57
58 // Register the panel to receive board change notifications
59 if( m_board != nullptr )
60 {
62 m_board->AddListener( this );
63 }
64
65 // Connect to board events
66 m_frame->Bind( EDA_EVT_UNITS_CHANGED, &PCB_NET_INSPECTOR_PANEL::onUnitsChanged, this );
67
68 // Connect to wxDataViewCtrl events
69 m_netsList->Bind( wxEVT_DATAVIEW_ITEM_EXPANDED, &PCB_NET_INSPECTOR_PANEL::OnExpandCollapseRow, this );
70 m_netsList->Bind( wxEVT_DATAVIEW_ITEM_COLLAPSED, &PCB_NET_INSPECTOR_PANEL::OnExpandCollapseRow, this );
71 m_netsList->Bind( wxEVT_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK, &PCB_NET_INSPECTOR_PANEL::OnHeaderContextMenu, this );
72 m_netsList->Bind( wxEVT_DATAVIEW_ITEM_CONTEXT_MENU, &PCB_NET_INSPECTOR_PANEL::OnNetsListContextMenu, this );
73 m_netsList->Bind( wxEVT_DATAVIEW_ITEM_ACTIVATED, &PCB_NET_INSPECTOR_PANEL::OnNetsListItemActivated, this );
74 m_netsList->Bind( wxEVT_DATAVIEW_COLUMN_SORTED, &PCB_NET_INSPECTOR_PANEL::OnColumnSorted, this );
75}
76
78{
80
81 m_netsList->AssociateModel( nullptr );
82
83 // Disconnect from board events
84 m_frame->Unbind( EDA_EVT_UNITS_CHANGED, &PCB_NET_INSPECTOR_PANEL::onUnitsChanged, this );
85
86 // Connect to wxDataViewCtrl events
87 m_netsList->Unbind( wxEVT_DATAVIEW_ITEM_EXPANDED, &PCB_NET_INSPECTOR_PANEL::OnExpandCollapseRow, this );
88 m_netsList->Unbind( wxEVT_DATAVIEW_ITEM_COLLAPSED, &PCB_NET_INSPECTOR_PANEL::OnExpandCollapseRow, this );
89 m_netsList->Unbind( wxEVT_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK, &PCB_NET_INSPECTOR_PANEL::OnHeaderContextMenu, this );
90 m_netsList->Unbind( wxEVT_DATAVIEW_ITEM_CONTEXT_MENU, &PCB_NET_INSPECTOR_PANEL::OnNetsListContextMenu, this );
91 m_netsList->Unbind( wxEVT_DATAVIEW_ITEM_ACTIVATED, &PCB_NET_INSPECTOR_PANEL::OnNetsListItemActivated, this );
92 m_netsList->Unbind( wxEVT_DATAVIEW_COLUMN_SORTED, &PCB_NET_INSPECTOR_PANEL::OnColumnSorted, this );
93}
94
95
96/*****************************************************************************************
97 *
98 * Grid / model columns configuration
99 *
100 * ***************************************************************************************/
101
102
104{
105 m_columns.clear();
106
107 // Set up the column display vector
108 m_columns.emplace_back( 0u, UNDEFINED_LAYER, _( "Name" ), _( "Net Name" ), CSV_COLUMN_DESC::CSV_QUOTE, false );
109 m_columns.emplace_back( 1u, UNDEFINED_LAYER, _( "Netclass" ), _( "Netclass" ), CSV_COLUMN_DESC::CSV_QUOTE, false );
110
112 {
113 m_columns.emplace_back( 2u, UNDEFINED_LAYER, _( "Total Delay" ), _( "Net Delay" ), CSV_COLUMN_DESC::CSV_NONE,
114 true );
115 }
116 else
117 {
118 m_columns.emplace_back( 2u, UNDEFINED_LAYER, _( "Total Length" ), _( "Net Length" ), CSV_COLUMN_DESC::CSV_NONE,
119 true );
120 }
121
122 m_columns.emplace_back( 3u, UNDEFINED_LAYER, _( "Via Count" ), _( "Via Count" ), CSV_COLUMN_DESC::CSV_NONE, false );
123
125 {
126 m_columns.emplace_back( 4u, UNDEFINED_LAYER, _( "Via Delay" ), _( "Via Delay" ), CSV_COLUMN_DESC::CSV_NONE,
127 true );
128 m_columns.emplace_back( 5u, UNDEFINED_LAYER, _( "Track Delay" ), _( "Track Delay" ), CSV_COLUMN_DESC::CSV_NONE,
129 true );
130 m_columns.emplace_back( 6u, UNDEFINED_LAYER, _( "Die Delay" ), _( "Die Delay" ), CSV_COLUMN_DESC::CSV_NONE,
131 true );
132 }
133 else
134 {
135 m_columns.emplace_back( 4u, UNDEFINED_LAYER, _( "Via Length" ), _( "Via Length" ), CSV_COLUMN_DESC::CSV_NONE,
136 true );
137 m_columns.emplace_back( 5u, UNDEFINED_LAYER, _( "Track Length" ), _( "Track Length" ),
139 m_columns.emplace_back( 6u, UNDEFINED_LAYER, _( "Die Length" ), _( "Die Length" ), CSV_COLUMN_DESC::CSV_NONE,
140 true );
141 }
142
143 m_columns.emplace_back( 7u, UNDEFINED_LAYER, _( "Pad Count" ), _( "Pad Count" ), CSV_COLUMN_DESC::CSV_NONE, false );
144
145 const std::vector<std::function<void( void )>> add_col{
146 [&]()
147 {
148 m_netsList->AppendTextColumn( m_columns[COLUMN_NAME].display_name, m_columns[COLUMN_NAME],
149 wxDATAVIEW_CELL_INERT, -1, wxALIGN_LEFT,
150 wxDATAVIEW_COL_RESIZABLE|wxDATAVIEW_COL_SORTABLE );
151 },
152 [&]()
153 {
154 m_netsList->AppendTextColumn( m_columns[COLUMN_NETCLASS].display_name, m_columns[COLUMN_NETCLASS],
155 wxDATAVIEW_CELL_INERT, -1, wxALIGN_LEFT,
156 wxDATAVIEW_COL_RESIZABLE|wxDATAVIEW_COL_REORDERABLE|wxDATAVIEW_COL_SORTABLE );
157 },
158 [&]()
159 {
160 m_netsList->AppendTextColumn( m_columns[COLUMN_TOTAL_LENGTH].display_name, m_columns[COLUMN_TOTAL_LENGTH],
161 wxDATAVIEW_CELL_INERT, -1, wxALIGN_CENTER,
162 wxDATAVIEW_COL_RESIZABLE|wxDATAVIEW_COL_REORDERABLE|wxDATAVIEW_COL_SORTABLE );
163 },
164 [&]()
165 {
166 m_netsList->AppendTextColumn( m_columns[COLUMN_VIA_COUNT].display_name, m_columns[COLUMN_VIA_COUNT],
167 wxDATAVIEW_CELL_INERT, -1, wxALIGN_CENTER,
168 wxDATAVIEW_COL_RESIZABLE|wxDATAVIEW_COL_REORDERABLE|wxDATAVIEW_COL_SORTABLE );
169 },
170 [&]()
171 {
172 m_netsList->AppendTextColumn( m_columns[COLUMN_VIA_LENGTH].display_name, m_columns[COLUMN_VIA_LENGTH],
173 wxDATAVIEW_CELL_INERT, -1, wxALIGN_CENTER,
174 wxDATAVIEW_COL_RESIZABLE|wxDATAVIEW_COL_REORDERABLE|wxDATAVIEW_COL_SORTABLE );
175 },
176 [&]()
177 {
178 m_netsList->AppendTextColumn( m_columns[COLUMN_BOARD_LENGTH].display_name, m_columns[COLUMN_BOARD_LENGTH],
179 wxDATAVIEW_CELL_INERT, -1, wxALIGN_CENTER,
180 wxDATAVIEW_COL_RESIZABLE|wxDATAVIEW_COL_REORDERABLE|wxDATAVIEW_COL_SORTABLE );
181 },
182 [&]()
183 {
184 m_netsList->AppendTextColumn( m_columns[COLUMN_PAD_DIE_LENGTH].display_name,
185 m_columns[COLUMN_PAD_DIE_LENGTH], wxDATAVIEW_CELL_INERT, -1, wxALIGN_CENTER,
186 wxDATAVIEW_COL_RESIZABLE|wxDATAVIEW_COL_REORDERABLE|wxDATAVIEW_COL_SORTABLE );
187 },
188 [&]()
189 {
190 m_netsList->AppendTextColumn( m_columns[COLUMN_PAD_COUNT].display_name, m_columns[COLUMN_PAD_COUNT],
191 wxDATAVIEW_CELL_INERT, -1, wxALIGN_CENTER,
192 wxDATAVIEW_COL_RESIZABLE|wxDATAVIEW_COL_REORDERABLE|wxDATAVIEW_COL_SORTABLE );
193 }
194 };
195
196 // If we have not yet loaded the first board, use a dummy local settings object to ensure we
197 // don't over-write existing board settings (note that PCB_EDIT_FRAME loads the local settings
198 // object prior to loading the board; the two are not synced and we need to account for that)
199 PANEL_NET_INSPECTOR_SETTINGS* cfg = nullptr;
200
201 if( m_boardLoaded )
202 {
204 cfg = &localSettings.m_NetInspectorPanel;
205 }
206 else
207 {
209 }
210
211 // Reset the column display settings if column count doesn't match
212 const int totalNumColumns = (int) add_col.size() + m_board->GetCopperLayerCount();
213
214 if( (int) cfg->col_order.size() != totalNumColumns
215 || (int) cfg->col_hidden.size() != totalNumColumns )
216 {
217 cfg->col_order.resize( totalNumColumns );
218 cfg->col_hidden.resize( totalNumColumns );
219
220 for( int i = 0; i < totalNumColumns; ++i )
221 {
222 cfg->col_order[i] = i;
223 cfg->col_hidden[i] = false;
224 }
225 }
226
227 // Check that all rows are unique to protect against corrupted settings data
228 std::set<int> col_order_set( cfg->col_order.begin(), cfg->col_order.end() );
229 if( col_order_set.size() != cfg->col_order.size() )
230 {
231 for( std::size_t i = 0; i < cfg->col_order.size(); ++i )
232 cfg->col_order[i] = static_cast<int>( i );
233 }
234
235 // Add column records for copper layers
236 for( PCB_LAYER_ID layer : m_board->GetEnabledLayers().Seq() )
237 {
238 if( !IsCopperLayer( layer ) )
239 continue;
240
241 m_columns.emplace_back( m_columns.size(), layer, m_board->GetLayerName( layer ), m_board->GetLayerName( layer ),
243 }
244
245 // Add display columns in settings order
246 for( const int i : cfg->col_order )
247 {
248 const int addModelColumn = i;
249
250 if( addModelColumn >= (int) add_col.size() )
251 {
252 m_netsList->AppendTextColumn( m_board->GetLayerName( m_columns[addModelColumn].layer ),
253 m_columns[addModelColumn], wxDATAVIEW_CELL_INERT, -1, wxALIGN_CENTER,
254 wxDATAVIEW_COL_RESIZABLE|wxDATAVIEW_COL_REORDERABLE|wxDATAVIEW_COL_SORTABLE );
255 }
256 else
257 {
258 add_col.at( i )();
259 }
260 }
261
262 // Set the name column as the expander row
263 if( wxDataViewColumn* col = getDisplayedColumnForModelField( COLUMN_NAME ) )
264 {
265 m_netsList->SetExpanderColumn( col );
266 }
267
269
270 // Delete the temporary config if used
271 if( !m_boardLoaded )
272 delete cfg;
273}
274
275
277{
278 wxWindowUpdateLocker locker( m_netsList );
279
280 if( cfg->col_widths.size() != m_columns.size() )
281 {
282 int minValueWidth = GetTextExtent( wxT( "00000,000 mm" ) ).x;
283 int minNumberWidth = GetTextExtent( wxT( "000" ) ).x;
284 int minNameWidth = GetTextExtent( wxT( "MMMMMMMMMMMM" ) ).x;
285
286 // Considering left and right margins.
287 // For wxRenderGeneric it is 5px.
288 // Also account for the sorting arrow in the column header.
289 // Column 0 also needs space for any potential expander icons.
290 constexpr int margins = 15;
291 constexpr int extra_width = 30;
292
293 auto getTargetWidth =
294 [&]( int columnID )
295 {
296 switch( columnID )
297 {
298 case COLUMN_NAME: return minNameWidth + extra_width;
299 case COLUMN_NETCLASS: return minNameWidth + margins;
300 case COLUMN_VIA_COUNT: return minNumberWidth + margins;
301 case COLUMN_PAD_COUNT: return minNumberWidth + margins;
302 default: return minValueWidth + margins;
303 }
304 };
305
306 wxASSERT( m_columns.size() == cfg->col_order.size() );
307
308 for( size_t i = 0; i < m_columns.size(); ++i )
309 {
310 const int modelColumn = cfg->col_order[i];
311 int titleSize = GetTextExtent( m_columns[modelColumn].display_name ).x;
312 titleSize = modelColumn == COLUMN_NAME ? titleSize + extra_width : titleSize + margins;
313 const int valSize = getTargetWidth( modelColumn );
314 m_netsList->GetColumn( i )->SetWidth( std::max( titleSize, valSize ) );
315 }
316 }
317 else
318 {
319 wxASSERT( m_columns.size() == cfg->col_hidden.size() );
320 wxASSERT( m_columns.size() == cfg->col_widths.size() );
321
322 for( size_t ii = 0; ii < m_columns.size(); ++ii )
323 {
324 const int newWidth = cfg->col_widths[ii];
325 // Make sure we end up with something non-zero so we can resize it
326 m_netsList->GetColumn( ii )->SetWidth( std::max( newWidth, 10 ) );
327 m_netsList->GetColumn( ii )->SetHidden( cfg->col_hidden[ii] );
328 }
329 }
330
331 m_netsList->Refresh();
332}
333
334
335bool PCB_NET_INSPECTOR_PANEL::restoreSortColumn( const int sortingColumnId, const bool sortOrderAsc ) const
336{
337 if( sortingColumnId != -1 )
338 {
339 if( wxDataViewColumn* col = getDisplayedColumnForModelField( sortingColumnId ) )
340 {
341 col->SetSortOrder( sortOrderAsc );
342 m_dataModel->Resort();
343 return true;
344 }
345 }
346
347 return false;
348}
349
350
351wxDataViewColumn* PCB_NET_INSPECTOR_PANEL::getDisplayedColumnForModelField( const int columnId ) const
352{
353 for( unsigned int i = 0; i < m_netsList->GetColumnCount(); ++i )
354 {
355 wxDataViewColumn* col = m_netsList->GetColumn( i );
356
357 if( static_cast<int>( col->GetModelColumn() ) == columnId )
358 return col;
359 }
360
361 return nullptr;
362}
363
364
365/*****************************************************************************************
366 *
367 * Nets list generation
368 *
369 * ***************************************************************************************/
370
371
372void PCB_NET_INSPECTOR_PANEL::buildNetsList( const bool rebuildColumns )
373{
374 // Only build the list of nets if there is a board present
375 if( !m_board )
376 return;
377
378 m_inBuildNetsList = true;
379
380 m_netsList->Freeze();
381
382 m_dataModel->SetIsTimeDomain( m_showTimeDomainDetails );
383
386
387 // Refresh all filtering / grouping settings
394
395 // Attempt to keep any expanded groups open
397 {
398 cfg->expanded_rows.clear();
399 DATA_MODEL* model = static_cast<DATA_MODEL*>( m_netsList->GetModel() );
400
401 for( const auto& groupItems = model->getGroupDataViewItems();
402 auto& [groupName, groupItem] : groupItems )
403 {
404 if( m_netsList->IsExpanded( groupItem ) )
405 cfg->expanded_rows.push_back( groupName );
406 }
407 }
408
409 // When rebuilding the netlist, try to keep the row selection
410 wxDataViewItemArray sel;
411 m_netsList->GetSelections( sel );
412
413 std::vector<int> prev_selected_netcodes;
414 prev_selected_netcodes.reserve( sel.GetCount() );
415
416 for( unsigned int i = 0; i < sel.GetCount(); ++i )
417 {
418 const LIST_ITEM* item = static_cast<const LIST_ITEM*>( sel.Item( i ).GetID() );
419 prev_selected_netcodes.push_back( item->GetNetCode() );
420 }
421
422 int sorting_column_id = cfg->sorting_column;
423 bool sort_order_asc = cfg->sort_order_asc;
424
425 if( wxDataViewColumn* sorting_column = m_netsList->GetSortingColumn() )
426 {
427 if( !m_boardLoading )
428 {
429 sorting_column_id = static_cast<int>( sorting_column->GetModelColumn() );
430 sort_order_asc = sorting_column->IsSortOrderAscending();
431 }
432
433 // On GTK, wxDVC will crash if we rebuild with a sorting column set.
434 sorting_column->UnsetAsSortKey();
435 }
436
437 if( rebuildColumns )
438 {
439 m_netsList->ClearColumns();
440 buildColumns();
441 }
442
443 m_dataModel->deleteAllItems();
444 m_custom_group_rules.clear();
445
446 for( const wxString& rule : cfg->custom_group_rules )
447 m_custom_group_rules.push_back( std::make_unique<EDA_COMBINED_MATCHER>( rule, CTX_NET ) );
448
449 m_dataModel->addCustomGroups();
450
451 std::vector<NETINFO_ITEM*> netCodes;
452
453 for( NETINFO_ITEM* ni : m_board->GetNetInfo() )
454 {
455 if( netFilterMatches( ni, cfg ) )
456 netCodes.emplace_back( ni );
457 }
458
459 std::ranges::sort( netCodes,
460 []( const NETINFO_ITEM* a, const NETINFO_ITEM* b )
461 {
462 return a->GetNetCode() < b->GetNetCode();
463 } );
464
465 std::vector<std::unique_ptr<LIST_ITEM>> lengths = calculateNets( netCodes, m_showZeroPadNets );
466
467 m_dataModel->addItems( lengths );
468
469 // Try to re-enable the sorting column
470 if( !restoreSortColumn( sorting_column_id, sort_order_asc ))
471 {
472 // By default, sort by Name column
474 }
475
476 // Try to restore the expanded groups
477 if( m_boardLoaded )
478 {
479 m_rowExpanding = true;
480
481 std::vector<std::pair<wxString, wxDataViewItem>> groupItems = m_dataModel->getGroupDataViewItems();
482
483 for( wxString& groupName : cfg->expanded_rows )
484 {
485 auto pred =
486 [&groupName]( const std::pair<wxString, wxDataViewItem>& item )
487 {
488 return groupName == item.first;
489 };
490
491 auto tableItem = std::ranges::find_if( groupItems, pred );
492
493 if( tableItem != groupItems.end() )
494 m_netsList->Expand( tableItem->second );
495 }
496
497 m_rowExpanding = false;
498 }
499
500 // Try to restore the selected rows
501 sel.Clear();
502
503 for( const int& nc : prev_selected_netcodes )
504 {
505 if( std::optional<LIST_ITEM_ITER> r = m_dataModel->findItem( nc ) )
506 {
507 const std::unique_ptr<LIST_ITEM>& list_item = *r.value();
508 sel.Add( wxDataViewItem( list_item.get() ) );
509 }
510 }
511
512 m_netsList->Thaw(); // Must thaw before reselecting to avoid windows selection bug
513
514 if( !sel.IsEmpty() )
515 {
516 m_netsList->SetSelections( sel );
517 m_netsList->EnsureVisible( sel.Item( 0 ) );
518 }
519 else
520 {
521 m_netsList->UnselectAll();
522 }
523
524 m_inBuildNetsList = false;
525}
526
527
530{
531 if( cfg == nullptr )
532 {
534 cfg = &localSettings.m_NetInspectorPanel;
535 }
536
537 // Never show an unconnected net
538 if( aNet->GetNetCode() <= 0 )
539 return false;
540
541 const wxString filterString = UnescapeString( m_searchCtrl->GetValue() ).Upper();
542 const wxString netName = UnescapeString( aNet->GetNetname() ).Upper();
543 const NETCLASS* netClass = aNet->GetNetClass();
544 const wxString netClassName = UnescapeString( netClass->GetName() ).Upper();
545
546 bool matched = false;
547
548 // No filter - match all
549 if( filterString.Length() == 0 )
550 matched = true;
551
552 // Search on net class
553 if( !matched && cfg->filter_by_netclass && netClassName.Find( filterString ) != wxNOT_FOUND )
554 matched = true;
555
556 // Search on net name
557 if( !matched && cfg->filter_by_net_name && netName.Find( filterString ) != wxNOT_FOUND )
558 matched = true;
559
560 // Remove unconnected nets if required
561 if( matched )
562 {
564 matched = !netName.StartsWith( wxT( "UNCONNECTED-(" ) );
565 }
566
567 return matched;
568}
569
570
572{
573 bool operator()( const CN_ITEM* a, const CN_ITEM* b ) const { return a->Net() < b->Net(); }
574
575 bool operator()( const CN_ITEM* a, int b ) const { return a->Net() < b; }
576
577 bool operator()( int a, const CN_ITEM* b ) const { return a < b->Net(); }
578};
579
580
582{
583 // Pre-filter the connectivity items and sort them by netcode. This avoids quadratic runtime when building the whole
584 // net list.
585 const auto type_bits = std::bitset<MAX_STRUCT_TYPE_ID>().set( PCB_TRACE_T )
586 .set( PCB_ARC_T )
587 .set( PCB_VIA_T )
588 .set( PCB_PAD_T );
589
590 std::vector<CN_ITEM*> cn_items;
591 cn_items.reserve( 1024 );
592
593 for( CN_ITEM* cn_item : m_board->GetConnectivity()->GetConnectivityAlgo()->ItemList() )
594 {
595 if( cn_item->Valid() && type_bits[cn_item->Parent()->Type()] )
596 cn_items.push_back( cn_item );
597 }
598
599 std::ranges::sort( cn_items, NETCODE_CMP_LESS() );
600
601 return cn_items;
602}
603
604
605std::vector<std::unique_ptr<PCB_NET_INSPECTOR_PANEL::LIST_ITEM>>
606PCB_NET_INSPECTOR_PANEL::calculateNets( const std::vector<NETINFO_ITEM*>& aNetCodes, bool aIncludeZeroPadNets ) const
607{
608 std::vector<std::unique_ptr<LIST_ITEM>> results;
609
611 const std::vector<CN_ITEM*> conItems = relevantConnectivityItems();
612
613 // First assemble the LENGTH_CALCULATION_ITEMs for board items which match the nets we need to recompute
614 // Precondition: conItems and aNetCodes are sorted in increasing netcode value
615 // Functionality: This extracts any items from conItems which have a netcode which is present in aNetCodes
616 std::unordered_map<int, std::vector<LENGTH_DELAY_CALCULATION_ITEM>> netItemsMap;
617 std::vector<NETINFO_ITEM*> foundNets;
618
619 auto itemItr = conItems.begin();
620 auto netCodeItr = aNetCodes.begin();
621
622 while( itemItr != conItems.end() && netCodeItr != aNetCodes.end() )
623 {
624 const int curNetCode = ( *netCodeItr )->GetNetCode();
625 const int curItemNetCode = ( *itemItr )->Net();
626
627 if( curItemNetCode == curNetCode )
628 {
629 if( foundNets.empty() || foundNets.back() != *netCodeItr )
630 foundNets.emplace_back( *netCodeItr );
631
632 // Take the item
633 LENGTH_DELAY_CALCULATION_ITEM lengthItem = calc->GetLengthCalculationItem( ( *itemItr )->Parent() );
634 netItemsMap[curItemNetCode].emplace_back( std::move( lengthItem ) );
635 ++itemItr;
636 }
637 else if( curItemNetCode < curNetCode )
638 {
639 // Fast-forward through items
640 while( itemItr != conItems.end() && ( *itemItr )->Net() < curNetCode )
641 ++itemItr;
642 }
643 else if( curItemNetCode > curNetCode )
644 {
645 // Fast-forward through required net codes
646 while( netCodeItr != aNetCodes.end() && curItemNetCode > ( *netCodeItr )->GetNetCode() )
647 ++netCodeItr;
648 }
649 }
650
651 // Now calculate the length statistics for each net. This includes potentially expensive path optimisations, so
652 // parallelize this work.
653 std::mutex resultsMutex;
655
656 auto resultsFuture = tp.parallelize_loop(
657 0, foundNets.size(),
658 [&, this, calc]( const int start, const int end )
659 {
660 for( int i = start; i < end; ++i )
661 {
662 int netCode = foundNets[i]->GetNetCode();
663
664 constexpr PATH_OPTIMISATIONS opts = { .OptimiseViaLayers = true,
665 .MergeTracks = true,
666 .OptimiseTracesInPads = true,
667 .InferViaInPad = false };
668
669 LENGTH_DELAY_STATS lengthDetails = calc->CalculateLengthDetails(
670 netItemsMap[netCode],
671 opts,
672 nullptr,
673 nullptr,
674 LENGTH_DELAY_LAYER_OPT::WITH_LAYER_DETAIL,
675 m_showTimeDomainDetails ? LENGTH_DELAY_DOMAIN_OPT::WITH_DELAY_DETAIL
676 : LENGTH_DELAY_DOMAIN_OPT::NO_DELAY_DETAIL );
677
678 if( aIncludeZeroPadNets || lengthDetails.NumPads > 0 )
679 {
680 std::unique_ptr<LIST_ITEM> new_item = std::make_unique<LIST_ITEM>( foundNets[i] );
681
682 new_item->SetPadCount( lengthDetails.NumPads );
683 new_item->SetLayerCount( m_board->GetCopperLayerCount() );
684 new_item->SetPadDieLength( lengthDetails.PadToDieLength );
685 new_item->SetPadDieDelay( lengthDetails.PadToDieDelay );
686 new_item->SetViaCount( lengthDetails.NumVias );
687 new_item->SetViaLength( lengthDetails.ViaLength );
688 new_item->SetViaDelay( lengthDetails.ViaDelay );
689 new_item->SetLayerWireLengths( *lengthDetails.LayerLengths );
690
691 if( m_showTimeDomainDetails )
692 new_item->SetLayerWireDelays( *lengthDetails.LayerDelays );
693
694 std::scoped_lock lock( resultsMutex );
695 results.emplace_back( std::move( new_item ) );
696 }
697 }
698 } );
699
700 resultsFuture.get();
701
702 return results;
703}
704
705
706/*****************************************************************************************
707 *
708 * Formatting helpers
709 *
710 * ***************************************************************************************/
711
712
714{
715 return wxString::Format( wxT( "%.3d" ), aNet->GetNetCode() );
716}
717
718
720{
721 return UnescapeString( aNet->GetNetname() );
722}
723
724
725wxString PCB_NET_INSPECTOR_PANEL::formatCount( const unsigned int aValue )
726{
727 return wxString::Format( wxT( "%u" ), aValue );
728}
729
730
731wxString PCB_NET_INSPECTOR_PANEL::formatLength( const int64_t aValue ) const
732{
733 return m_frame->MessageTextFromValue( aValue,
734 // don't include unit label in the string when reporting
735 !m_inReporting );
736}
737
738wxString PCB_NET_INSPECTOR_PANEL::formatDelay( const int64_t aValue ) const
739{
740 return m_frame->MessageTextFromValue( aValue,
741 // don't include unit label in the string when reporting
742 !m_inReporting, EDA_DATA_TYPE::TIME );
743}
744
745
746void PCB_NET_INSPECTOR_PANEL::updateDisplayedRowValues( const std::optional<LIST_ITEM_ITER>& aRow ) const
747{
748 if( !aRow )
749 return;
750
751 wxDataViewItemArray sel;
752 m_netsList->GetSelections( sel );
753
754 m_dataModel->updateItem( aRow );
755
756 if( !sel.IsEmpty() )
757 {
758 m_netsList->SetSelections( sel );
759 m_netsList->EnsureVisible( sel.Item( 0 ) );
760 }
761}
762
763
764/*****************************************************************************************
765 *
766 * BOARD_LISTENER event handling
767 *
768 * ***************************************************************************************/
769
770
772{
774
775 if( m_board )
776 m_board->AddListener( this );
777
778 m_boardLoaded = true;
779 m_boardLoading = true;
780
782 auto& cfg = localSettings.m_NetInspectorPanel;
783 m_searchCtrl->SetValue( cfg.filter_text );
784
785 buildNetsList( true );
786
787 m_boardLoading = false;
788}
789
790
792{
793 const std::vector<BOARD_ITEM*> item{ aBoardItem };
794 updateBoardItems( item );
795}
796
797
798void PCB_NET_INSPECTOR_PANEL::OnBoardItemsAdded( BOARD& aBoard, std::vector<BOARD_ITEM*>& aBoardItems )
799{
800 updateBoardItems( aBoardItems );
801}
802
803
804void PCB_NET_INSPECTOR_PANEL::updateBoardItems( const std::vector<BOARD_ITEM*>& aBoardItems )
805{
806 if( !IsShownOnScreen() )
807 return;
808
809 // Rebuild full list for large changes
810 if( aBoardItems.size()
812 {
814 }
815 else
816 {
817 std::vector<NETINFO_ITEM*> changedNets;
818
819 for( BOARD_ITEM* boardItem : aBoardItems )
820 {
821 if( NETINFO_ITEM* net = dynamic_cast<NETINFO_ITEM*>( boardItem ) )
822 {
823 // A new net has been added to the board. Add it to our list if it passes the netname filter test.
824 if( netFilterMatches( net ) )
825 changedNets.emplace_back( net );
826 }
827 else if( BOARD_CONNECTED_ITEM* i = dynamic_cast<BOARD_CONNECTED_ITEM*>( boardItem ) )
828 {
829 changedNets.emplace_back( i->GetNet() );
830 }
831 else if( FOOTPRINT* footprint = dynamic_cast<FOOTPRINT*>( boardItem ) )
832 {
833 for( const PAD* pad : footprint->Pads() )
834 {
835 if( netFilterMatches( pad->GetNet() ) )
836 changedNets.emplace_back( pad->GetNet() );
837 }
838 }
839 }
840
841 std::ranges::sort( changedNets,
842 []( const NETINFO_ITEM* a, const NETINFO_ITEM* b )
843 {
844 return a->GetNetCode() < b->GetNetCode();
845 } );
846
847 updateNets( changedNets );
848 }
849
850 m_netsList->Refresh();
851}
852
853
854void PCB_NET_INSPECTOR_PANEL::updateNets( const std::vector<NETINFO_ITEM*>& aNets ) const
855{
856 std::vector<NETINFO_ITEM*> netsToUpdate;
857 std::unordered_set<NETINFO_ITEM*> netsToDelete;
858
859 for( NETINFO_ITEM* net : aNets )
860 {
861 // Add all nets to the deletion list - we will prune this later to only contain unhandled nets
862 netsToDelete.insert( net );
863
864 // Only calculate nets that match the current filter
865 if( netFilterMatches( net ) )
866 netsToUpdate.emplace_back( net );
867 }
868
869 wxWindowUpdateLocker updateLocker( m_netsList );
870
871 std::vector<std::unique_ptr<LIST_ITEM>> newListItems = calculateNets( aNets, true );
872
873 for( std::unique_ptr<LIST_ITEM>& newListItem : newListItems )
874 {
875 // Remove the handled net from the deletion list
876 netsToDelete.erase( newListItem->GetNet() );
877
878 std::optional<LIST_ITEM_ITER> curNetRow = m_dataModel->findItem( newListItem->GetNetCode() );
879
880 if( !m_showZeroPadNets && newListItem->GetPadCount() == 0 )
881 {
882 m_dataModel->deleteItem( curNetRow );
883 continue;
884 }
885
886 if( !curNetRow )
887 {
888 m_dataModel->addItem( std::move( newListItem ) );
889 continue;
890 }
891
892 const std::unique_ptr<LIST_ITEM>& curListItem = *curNetRow.value();
893
894 if( curListItem->GetNetName() != newListItem->GetNetName() )
895 {
896 // If the name has changed, it might require re-grouping. It's easier to remove and re-insert it.
897 m_dataModel->deleteItem( curNetRow );
898 m_dataModel->addItem( std::move( newListItem ) );
899 }
900 else
901 {
902 curListItem->SetPadCount( newListItem->GetPadCount() );
903 curListItem->SetPadDieLength( newListItem->GetPadDieLength() );
904 curListItem->SetPadDieDelay( newListItem->GetPadDieDelay() );
905 curListItem->SetViaCount( newListItem->GetViaCount() );
906 curListItem->SetViaLength( newListItem->GetViaLength() );
907 curListItem->SetViaDelay( newListItem->GetViaDelay() );
908 curListItem->SetLayerWireLengths( newListItem->GetLayerWireLengths() );
909
911 curListItem->SetLayerWireDelays( newListItem->GetLayerWireDelays() );
912
913 updateDisplayedRowValues( curNetRow );
914 }
915 }
916
917 // Delete any nets we have not yet handled
918 for( const NETINFO_ITEM* netToDelete : netsToDelete )
919 m_dataModel->deleteItem( m_dataModel->findItem( netToDelete->GetNetCode() ) );
920}
921
922
924{
925 const std::vector<BOARD_ITEM*> item{ aBoardItem };
926 updateBoardItems( item );
927}
928
929
930void PCB_NET_INSPECTOR_PANEL::OnBoardItemsRemoved( BOARD& aBoard, std::vector<BOARD_ITEM*>& aBoardItems )
931{
932 updateBoardItems( aBoardItems );
933}
934
935
937{
938 if( !IsShownOnScreen() )
939 return;
940
942}
943
944
946{
947 const std::vector<BOARD_ITEM*> item{ aBoardItem };
948 updateBoardItems( item );
949}
950
951
952void PCB_NET_INSPECTOR_PANEL::OnBoardItemsChanged( BOARD& aBoard, std::vector<BOARD_ITEM*>& aBoardItems )
953{
954 updateBoardItems( aBoardItems );
955}
956
957
959 std::vector<BOARD_ITEM*>& aAddedItems,
960 std::vector<BOARD_ITEM*>& aRemovedItems,
961 std::vector<BOARD_ITEM*>& aChangedItems )
962{
963 if( !IsShownOnScreen() )
964 return;
965
966 std::vector<BOARD_ITEM*> allItems{ aAddedItems.begin(), aAddedItems.end() };
967 allItems.insert( allItems.end(), aRemovedItems.begin(), aRemovedItems.end() );
968 allItems.insert( allItems.end(), aChangedItems.begin(), aChangedItems.end() );
969 updateBoardItems( allItems );
970}
971
972
974{
975 if( m_highlightingNets || !IsShownOnScreen() )
976 return;
977
978 if( !m_board->IsHighLightNetON() )
979 {
980 m_netsList->UnselectAll();
981 }
982 else
983 {
984 const std::set<int>& selected_codes = m_board->GetHighLightNetCodes();
985
986 wxDataViewItemArray new_selection;
987 new_selection.Alloc( selected_codes.size() );
988
989 for( const int code : selected_codes )
990 {
991 if( std::optional<LIST_ITEM_ITER> r = m_dataModel->findItem( code ) )
992 new_selection.Add( wxDataViewItem( &***r ) );
993 }
994
995 m_netsList->SetSelections( new_selection );
996
997 if( !new_selection.IsEmpty() )
998 m_netsList->EnsureVisible( new_selection.Item( 0 ) );
999 }
1000}
1001
1002
1003/*****************************************************************************************
1004 *
1005 * UI-generated event handling
1006 *
1007 * ***************************************************************************************/
1008
1010{
1011 buildNetsList();
1013}
1014
1015
1017{
1018 bool multipleSelections = false;
1019 const LIST_ITEM* selItem = nullptr;
1020
1021 if( m_netsList->GetSelectedItemsCount() == 1 )
1022 {
1023 selItem = static_cast<const LIST_ITEM*>( m_netsList->GetSelection().GetID() );
1024 }
1025 else
1026 {
1027 if( m_netsList->GetSelectedItemsCount() > 1 )
1028 multipleSelections = true;
1029 }
1030
1031 wxMenu menu;
1032
1033 // Net edit menu items
1034 wxMenuItem* highlightNet = new wxMenuItem( &menu, ID_HIGHLIGHT_SELECTED_NETS, _( "Highlight Selected Net" ),
1035 wxEmptyString, wxITEM_NORMAL );
1036 menu.Append( highlightNet );
1037
1038 wxMenuItem* clearHighlighting = new wxMenuItem( &menu, ID_CLEAR_HIGHLIGHTING, _( "Clear Net Highlighting" ),
1039 wxEmptyString, wxITEM_NORMAL );
1040 menu.Append( clearHighlighting );
1041
1042 RENDER_SETTINGS* renderSettings = m_frame->GetCanvas()->GetView()->GetPainter()->GetSettings();
1043 const std::set<int>& selected_codes = renderSettings->GetHighlightNetCodes();
1044
1045 if( selected_codes.size() == 0 )
1046 clearHighlighting->Enable( false );
1047
1048 menu.AppendSeparator();
1049
1050 wxMenuItem* renameNet = new wxMenuItem( &menu, ID_RENAME_NET, _( "Rename Selected Net..." ), wxEmptyString,
1051 wxITEM_NORMAL );
1052 menu.Append( renameNet );
1053
1054 wxMenuItem* deleteNet = new wxMenuItem( &menu, ID_DELETE_NET, _( "Delete Selected Net" ), wxEmptyString,
1055 wxITEM_NORMAL );
1056 menu.Append( deleteNet );
1057
1058 menu.AppendSeparator();
1059
1060 wxMenuItem* addNet = new wxMenuItem( &menu, ID_ADD_NET, _( "Add Net..." ), wxEmptyString, wxITEM_NORMAL );
1061 menu.Append( addNet );
1062
1063 if( !selItem && !multipleSelections )
1064 {
1065 highlightNet->Enable( false );
1066 deleteNet->Enable( false );
1067 renameNet->Enable( false );
1068 }
1069 else
1070 {
1071 if( multipleSelections || selItem->GetIsGroup() )
1072 {
1073 highlightNet->SetItemLabel( _( "Highlight Selected Nets" ) );
1074 renameNet->Enable( false );
1075 deleteNet->SetItemLabel( _( "Delete Selected Nets" ) );
1076 }
1077 }
1078
1079 menu.AppendSeparator();
1080
1081 wxMenuItem* removeSelectedGroup = new wxMenuItem( &menu, ID_REMOVE_SELECTED_GROUP,
1082 _( "Remove Selected Custom Group" ),
1083 wxEmptyString, wxITEM_NORMAL );
1084 menu.Append( removeSelectedGroup );
1085
1086 if( !selItem || !selItem->GetIsGroup() )
1087 removeSelectedGroup->Enable( false );
1088
1089 menu.Bind( wxEVT_COMMAND_MENU_SELECTED, &PCB_NET_INSPECTOR_PANEL::onContextMenuSelection, this );
1090
1091 PopupMenu( &menu );
1092}
1093
1094
1096{
1097 SaveSettings();
1098 buildNetsList();
1099}
1100
1101
1103{
1104 wxString newGroupName;
1105 NETNAME_VALIDATOR validator( &newGroupName );
1106
1107 WX_TEXT_ENTRY_DIALOG dlg( this, _( "Group name / pattern:" ), _( "New Group" ), newGroupName );
1108 wxStaticText* help = new wxStaticText( &dlg, wxID_ANY, _( "(Use /.../ to indicate a regular expression.)" ) );
1109 help->SetFont( KIUI::GetInfoFont( this ).Italic() );
1110 dlg.m_ContentSizer->Add( help, 0, wxALL|wxEXPAND, 5 );
1111 dlg.SetTextValidator( validator );
1112 dlg.GetSizer()->SetSizeHints( &dlg );
1113
1114 if( dlg.ShowModal() != wxID_OK || dlg.GetValue().IsEmpty() )
1115 return; //Aborted by user
1116
1117 newGroupName = UnescapeString( dlg.GetValue() );
1118
1119 if( newGroupName == "" )
1120 return;
1121
1122 if( std::ranges::find_if( m_custom_group_rules,
1123 [&]( std::unique_ptr<EDA_COMBINED_MATCHER>& rule )
1124 {
1125 return rule->GetPattern() == newGroupName;
1126 } )
1127 == m_custom_group_rules.end() )
1128 {
1129 m_custom_group_rules.push_back( std::make_unique<EDA_COMBINED_MATCHER>( newGroupName, CTX_NET ) );
1130 SaveSettings();
1131 }
1132
1133 buildNetsList();
1134}
1135
1136
1138{
1139 m_highlightingNets = true;
1140
1144
1145 m_highlightingNets = false;
1146}
1147
1148
1150{
1151 if( !m_rowExpanding )
1152 SaveSettings();
1153}
1154
1155
1157{
1158 wxMenu menu;
1160 menu.Bind( wxEVT_COMMAND_MENU_SELECTED, &PCB_NET_INSPECTOR_PANEL::onContextMenuSelection, this );
1161 PopupMenu( &menu );
1162}
1163
1164
1165void PCB_NET_INSPECTOR_PANEL::OnConfigButton( wxCommandEvent& event )
1166{
1168 auto& cfg = localSettings.m_NetInspectorPanel;
1169
1170 const LIST_ITEM* selItem = nullptr;
1171
1172 if( m_netsList->GetSelectedItemsCount() == 1 )
1173 {
1174 selItem = static_cast<const LIST_ITEM*>( m_netsList->GetSelection().GetID() );
1175 }
1176
1177 wxMenu menu;
1178
1179 // Filtering menu items
1180 wxMenuItem* filterByNetName = new wxMenuItem( &menu, ID_FILTER_BY_NET_NAME,
1181 _( "Filter by Net Name" ),
1182 wxEmptyString, wxITEM_CHECK );
1183 menu.Append( filterByNetName );
1184 filterByNetName->Check( cfg.filter_by_net_name );
1185
1186 wxMenuItem* filterByNetclass = new wxMenuItem( &menu, ID_FILTER_BY_NETCLASS,
1187 _( "Filter by Netclass" ),
1188 wxEmptyString, wxITEM_CHECK );
1189 menu.Append( filterByNetclass );
1190 filterByNetclass->Check( cfg.filter_by_netclass );
1191
1192 menu.AppendSeparator();
1193
1194 // Grouping menu items
1195 //wxMenuItem* groupConstraint =
1196 // new wxMenuItem( &menu, ID_GROUP_BY_CONSTRAINT, _( "Group by DRC Constraint" ),
1197 // wxEmptyString, wxITEM_CHECK );
1198 //groupConstraint->Check( m_group_by_constraint );
1199 //menu.Append( groupConstraint );
1200
1201 wxMenuItem* groupNetclass = new wxMenuItem( &menu, ID_GROUP_BY_NETCLASS,
1202 _( "Group by Netclass" ),
1203 wxEmptyString, wxITEM_CHECK );
1204 menu.Append( groupNetclass );
1205 groupNetclass->Check( m_groupByNetclass );
1206
1207 menu.AppendSeparator();
1208
1209 wxMenuItem* addGroup = new wxMenuItem( &menu, ID_ADD_GROUP, _( "Add Custom Group..." ),
1210 wxEmptyString, wxITEM_NORMAL );
1211 menu.Append( addGroup );
1212
1213 wxMenuItem* removeSelectedGroup = new wxMenuItem( &menu, ID_REMOVE_SELECTED_GROUP,
1214 _( "Remove Selected Custom Group" ),
1215 wxEmptyString, wxITEM_NORMAL );
1216 menu.Append( removeSelectedGroup );
1217
1218 if( !selItem || !selItem->GetIsGroup() )
1219 removeSelectedGroup->Enable( false );
1220
1221 wxMenuItem* removeCustomGroups = new wxMenuItem( &menu, ID_REMOVE_GROUPS,
1222 _( "Remove All Custom Groups" ),
1223 wxEmptyString, wxITEM_NORMAL );
1224 menu.Append( removeCustomGroups );
1225 removeCustomGroups->Enable( m_custom_group_rules.size() != 0 );
1226
1227 menu.AppendSeparator();
1228
1229 wxMenuItem* showZeroNetPads = new wxMenuItem( &menu, ID_SHOW_ZERO_NET_PADS,
1230 _( "Show Zero Pad Nets" ),
1231 wxEmptyString, wxITEM_CHECK );
1232 menu.Append( showZeroNetPads );
1233 showZeroNetPads->Check( m_showZeroPadNets );
1234
1235 wxMenuItem* showUnconnectedNets = new wxMenuItem( &menu, ID_SHOW_UNCONNECTED_NETS,
1236 _( "Show Unconnected Nets" ),
1237 wxEmptyString, wxITEM_CHECK );
1238 menu.Append( showUnconnectedNets );
1239 showUnconnectedNets->Check( m_showUnconnectedNets );
1240
1241 menu.AppendSeparator();
1242
1243 wxMenuItem* showTimeDomainDetails = new wxMenuItem( &menu, ID_SHOW_TIME_DOMAIN_DETAILS,
1244 _( "Show Time Domain Details" ), wxEmptyString, wxITEM_CHECK );
1245 menu.Append( showTimeDomainDetails );
1246 showTimeDomainDetails->Check( m_showTimeDomainDetails );
1247
1248 menu.AppendSeparator();
1249
1250 // Report generation
1251 wxMenuItem* generateReport = new wxMenuItem( &menu, ID_GENERATE_REPORT,
1252 _( "Save Net Inspector Report..." ),
1253 wxEmptyString, wxITEM_NORMAL );
1254 menu.Append( generateReport );
1255
1256 menu.AppendSeparator();
1257
1258 // Show / hide columns menu items
1259 wxMenu* colsMenu = new wxMenu();
1260 generateShowHideColumnMenu( colsMenu );
1261 menu.AppendSubMenu( colsMenu, _( "Show / Hide Columns" ) );
1262
1263 menu.Bind( wxEVT_COMMAND_MENU_SELECTED, &PCB_NET_INSPECTOR_PANEL::onContextMenuSelection, this );
1264
1265 PopupMenu( &menu );
1266}
1267
1268
1270{
1271 for( int i = 1; i <= COLUMN_LAST_STATIC_COL; ++i )
1272 {
1273 wxMenuItem* opt = new wxMenuItem( target, ID_HIDE_COLUMN + i, m_columns[i].display_name,
1274 wxEmptyString, wxITEM_CHECK );
1275 wxDataViewColumn* col = getDisplayedColumnForModelField( i );
1276 target->Append( opt );
1277 opt->Check( !col->IsHidden() );
1278 }
1279
1280 target->AppendSeparator();
1281
1282 for( std::size_t i = COLUMN_LAST_STATIC_COL + 1; i < m_columns.size(); ++i )
1283 {
1284 wxMenuItem* opt = new wxMenuItem( target, ID_HIDE_COLUMN + i, m_columns[i].display_name,
1285 wxEmptyString, wxITEM_CHECK );
1286 wxDataViewColumn* col = getDisplayedColumnForModelField( i );
1287 target->Append( opt );
1288 opt->Check( !col->IsHidden() );
1289 }
1290}
1291
1292
1294{
1295 bool saveAndRebuild = true;
1296
1297 switch( event.GetId() )
1298 {
1299 case ID_ADD_NET:
1300 onAddNet();
1301 break;
1302
1303 case ID_RENAME_NET:
1305 break;
1306
1307 case ID_DELETE_NET:
1309 break;
1310
1311 case ID_ADD_GROUP:
1312 onAddGroup();
1313 break;
1314
1316
1318
1320
1322
1325 break;
1326
1327 case ID_REMOVE_GROUPS:
1328 m_custom_group_rules.clear();
1329 break;
1330
1332
1334
1336
1337 case ID_GENERATE_REPORT:
1339 saveAndRebuild = false;
1340 break;
1341
1344 saveAndRebuild = false;
1345 break;
1346
1349 saveAndRebuild = false;
1350 break;
1351
1352 default:
1353 if( event.GetId() >= ID_HIDE_COLUMN )
1354 {
1355 const int columnId = event.GetId() - ID_HIDE_COLUMN;
1356 wxDataViewColumn* col = getDisplayedColumnForModelField( columnId );
1357 // Make sure we end up with something non-zero so we can resize it
1358 col->SetWidth( std::max( col->GetWidth(), 10 ) );
1359 col->SetHidden( !col->IsHidden() );
1360 }
1361 break;
1362 }
1363
1364 if( saveAndRebuild )
1365 {
1366 SaveSettings();
1367 buildNetsList();
1368 }
1369}
1370
1371
1373{
1374 if( m_netsList->GetSelectedItemsCount() == 1 )
1375 {
1376 auto* selItem = static_cast<const LIST_ITEM*>( m_netsList->GetSelection().GetID() );
1377
1378 if( selItem->GetIsGroup() )
1379 {
1380 const wxString groupName = selItem->GetGroupName();
1381 const auto groupIter = std::ranges::find_if( m_custom_group_rules,
1382 [&]( std::unique_ptr<EDA_COMBINED_MATCHER>& rule )
1383 {
1384 return rule->GetPattern() == groupName;
1385 } );
1386
1387 if( groupIter != m_custom_group_rules.end() )
1388 {
1389 m_custom_group_rules.erase( groupIter );
1390 SaveSettings();
1391 buildNetsList();
1392 }
1393 }
1394 }
1395}
1396
1397
1399{
1400 wxFileDialog dlg( this, _( "Save Net Inspector Report File" ), "", "",
1401 _( "Report file" ) + AddFileExtListToFilter( { "csv" } ),
1402 wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
1403
1404 if( dlg.ShowModal() == wxID_CANCEL )
1405 return;
1406
1407 wxTextFile f( dlg.GetPath() );
1408
1409 f.Create();
1410
1411 wxString txt;
1412
1413 m_inReporting = true;
1414
1415 // Print Header:
1416 for( auto&& col : m_columns )
1417 {
1418 txt += '"';
1419
1420 if( col.has_units )
1421 {
1422 txt += wxString::Format( _( "%s (%s)" ),
1423 col.csv_name,
1425 }
1426 else
1427 {
1428 txt += col.csv_name;
1429 }
1430
1431 txt += wxT( "\";" );
1432 }
1433
1434 f.AddLine( txt );
1435
1436 // Print list of nets:
1437 const unsigned int num_rows = m_dataModel->itemCount();
1438
1439 for( unsigned int row = 0; row < num_rows; row++ )
1440 {
1441 auto& i = m_dataModel->itemAt( row );
1442
1443 if( i.GetIsGroup() || i.GetNetCode() == 0 )
1444 continue;
1445
1446 txt = "";
1447
1448 for( auto&& col : m_columns )
1449 {
1450 if( static_cast<int>( col.csv_flags ) & static_cast<int>( CSV_COLUMN_DESC::CSV_QUOTE ) )
1451 txt += '"' + m_dataModel->valueAt( col.num, row ).GetString() + wxT( "\";" );
1452 else
1453 txt += m_dataModel->valueAt( col.num, row ).GetString() + ';';
1454 }
1455
1456 f.AddLine( txt );
1457 }
1458
1459 m_inReporting = false;
1460
1461 f.Write();
1462 f.Close();
1463}
1464
1465
1467{
1469}
1470
1471
1473{
1474 // ignore selection changes while the whole list is being rebuilt.
1475 if( m_inBuildNetsList )
1476 return;
1477
1478 m_highlightingNets = true;
1479
1480 RENDER_SETTINGS* renderSettings = m_frame->GetCanvas()->GetView()->GetPainter()->GetSettings();
1481
1482 if( m_netsList->HasSelection() )
1483 {
1484 wxDataViewItemArray sel;
1485 m_netsList->GetSelections( sel );
1486
1487 renderSettings->SetHighlight( false );
1488
1489 for( unsigned int i = 0; i < sel.GetCount(); ++i )
1490 {
1491 const LIST_ITEM* ii = static_cast<const LIST_ITEM*>( sel.Item( i ).GetID() );
1492
1493 if( ii->GetIsGroup() )
1494 {
1495 for( auto c = ii->ChildrenBegin(), end = ii->ChildrenEnd(); c != end; ++c )
1496 renderSettings->SetHighlight( true, ( *c )->GetNetCode(), true );
1497 }
1498 else
1499 {
1500 renderSettings->SetHighlight( true, ii->GetNetCode(), true );
1501 }
1502 }
1503 }
1504 else
1505 {
1506 renderSettings->SetHighlight( false );
1507 }
1508
1511
1512 m_highlightingNets = false;
1513}
1514
1515
1516void PCB_NET_INSPECTOR_PANEL::OnColumnSorted( wxDataViewEvent& event )
1517{
1518 if( !m_inBuildNetsList )
1519 SaveSettings();
1520}
1521
1522
1524{
1525 // Rebuilt the nets list, and force rebuild of columns in case the stackup has changed
1526 buildNetsList( true );
1527}
1528
1529
1531{
1532 wxString newNetName;
1533 NETNAME_VALIDATOR validator( &newNetName );
1534
1535 WX_TEXT_ENTRY_DIALOG dlg( this, _( "Net name:" ), _( "New Net" ), newNetName );
1536 dlg.SetTextValidator( validator );
1537
1538 while( true )
1539 {
1540 if( dlg.ShowModal() != wxID_OK || dlg.GetValue().IsEmpty() )
1541 return; //Aborted by user
1542
1543 newNetName = dlg.GetValue();
1544
1545 if( m_board->FindNet( newNetName ) )
1546 {
1547 DisplayError( this,
1548 wxString::Format( _( "Net name '%s' is already in use." ), newNetName ) );
1549 newNetName = wxEmptyString;
1550 }
1551 else
1552 {
1553 break;
1554 }
1555 }
1556
1557 NETINFO_ITEM* newnet = new NETINFO_ITEM( m_board, dlg.GetValue(), 0 );
1558
1559 m_board->Add( newnet );
1560
1561 // We'll get an OnBoardItemAdded callback from this to update our listbox
1562 m_frame->OnModify();
1563}
1564
1565
1567{
1568 if( m_netsList->GetSelectedItemsCount() == 1 )
1569 {
1570 const LIST_ITEM* sel = static_cast<const LIST_ITEM*>( m_netsList->GetSelection().GetID() );
1571
1572 if( sel->GetIsGroup() )
1573 return;
1574
1575 NETINFO_ITEM* net = sel->GetNet();
1576 wxString fullNetName = net->GetNetname();
1577 wxString netPath;
1578 wxString shortNetName;
1579
1580 if( fullNetName.Contains( wxT( "/" ) ) )
1581 {
1582 netPath = fullNetName.BeforeLast( '/' ) + '/';
1583 shortNetName = fullNetName.AfterLast( '/' );
1584 }
1585 else
1586 {
1587 shortNetName = fullNetName;
1588 }
1589
1590 wxString unescapedShortName = UnescapeString( shortNetName );
1591
1592 WX_TEXT_ENTRY_DIALOG dlg( this, _( "Net name:" ), _( "Rename Net" ), unescapedShortName );
1593 NETNAME_VALIDATOR validator( &unescapedShortName );
1594 dlg.SetTextValidator( validator );
1595
1596 while( true )
1597 {
1598 if( dlg.ShowModal() != wxID_OK || dlg.GetValue() == unescapedShortName )
1599 return;
1600
1601 unescapedShortName = dlg.GetValue();
1602
1603 if( unescapedShortName.IsEmpty() )
1604 {
1605 DisplayError( this, wxString::Format( _( "Net name cannot be empty." ),
1606 unescapedShortName ) );
1607 continue;
1608 }
1609
1610 shortNetName = EscapeString( unescapedShortName, CTX_NETNAME );
1611 fullNetName = netPath + shortNetName;
1612
1613 if( m_board->FindNet( shortNetName ) || m_board->FindNet( fullNetName ) )
1614 {
1615 DisplayError( this, wxString::Format( _( "Net name '%s' is already in use." ),
1616 unescapedShortName ) );
1617 unescapedShortName = wxEmptyString;
1618 }
1619 else
1620 {
1621 break;
1622 }
1623 }
1624
1625 for( BOARD_CONNECTED_ITEM* boardItem : m_frame->GetBoard()->AllConnectedItems() )
1626 {
1627 if( boardItem->GetNet() == net )
1628 boardItem->SetFlags( CANDIDATE );
1629 else
1630 boardItem->ClearFlags( CANDIDATE );
1631 }
1632
1633 // the changed name might require re-grouping. remove/re-insert is easier.
1634 auto removed_item = m_dataModel->deleteItem( m_dataModel->findItem( net ) );
1635
1636 m_board->Remove( net );
1637 net->SetNetname( fullNetName );
1638 m_board->Add( net );
1639
1640 for( BOARD_CONNECTED_ITEM* boardItem : m_frame->GetBoard()->AllConnectedItems() )
1641 {
1642 if( boardItem->GetFlags() & CANDIDATE )
1643 boardItem->SetNet( net );
1644 }
1645
1646 buildNetsList();
1647
1648 if( std::optional<LIST_ITEM_ITER> r = m_dataModel->findItem( net ) )
1649 m_netsList->Select( wxDataViewItem( r.value()->get() ) );
1650
1651 m_frame->OnModify();
1652
1653 // Currently only tracks and pads have netname annotations and need to be redrawn,
1654 // but zones are likely to follow. Since we don't have a way to ask what is current,
1655 // just refresh all items.
1658 }
1659}
1660
1661
1663{
1664 if( !m_netsList->HasSelection() )
1665 return;
1666
1667 wxDataViewItemArray sel;
1668 m_netsList->GetSelections( sel );
1669
1670 auto delete_one = [this]( const LIST_ITEM* i )
1671 {
1672 if( i->GetPadCount() == 0
1673 || IsOK( this, wxString::Format( _( "Net '%s' is in use. Delete anyway?" ),
1674 i->GetNetName() ) ) )
1675 {
1676 // This is a bit hacky, but it will do for now, since this is the only path
1677 // outside the netlist updater where you can remove a net from a BOARD.
1678 int removedCode = i->GetNetCode();
1679
1681 [removedCode]( KIGFX::VIEW_ITEM* aItem ) -> int
1682 {
1683 auto boardItem = dynamic_cast<BOARD_CONNECTED_ITEM*>( aItem );
1684
1685 if( boardItem && boardItem->GetNetCode() == removedCode )
1686 return KIGFX::REPAINT;
1687
1688 EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( aItem );
1689
1690 if( text && text->HasTextVars() )
1691 {
1692 text->ClearRenderCache();
1693 text->ClearBoundingBoxCache();
1695 }
1696
1697 return 0;
1698 } );
1699
1700 m_board->Remove( i->GetNet() );
1701 m_frame->OnModify();
1702
1703 // We'll get an OnBoardItemRemoved callback from this to update our listbox
1704 }
1705 };
1706
1707 for( unsigned int i = 0; i < sel.GetCount(); ++i )
1708 {
1709 const LIST_ITEM* ii = static_cast<const LIST_ITEM*>( sel.Item( i ).GetID() );
1710
1711 if( ii->GetIsGroup() )
1712 {
1713 if( ii->ChildrenCount() != 0
1714 && IsOK( this, wxString::Format( _( "Delete all nets in group '%s'?" ),
1715 ii->GetGroupName() ) ) )
1716 {
1717 // we can't be iterating the children container and deleting items from
1718 // it at the same time. thus take a copy of it first.
1719 std::vector<const LIST_ITEM*> children;
1720 children.reserve( ii->ChildrenCount() );
1721 std::copy( ii->ChildrenBegin(), ii->ChildrenEnd(), std::back_inserter( children ) );
1722
1723 for( const LIST_ITEM* c : children )
1724 delete_one( c );
1725 }
1726 }
1727 else
1728 {
1729 delete_one( ii );
1730 }
1731 }
1732}
1733
1734/*****************************************************************************************
1735 *
1736 * Application-generated event handling
1737 *
1738 * ***************************************************************************************/
1739
1740
1742{
1743 SaveSettings();
1744 buildNetsList( true );
1745 m_dataModel->updateAllItems();
1746}
1747
1748
1749void PCB_NET_INSPECTOR_PANEL::onUnitsChanged( wxCommandEvent& event )
1750{
1751 m_dataModel->updateAllItems();
1752 event.Skip();
1753}
1754
1755
1756/*****************************************************************************************
1757 *
1758 * Settings persistence
1759 *
1760 * ***************************************************************************************/
1761
1762
1764{
1765 // Don't save settings if a board has not yet been loaded or the panel hasn't been displayed.
1766 // Events fire while we set up the panel which overwrite the settings we haven't yet loaded.
1767 bool displayed = false;
1768
1769 for( unsigned int ii = 0; ii < m_dataModel->columnCount() && !displayed; ++ii )
1770 {
1771 if( m_netsList->GetColumn( ii )->GetWidth() > 0 )
1772 displayed = true;
1773 }
1774
1775 if( !displayed || !m_boardLoaded || m_boardLoading )
1776 return;
1777
1779 auto& cfg = localSettings.m_NetInspectorPanel;
1780
1781 // User-defined filters / grouping
1782 cfg.filter_text = m_searchCtrl->GetValue();
1783 cfg.filter_by_net_name = m_filterByNetName;
1784 cfg.filter_by_netclass = m_filterByNetclass;
1785 cfg.group_by_netclass = m_groupByNetclass;
1786 cfg.group_by_constraint = m_groupByConstraint;
1787 cfg.show_zero_pad_nets = m_showZeroPadNets;
1788 cfg.show_unconnected_nets = m_showUnconnectedNets;
1789 cfg.show_time_domain_details = m_showTimeDomainDetails;
1790
1791 // Grid sorting
1792 wxDataViewColumn* sortingCol = m_netsList->GetSortingColumn();
1793 cfg.sorting_column = sortingCol ? static_cast<int>( sortingCol->GetModelColumn() ) : -1;
1794 cfg.sort_order_asc = sortingCol ? sortingCol->IsSortOrderAscending() : true;
1795
1796 // Column arrangement / sizes
1797 cfg.col_order.resize( m_dataModel->columnCount() );
1798 cfg.col_widths.resize( m_dataModel->columnCount() );
1799 cfg.col_hidden.resize( m_dataModel->columnCount() );
1800
1801 for( unsigned int ii = 0; ii < m_dataModel->columnCount(); ++ii )
1802 {
1803 cfg.col_order[ii] = (int) m_netsList->GetColumn( ii )->GetModelColumn();
1804 cfg.col_widths[ii] = m_netsList->GetColumn( ii )->GetWidth();
1805 cfg.col_hidden[ii] = m_netsList->GetColumn( ii )->IsHidden();
1806 }
1807
1808 // Expanded rows
1809 cfg.expanded_rows.clear();
1810 std::vector<std::pair<wxString, wxDataViewItem>> groupItems = m_dataModel->getGroupDataViewItems();
1811
1812 for( std::pair<wxString, wxDataViewItem>& item : groupItems )
1813 {
1814 if( m_netsList->IsExpanded( item.second ) )
1815 cfg.expanded_rows.push_back( item.first );
1816 }
1817
1818 // Customer group rules
1819 cfg.custom_group_rules.clear();
1820
1821 for( const std::unique_ptr<EDA_COMBINED_MATCHER>& rule : m_custom_group_rules )
1822 cfg.custom_group_rules.push_back( rule->GetPattern() );
1823}
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:79
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:317
const NETINFO_LIST & GetNetInfo() const
Definition: board.h:934
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
Definition: board.cpp:1147
const std::set< int > & GetHighLightNetCodes() const
Definition: board.h:579
LENGTH_DELAY_CALCULATION * GetLengthCalculation() const
Returns the track length calculator.
Definition: board.h:1340
const std::vector< BOARD_CONNECTED_ITEM * > AllConnectedItems()
Definition: board.cpp:2726
void AddListener(BOARD_LISTENER *aListener)
Add a listener to the board to receive calls whenever something on the board has been modified.
Definition: board.cpp:2781
NETINFO_ITEM * FindNet(int aNetcode) const
Search for a net with the given netcode.
Definition: board.cpp:2099
int GetCopperLayerCount() const
Definition: board.cpp:859
bool IsHighLightNetON() const
Definition: board.h:595
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition: board.cpp:680
const LSET & GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition: board.cpp:907
void Remove(BOARD_ITEM *aBoardItem, REMOVE_MODE aMode=REMOVE_MODE::NORMAL) override
Removes an item from the container.
Definition: board.cpp:1310
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Return a list of missing connections between components/tracks.
Definition: board.h:522
CN_ITEM represents a BOARD_CONNETED_ITEM in the connectivity system (ie: a pad, track/arc/via,...
int Net() const
int ShowModal() override
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition: eda_text.h:79
virtual RENDER_SETTINGS * GetSettings()=0
Return a pointer to current settings that are going to be used when drawing items.
Container for all the knowledge about how graphical objects are drawn on any output surface/device.
const std::set< int > & GetHighlightNetCodes() const
Return the netcode of currently highlighted net.
void SetHighlight(bool aEnabled, int aNetcode=-1, bool aMulti=false)
Turns on/off highlighting.
An abstract base class for deriving all objects that can be added to a VIEW.
Definition: view_item.h:86
void UpdateAllLayersColor()
Apply the new coloring scheme to all layers.
Definition: view.cpp:775
void UpdateAllItems(int aUpdateFlags)
Update all items in the view according to the given flags.
Definition: view.cpp:1561
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition: view.h:220
void UpdateAllItemsConditionally(int aUpdateFlags, std::function< bool(VIEW_ITEM *)> aCondition)
Update items in the view according to the given flags and condition.
Definition: view.cpp:1571
Lightweight class which holds a pad, via, or a routed trace outline.
Class which calculates lengths (and associated routing statistics) in a BOARD context.
LENGTH_DELAY_CALCULATION_ITEM GetLengthCalculationItem(const BOARD_CONNECTED_ITEM *aBoardItem) const
Return a LENGTH_CALCULATION_ITEM constructed from the given BOARD_CONNECTED_ITEM.
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:296
A collection of nets and the parameters used to route or test these nets.
Definition: netclass.h:45
const wxString GetName() const
Gets the name of this (maybe aggregate) netclass in a format for internal usage or for export to exte...
Definition: netclass.cpp:322
Handle the data for a net.
Definition: netinfo.h:56
void SetNetname(const wxString &aNewName)
Set the long netname to aNetName, the short netname to the last token in the long netname's path,...
Definition: netinfo.h:139
const wxString & GetNetname() const
Definition: netinfo.h:114
NETCLASS * GetNetClass()
Definition: netinfo.h:101
int GetNetCode() const
Definition: netinfo.h:108
A base class used to implement docking net inspector panels.
wxDataViewCtrl * m_netsList
wxSearchCtrl * m_searchCtrl
Definition: pad.h:54
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
BOARD * GetBoard() const
virtual KIGFX::PCB_VIEW * GetView() const override
Return a pointer to the #VIEW instance used in the panel.
The main frame for Pcbnew.
void OnModify() override
Must be called after a board change to set the modified flag.
Data model for display in the Net Inspector panel.
std::vector< std::pair< wxString, wxDataViewItem > > getGroupDataViewItems()
Primary data item for entries in the Net Inspector list.
void OnBoardItemRemoved(BOARD &aBoard, BOARD_ITEM *aBoardItem) override
void OnBoardHighlightNetChanged(BOARD &aBoard) override
void generateReport()
Generates a CSV report from currently disaplyed data.
PCB_NET_INSPECTOR_PANEL(wxWindow *parent, PCB_EDIT_FRAME *aFrame)
void onDeleteSelectedNet()
Deletes a selected net.
bool restoreSortColumn(int sortingColumnId, bool sortOrderAsc) const
Sets the sort column in the grid to that showing the given model ID column.
void OnBoardItemsChanged(BOARD &aBoard, std::vector< BOARD_ITEM * > &aBoardItems) override
void adjustListColumnSizes(PANEL_NET_INSPECTOR_SETTINGS *cfg) const
Adjust the sizing of list columns.
void OnSearchTextChanged(wxCommandEvent &event) override
void updateDisplayedRowValues(const std::optional< LIST_ITEM_ITER > &aRow) const
Refreshes displayed data for the given rows.
void onAddNet()
Adds a new user-specified net to the board.
PCB_EDIT_FRAME * m_frame
Owning edit frame.
void OnBoardItemsRemoved(BOARD &aBoard, std::vector< BOARD_ITEM * > &aBoardItems) override
void onClearHighlighting()
Clears highlighting from nets.
void onContextMenuSelection(wxCommandEvent &event)
Handle a net row(s) context menu selection.
static wxString formatNetCode(const NETINFO_ITEM *aNet)
void OnBoardChanged() override
Update panel when board is changed.
void generateShowHideColumnMenu(wxMenu *target)
Generates a sub-menu for the show / hide columns submenu.
std::vector< std::unique_ptr< LIST_ITEM > > calculateNets(const std::vector< NETINFO_ITEM * > &aNetCodes, bool aIncludeZeroPadNets) const
Calculates the length statistics for each given netcode.
static wxString formatCount(unsigned int aValue)
std::vector< std::unique_ptr< EDA_COMBINED_MATCHER > > m_custom_group_rules
Custom net grouping rules.
std::vector< CN_ITEM * > relevantConnectivityItems() const
Fetches an ordered (by NetCode) list of all board connectivity items.
void highlightSelectedNets()
Highlight the currently selected net.
void updateNets(const std::vector< NETINFO_ITEM * > &aNets) const
Updates displayed statistics for the given nets.
void OnBoardItemsAdded(BOARD &aBoard, std::vector< BOARD_ITEM * > &aBoardItems) override
void OnLanguageChangedImpl() override
Reloads strings on an application language change.
void onAddGroup()
Adds a custom display grouping of nets.
void OnNetsListContextMenu(wxDataViewEvent &event)
void OnBoardNetSettingsChanged(BOARD &aBoard) override
void OnBoardCompositeUpdate(BOARD &aBoard, std::vector< BOARD_ITEM * > &aAddedItems, std::vector< BOARD_ITEM * > &aRemovedItems, std::vector< BOARD_ITEM * > &aChangedItems) override
void OnNetsListItemActivated(wxDataViewEvent &event)
void OnColumnSorted(wxDataViewEvent &event)
void onRemoveSelectedGroup()
Removes a custom display grouping.
void buildColumns()
Build the required columns in the net inspector grid.
void OnBoardItemAdded(BOARD &aBoard, BOARD_ITEM *aBoardItem) override
void OnParentSetupChanged() override
Updates the netlist based on global board changes (e.g.
void OnHeaderContextMenu(wxCommandEvent &event)
bool netFilterMatches(NETINFO_ITEM *aNet, PANEL_NET_INSPECTOR_SETTINGS *cfg=nullptr) const
Filter to determine whether a board net should be included in the net inspector.
void OnConfigButton(wxCommandEvent &event) override
void buildNetsList(bool rebuildColumns=false)
Rebuilds the net inspector list, removing all previous entries.
wxString formatLength(int64_t aValue) const
void SaveSettings() override
Persist the net inspector configuration to project / global settings.
void onRenameSelectedNet()
Renames a selected net.
void onUnitsChanged(wxCommandEvent &event)
Handle an application-level change of units.
void OnExpandCollapseRow(wxCommandEvent &event)
void updateBoardItems(const std::vector< BOARD_ITEM * > &aBoardItems)
Unified handling of added / deleted / modified board items.
wxString formatDelay(int64_t aValue) const
wxObjectDataPtr< DATA_MODEL > m_dataModel
The bound data model to display.
wxDataViewColumn * getDisplayedColumnForModelField(int columnId) const
Fetches the displayed grid view column for the given model column ID.
static wxString formatNetName(const NETINFO_ITEM *aNet)
void OnBoardItemChanged(BOARD &aBoard, BOARD_ITEM *aBoardItem) override
std::vector< COLUMN_DESC > m_columns
All displayed (or hidden) columns.
void OnShowPanel() override
Prepare the panel when shown in the editor.
virtual SETTINGS_MANAGER & GetSettingsManager() const
Definition: pgm_base.h:125
The project local settings are things that are attached to a particular project, but also might be pa...
PANEL_NET_INSPECTOR_SETTINGS m_NetInspectorPanel
The state of the net inspector panel.
virtual PROJECT_LOCAL_SETTINGS & GetLocalSettings() const
Definition: project.h:210
PROJECT & Prj() const
A helper while we are not MDI-capable – return the one and only project.
wxString MessageTextFromValue(double aValue, bool aAddUnitLabel=true, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
A lower-precision version of StringFromValue().
EDA_UNITS GetUserUnits() const
wxBoxSizer * m_ContentSizer
A KICAD version of wxTextEntryDialog which supports the various improvements/work-arounds from DIALOG...
wxString GetValue() const
void SetTextValidator(const wxTextValidator &validator)
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition: confirm.cpp:251
void DisplayError(wxWindow *aParent, const wxString &aText)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:169
This file is part of the common library.
#define _(s)
#define CANDIDATE
flag indicating that the structure is connected
Abstract pattern-matching tool and implementations.
@ CTX_NET
int m_NetInspectorBulkUpdateOptimisationThreshold
When updating the net inspector, it either recalculates all nets or iterates through items one-by-one...
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition: layer_ids.h:665
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
@ UNDEFINED_LAYER
Definition: layer_ids.h:61
KICOMMON_API wxString GetLabel(EDA_UNITS aUnits, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
Get the units string for a given units type.
Definition: eda_units.cpp:180
@ REPAINT
Item needs to be redrawn.
Definition: view_item.h:58
@ GEOMETRY
Position or shape has changed.
Definition: view_item.h:55
KICOMMON_API wxFont GetInfoFont(wxWindow *aWindow)
Definition: ui_common.cpp:156
PGM_BASE & Pgm()
The global program "get" accessor.
Definition: pgm_base.cpp:902
see class PGM_BASE
static bool highlightNet(TOOL_MANAGER *aToolMgr, const VECTOR2D &aPosition)
wxString UnescapeString(const wxString &aSource)
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
@ CTX_NETNAME
Definition: string_utils.h:53
bool operator()(const CN_ITEM *a, const CN_ITEM *b) const
bool operator()(int a, const CN_ITEM *b) const
bool operator()(const CN_ITEM *a, int b) const
Persisted state for the net inspector panel.
std::vector< wxString > expanded_rows
std::vector< wxString > custom_group_rules
VECTOR2I end
thread_pool & GetKiCadThreadPool()
Get a reference to the current thread pool.
Definition: thread_pool.cpp:30
static thread_pool * tp
Definition: thread_pool.cpp:28
BS::thread_pool thread_pool
Definition: thread_pool.h:31
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:97
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition: typeinfo.h:87
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition: typeinfo.h:98
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:96
Custom text control validator definitions.
wxString AddFileExtListToFilter(const std::vector< std::string > &aExts)
Build the wildcard extension file dialog wildcard filter to add to the base message dialog.
Definition of file extensions used in Kicad.