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