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