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 if( col_order_set.size() != cfg->col_order.size() )
231 {
232 for( std::size_t i = 0; i < cfg->col_order.size(); ++i )
233 cfg->col_order[i] = static_cast<int>( i );
234 }
235
236 // Add column records for copper layers
237 for( PCB_LAYER_ID layer : m_board->GetEnabledLayers().Seq() )
238 {
239 if( !IsCopperLayer( layer ) )
240 continue;
241
242 m_columns.emplace_back( m_columns.size(), layer, m_board->GetLayerName( layer ), m_board->GetLayerName( layer ),
244 }
245
246 // Add display columns in settings order
247 for( const int i : cfg->col_order )
248 {
249 const int addModelColumn = i;
250
251 if( addModelColumn >= (int) add_col.size() )
252 {
253 m_netsList->AppendTextColumn( m_board->GetLayerName( m_columns[addModelColumn].layer ),
254 m_columns[addModelColumn], wxDATAVIEW_CELL_INERT, -1, wxALIGN_CENTER,
255 wxDATAVIEW_COL_RESIZABLE|wxDATAVIEW_COL_REORDERABLE|wxDATAVIEW_COL_SORTABLE );
256 }
257 else
258 {
259 add_col.at( i )();
260 }
261 }
262
263 // Set the name column as the expander row
264 if( wxDataViewColumn* col = getDisplayedColumnForModelField( COLUMN_NAME ) )
265 {
266 m_netsList->SetExpanderColumn( col );
267 }
268
270
271 // Delete the temporary config if used
272 if( !m_boardLoaded )
273 delete cfg;
274}
275
276
278{
279 wxWindowUpdateLocker locker( m_netsList );
280
281 if( cfg->col_widths.size() != m_columns.size() )
282 {
283 int minValueWidth = GetTextExtent( wxT( "00000,000 mm" ) ).x;
284 int minNumberWidth = GetTextExtent( wxT( "000" ) ).x;
285 int minNameWidth = GetTextExtent( wxT( "MMMMMMMMMMMM" ) ).x;
286
287 // Considering left and right margins.
288 // For wxRenderGeneric it is 5px.
289 // Also account for the sorting arrow in the column header.
290 // Column 0 also needs space for any potential expander icons.
291 constexpr int margins = 15;
292 constexpr int extra_width = 30;
293
294 auto getTargetWidth =
295 [&]( int columnID )
296 {
297 switch( columnID )
298 {
299 case COLUMN_NAME: return minNameWidth + extra_width;
300 case COLUMN_NETCLASS: return minNameWidth + margins;
301 case COLUMN_VIA_COUNT: return minNumberWidth + margins;
302 case COLUMN_PAD_COUNT: return minNumberWidth + margins;
303 default: return minValueWidth + margins;
304 }
305 };
306
307 wxASSERT( m_columns.size() == cfg->col_order.size() );
308
309 for( size_t i = 0; i < m_columns.size(); ++i )
310 {
311 const int modelColumn = cfg->col_order[i];
312 int titleSize = GetTextExtent( m_columns[modelColumn].display_name ).x;
313 titleSize = modelColumn == COLUMN_NAME ? titleSize + extra_width : titleSize + margins;
314 const int valSize = getTargetWidth( modelColumn );
315 m_netsList->GetColumn( i )->SetWidth( std::max( titleSize, valSize ) );
316 }
317 }
318 else
319 {
320 wxASSERT( m_columns.size() == cfg->col_hidden.size() );
321 wxASSERT( m_columns.size() == cfg->col_widths.size() );
322
323 for( size_t ii = 0; ii < m_columns.size(); ++ii )
324 {
325 const int newWidth = cfg->col_widths[ii];
326 // Make sure we end up with something non-zero so we can resize it
327 m_netsList->GetColumn( ii )->SetWidth( std::max( newWidth, 10 ) );
328 m_netsList->GetColumn( ii )->SetHidden( cfg->col_hidden[ii] );
329 }
330 }
331
332 m_netsList->Refresh();
333}
334
335
336bool PCB_NET_INSPECTOR_PANEL::restoreSortColumn( const int sortingColumnId, const bool sortOrderAsc ) const
337{
338 if( sortingColumnId != -1 )
339 {
340 if( wxDataViewColumn* col = getDisplayedColumnForModelField( sortingColumnId ) )
341 {
342 col->SetSortOrder( sortOrderAsc );
343 m_dataModel->Resort();
344 return true;
345 }
346 }
347
348 return false;
349}
350
351
352wxDataViewColumn* PCB_NET_INSPECTOR_PANEL::getDisplayedColumnForModelField( const int columnId ) const
353{
354 for( unsigned int i = 0; i < m_netsList->GetColumnCount(); ++i )
355 {
356 wxDataViewColumn* col = m_netsList->GetColumn( i );
357
358 if( static_cast<int>( col->GetModelColumn() ) == columnId )
359 return col;
360 }
361
362 return nullptr;
363}
364
365
366/*****************************************************************************************
367 *
368 * Nets list generation
369 *
370 * ***************************************************************************************/
371
372
373void PCB_NET_INSPECTOR_PANEL::buildNetsList( const bool rebuildColumns )
374{
375 // Only build the list of nets if there is a board present
376 if( !m_board )
377 return;
378
379 m_inBuildNetsList = true;
380
381 m_netsList->Freeze();
382
383 m_dataModel->SetIsTimeDomain( m_showTimeDomainDetails );
384
387
388 // Refresh all filtering / grouping settings
395
396 // Attempt to keep any expanded groups open
398 {
399 cfg->expanded_rows.clear();
400 DATA_MODEL* model = static_cast<DATA_MODEL*>( m_netsList->GetModel() );
401
402 for( const auto& groupItems = model->getGroupDataViewItems();
403 auto& [groupName, groupItem] : groupItems )
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,
1179 _( "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,
1185 _( "Filter by Netclass" ),
1186 wxEmptyString, wxITEM_CHECK );
1187 menu.Append( filterByNetclass );
1188 filterByNetclass->Check( cfg.filter_by_netclass );
1189
1190 menu.AppendSeparator();
1191
1192 // Grouping menu items
1193 //wxMenuItem* groupConstraint =
1194 // new wxMenuItem( &menu, ID_GROUP_BY_CONSTRAINT, _( "Group by DRC Constraint" ),
1195 // wxEmptyString, wxITEM_CHECK );
1196 //groupConstraint->Check( m_group_by_constraint );
1197 //menu.Append( groupConstraint );
1198
1199 wxMenuItem* groupNetclass = new wxMenuItem( &menu, ID_GROUP_BY_NETCLASS,
1200 _( "Group by Netclass" ),
1201 wxEmptyString, wxITEM_CHECK );
1202 menu.Append( groupNetclass );
1203 groupNetclass->Check( m_groupByNetclass );
1204
1205 menu.AppendSeparator();
1206
1207 wxMenuItem* addGroup = new wxMenuItem( &menu, ID_ADD_GROUP, _( "Add Custom Group..." ),
1208 wxEmptyString, wxITEM_NORMAL );
1209 menu.Append( addGroup );
1210
1211 wxMenuItem* removeSelectedGroup = new wxMenuItem( &menu, ID_REMOVE_SELECTED_GROUP,
1212 _( "Remove Selected Custom Group" ),
1213 wxEmptyString, wxITEM_NORMAL );
1214 menu.Append( removeSelectedGroup );
1215
1216 if( !selItem || !selItem->GetIsGroup() )
1217 removeSelectedGroup->Enable( false );
1218
1219 wxMenuItem* removeCustomGroups = new wxMenuItem( &menu, ID_REMOVE_GROUPS,
1220 _( "Remove All Custom Groups" ),
1221 wxEmptyString, wxITEM_NORMAL );
1222 menu.Append( removeCustomGroups );
1223 removeCustomGroups->Enable( m_custom_group_rules.size() != 0 );
1224
1225 menu.AppendSeparator();
1226
1227 wxMenuItem* showZeroNetPads = new wxMenuItem( &menu, ID_SHOW_ZERO_NET_PADS,
1228 _( "Show Zero Pad Nets" ),
1229 wxEmptyString, wxITEM_CHECK );
1230 menu.Append( showZeroNetPads );
1231 showZeroNetPads->Check( m_showZeroPadNets );
1232
1233 wxMenuItem* showUnconnectedNets = new wxMenuItem( &menu, ID_SHOW_UNCONNECTED_NETS,
1234 _( "Show Unconnected Nets" ),
1235 wxEmptyString, wxITEM_CHECK );
1236 menu.Append( showUnconnectedNets );
1237 showUnconnectedNets->Check( m_showUnconnectedNets );
1238
1239 menu.AppendSeparator();
1240
1241 wxMenuItem* showTimeDomainDetails = new wxMenuItem( &menu, ID_SHOW_TIME_DOMAIN_DETAILS,
1242 _( "Show Time Domain Details" ), wxEmptyString, wxITEM_CHECK );
1243 menu.Append( showTimeDomainDetails );
1244 showTimeDomainDetails->Check( m_showTimeDomainDetails );
1245
1246 menu.AppendSeparator();
1247
1248 // Report generation
1249 wxMenuItem* generateReport = new wxMenuItem( &menu, ID_GENERATE_REPORT,
1250 _( "Save Net Inspector Report..." ),
1251 wxEmptyString, wxITEM_NORMAL );
1252 menu.Append( generateReport );
1253
1254 menu.AppendSeparator();
1255
1256 // Show / hide columns menu items
1257 wxMenu* colsMenu = new wxMenu();
1258 generateShowHideColumnMenu( colsMenu );
1259 menu.AppendSubMenu( colsMenu, _( "Show / Hide Columns" ) );
1260
1261 menu.Bind( wxEVT_COMMAND_MENU_SELECTED, &PCB_NET_INSPECTOR_PANEL::onContextMenuSelection, this );
1262
1263 PopupMenu( &menu );
1264}
1265
1266
1268{
1269 for( int i = 1; i <= COLUMN_LAST_STATIC_COL; ++i )
1270 {
1271 wxMenuItem* opt = new wxMenuItem( target, ID_HIDE_COLUMN + i, m_columns[i].display_name,
1272 wxEmptyString, wxITEM_CHECK );
1273 wxDataViewColumn* col = getDisplayedColumnForModelField( i );
1274 target->Append( opt );
1275 opt->Check( !col->IsHidden() );
1276 }
1277
1278 target->AppendSeparator();
1279
1280 for( std::size_t i = COLUMN_LAST_STATIC_COL + 1; i < m_columns.size(); ++i )
1281 {
1282 wxMenuItem* opt = new wxMenuItem( target, ID_HIDE_COLUMN + i, m_columns[i].display_name,
1283 wxEmptyString, wxITEM_CHECK );
1284 wxDataViewColumn* col = getDisplayedColumnForModelField( i );
1285 target->Append( opt );
1286 opt->Check( !col->IsHidden() );
1287 }
1288}
1289
1290
1292{
1293 bool saveAndRebuild = true;
1294
1295 switch( event.GetId() )
1296 {
1297 case ID_ADD_NET:
1298 onAddNet();
1299 break;
1300
1301 case ID_RENAME_NET:
1303 break;
1304
1305 case ID_DELETE_NET:
1307 break;
1308
1309 case ID_ADD_GROUP:
1310 onAddGroup();
1311 break;
1312
1314
1316
1318
1320
1323 break;
1324
1325 case ID_REMOVE_GROUPS:
1326 m_custom_group_rules.clear();
1327 break;
1328
1330
1332
1334
1335 case ID_GENERATE_REPORT:
1337 saveAndRebuild = false;
1338 break;
1339
1342 saveAndRebuild = false;
1343 break;
1344
1347 saveAndRebuild = false;
1348 break;
1349
1350 default:
1351 if( event.GetId() >= ID_HIDE_COLUMN )
1352 {
1353 const int columnId = event.GetId() - ID_HIDE_COLUMN;
1354 wxDataViewColumn* col = getDisplayedColumnForModelField( columnId );
1355 // Make sure we end up with something non-zero so we can resize it
1356 col->SetWidth( std::max( col->GetWidth(), 10 ) );
1357 col->SetHidden( !col->IsHidden() );
1358 }
1359 break;
1360 }
1361
1362 if( saveAndRebuild )
1363 {
1364 SaveSettings();
1365 buildNetsList();
1366 }
1367}
1368
1369
1371{
1372 if( m_netsList->GetSelectedItemsCount() == 1 )
1373 {
1374 auto* selItem = static_cast<const LIST_ITEM*>( m_netsList->GetSelection().GetID() );
1375
1376 if( selItem->GetIsGroup() )
1377 {
1378 const wxString groupName = selItem->GetGroupName();
1379 const auto groupIter = std::ranges::find_if( m_custom_group_rules,
1380 [&]( std::unique_ptr<EDA_COMBINED_MATCHER>& rule )
1381 {
1382 return rule->GetPattern() == groupName;
1383 } );
1384
1385 if( groupIter != m_custom_group_rules.end() )
1386 {
1387 m_custom_group_rules.erase( groupIter );
1388 SaveSettings();
1389 buildNetsList();
1390 }
1391 }
1392 }
1393}
1394
1395
1397{
1398 wxFileDialog dlg( this, _( "Save Net Inspector Report File" ), "", "",
1399 _( "Report file" ) + AddFileExtListToFilter( { "csv" } ),
1400 wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
1401
1402 if( dlg.ShowModal() == wxID_CANCEL )
1403 return;
1404
1405 wxTextFile f( dlg.GetPath() );
1406
1407 f.Create();
1408
1409 wxString txt;
1410
1411 m_inReporting = true;
1412
1413 // Print Header:
1414 for( auto&& col : m_columns )
1415 {
1416 txt += '"';
1417
1418 if( col.has_units )
1419 {
1420 txt += wxString::Format( _( "%s (%s)" ),
1421 col.csv_name,
1422 EDA_UNIT_UTILS::GetLabel( m_frame->GetUserUnits() ) );
1423 }
1424 else
1425 {
1426 txt += col.csv_name;
1427 }
1428
1429 txt += wxT( "\";" );
1430 }
1431
1432 f.AddLine( txt );
1433
1434 // Print list of nets:
1435 const unsigned int num_rows = m_dataModel->itemCount();
1436
1437 for( unsigned int row = 0; row < num_rows; row++ )
1438 {
1439 auto& i = m_dataModel->itemAt( row );
1440
1441 if( i.GetIsGroup() || i.GetNetCode() == 0 )
1442 continue;
1443
1444 txt = "";
1445
1446 for( auto&& col : m_columns )
1447 {
1448 if( static_cast<int>( col.csv_flags ) & static_cast<int>( CSV_COLUMN_DESC::CSV_QUOTE ) )
1449 txt += '"' + m_dataModel->valueAt( col.num, row ).GetString() + wxT( "\";" );
1450 else
1451 txt += m_dataModel->valueAt( col.num, row ).GetString() + ';';
1452 }
1453
1454 f.AddLine( txt );
1455 }
1456
1457 m_inReporting = false;
1458
1459 f.Write();
1460 f.Close();
1461}
1462
1463
1465{
1467}
1468
1469
1471{
1472 // ignore selection changes while the whole list is being rebuilt.
1473 if( m_inBuildNetsList )
1474 return;
1475
1476 m_highlightingNets = true;
1477
1478 RENDER_SETTINGS* renderSettings = m_frame->GetCanvas()->GetView()->GetPainter()->GetSettings();
1479
1480 if( m_netsList->HasSelection() )
1481 {
1482 wxDataViewItemArray sel;
1483 m_netsList->GetSelections( sel );
1484
1485 renderSettings->SetHighlight( false );
1486
1487 for( unsigned int i = 0; i < sel.GetCount(); ++i )
1488 {
1489 const LIST_ITEM* ii = static_cast<const LIST_ITEM*>( sel.Item( i ).GetID() );
1490
1491 if( ii->GetIsGroup() )
1492 {
1493 for( auto c = ii->ChildrenBegin(), end = ii->ChildrenEnd(); c != end; ++c )
1494 renderSettings->SetHighlight( true, ( *c )->GetNetCode(), true );
1495 }
1496 else
1497 {
1498 renderSettings->SetHighlight( true, ii->GetNetCode(), true );
1499 }
1500 }
1501 }
1502 else
1503 {
1504 renderSettings->SetHighlight( false );
1505 }
1506
1507 m_frame->GetCanvas()->GetView()->UpdateAllLayersColor();
1508 m_frame->GetCanvas()->Refresh();
1509
1510 m_highlightingNets = false;
1511}
1512
1513
1514void PCB_NET_INSPECTOR_PANEL::OnColumnSorted( wxDataViewEvent& event )
1515{
1516 if( !m_inBuildNetsList )
1517 SaveSettings();
1518}
1519
1520
1522{
1523 // Rebuilt the nets list, and force rebuild of columns in case the stackup has changed
1524 buildNetsList( true );
1525}
1526
1527
1529{
1530 wxString newNetName;
1531 NETNAME_VALIDATOR validator( &newNetName );
1532
1533 WX_TEXT_ENTRY_DIALOG dlg( this, _( "Net name:" ), _( "New Net" ), newNetName );
1534 dlg.SetTextValidator( validator );
1535
1536 while( true )
1537 {
1538 if( dlg.ShowModal() != wxID_OK || dlg.GetValue().IsEmpty() )
1539 return; //Aborted by user
1540
1541 newNetName = dlg.GetValue();
1542
1543 if( m_board->FindNet( newNetName ) )
1544 {
1545 DisplayError( this,
1546 wxString::Format( _( "Net name '%s' is already in use." ), newNetName ) );
1547 newNetName = wxEmptyString;
1548 }
1549 else
1550 {
1551 break;
1552 }
1553 }
1554
1555 NETINFO_ITEM* newnet = new NETINFO_ITEM( m_board, dlg.GetValue(), 0 );
1556
1557 m_board->Add( newnet );
1558
1559 // We'll get an OnBoardItemAdded callback from this to update our listbox
1560 m_frame->OnModify();
1561}
1562
1563
1565{
1566 if( m_netsList->GetSelectedItemsCount() == 1 )
1567 {
1568 const LIST_ITEM* sel = static_cast<const LIST_ITEM*>( m_netsList->GetSelection().GetID() );
1569
1570 if( sel->GetIsGroup() )
1571 return;
1572
1573 NETINFO_ITEM* net = sel->GetNet();
1574 wxString fullNetName = net->GetNetname();
1575 wxString netPath;
1576 wxString shortNetName;
1577
1578 if( fullNetName.Contains( wxT( "/" ) ) )
1579 {
1580 netPath = fullNetName.BeforeLast( '/' ) + '/';
1581 shortNetName = fullNetName.AfterLast( '/' );
1582 }
1583 else
1584 {
1585 shortNetName = fullNetName;
1586 }
1587
1588 wxString unescapedShortName = UnescapeString( shortNetName );
1589
1590 WX_TEXT_ENTRY_DIALOG dlg( this, _( "Net name:" ), _( "Rename Net" ), unescapedShortName );
1591 NETNAME_VALIDATOR validator( &unescapedShortName );
1592 dlg.SetTextValidator( validator );
1593
1594 while( true )
1595 {
1596 if( dlg.ShowModal() != wxID_OK || dlg.GetValue() == unescapedShortName )
1597 return;
1598
1599 unescapedShortName = dlg.GetValue();
1600
1601 if( unescapedShortName.IsEmpty() )
1602 {
1603 DisplayError( this, wxString::Format( _( "Net name cannot be empty." ),
1604 unescapedShortName ) );
1605 continue;
1606 }
1607
1608 shortNetName = EscapeString( unescapedShortName, CTX_NETNAME );
1609 fullNetName = netPath + shortNetName;
1610
1611 if( m_board->FindNet( shortNetName ) || m_board->FindNet( fullNetName ) )
1612 {
1613 DisplayError( this, wxString::Format( _( "Net name '%s' is already in use." ),
1614 unescapedShortName ) );
1615 unescapedShortName = wxEmptyString;
1616 }
1617 else
1618 {
1619 break;
1620 }
1621 }
1622
1623 for( BOARD_CONNECTED_ITEM* boardItem : m_frame->GetBoard()->AllConnectedItems() )
1624 {
1625 if( boardItem->GetNet() == net )
1626 boardItem->SetFlags( CANDIDATE );
1627 else
1628 boardItem->ClearFlags( CANDIDATE );
1629 }
1630
1631 // the changed name might require re-grouping. remove/re-insert is easier.
1632 auto removed_item = m_dataModel->deleteItem( m_dataModel->findItem( net ) );
1633
1634 m_board->Remove( net );
1635 net->SetNetname( fullNetName );
1636 m_board->Add( net );
1637
1638 for( BOARD_CONNECTED_ITEM* boardItem : m_frame->GetBoard()->AllConnectedItems() )
1639 {
1640 if( boardItem->GetFlags() & CANDIDATE )
1641 boardItem->SetNet( net );
1642 }
1643
1644 buildNetsList();
1645
1646 if( std::optional<LIST_ITEM_ITER> r = m_dataModel->findItem( net ) )
1647 m_netsList->Select( wxDataViewItem( r.value()->get() ) );
1648
1649 m_frame->OnModify();
1650
1651 // Currently only tracks and pads have netname annotations and need to be redrawn,
1652 // but zones are likely to follow. Since we don't have a way to ask what is current,
1653 // just refresh all items.
1654 m_frame->GetCanvas()->GetView()->UpdateAllItems( KIGFX::REPAINT );
1655 m_frame->GetCanvas()->Refresh();
1656 }
1657}
1658
1659
1661{
1662 if( !m_netsList->HasSelection() )
1663 return;
1664
1665 wxDataViewItemArray sel;
1666 m_netsList->GetSelections( sel );
1667
1668 auto delete_one = [this]( const LIST_ITEM* i )
1669 {
1670 if( i->GetPadCount() == 0
1671 || IsOK( this, wxString::Format( _( "Net '%s' is in use. Delete anyway?" ),
1672 i->GetNetName() ) ) )
1673 {
1674 // This is a bit hacky, but it will do for now, since this is the only path
1675 // outside the netlist updater where you can remove a net from a BOARD.
1676 int removedCode = i->GetNetCode();
1677
1678 m_frame->GetCanvas()->GetView()->UpdateAllItemsConditionally(
1679 [removedCode]( KIGFX::VIEW_ITEM* aItem ) -> int
1680 {
1681 auto boardItem = dynamic_cast<BOARD_CONNECTED_ITEM*>( aItem );
1682
1683 if( boardItem && boardItem->GetNetCode() == removedCode )
1684 return KIGFX::REPAINT;
1685
1686 EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( aItem );
1687
1688 if( text && text->HasTextVars() )
1689 {
1690 text->ClearRenderCache();
1691 text->ClearBoundingBoxCache();
1693 }
1694
1695 return 0;
1696 } );
1697
1698 m_board->Remove( i->GetNet() );
1699 m_frame->OnModify();
1700
1701 // We'll get an OnBoardItemRemoved callback from this to update our listbox
1702 }
1703 };
1704
1705 for( unsigned int i = 0; i < sel.GetCount(); ++i )
1706 {
1707 const LIST_ITEM* ii = static_cast<const LIST_ITEM*>( sel.Item( i ).GetID() );
1708
1709 if( ii->GetIsGroup() )
1710 {
1711 if( ii->ChildrenCount() != 0
1712 && IsOK( this, wxString::Format( _( "Delete all nets in group '%s'?" ),
1713 ii->GetGroupName() ) ) )
1714 {
1715 // we can't be iterating the children container and deleting items from
1716 // it at the same time. thus take a copy of it first.
1717 std::vector<const LIST_ITEM*> children;
1718 children.reserve( ii->ChildrenCount() );
1719 std::copy( ii->ChildrenBegin(), ii->ChildrenEnd(), std::back_inserter( children ) );
1720
1721 for( const LIST_ITEM* c : children )
1722 delete_one( c );
1723 }
1724 }
1725 else
1726 {
1727 delete_one( ii );
1728 }
1729 }
1730}
1731
1732/*****************************************************************************************
1733 *
1734 * Application-generated event handling
1735 *
1736 * ***************************************************************************************/
1737
1738
1740{
1741 SaveSettings();
1742 buildNetsList( true );
1743 m_dataModel->updateAllItems();
1744}
1745
1746
1747void PCB_NET_INSPECTOR_PANEL::onUnitsChanged( wxCommandEvent& event )
1748{
1749 m_dataModel->updateAllItems();
1750 event.Skip();
1751}
1752
1753
1754/*****************************************************************************************
1755 *
1756 * Settings persistence
1757 *
1758 * ***************************************************************************************/
1759
1760
1762{
1763 // Don't save settings if a board has not yet been loaded or the panel hasn't been displayed.
1764 // Events fire while we set up the panel which overwrite the settings we haven't yet loaded.
1765 bool displayed = false;
1766
1767 for( unsigned int ii = 0; ii < m_dataModel->columnCount() && !displayed; ++ii )
1768 {
1769 if( m_netsList->GetColumn( ii )->GetWidth() > 0 )
1770 displayed = true;
1771 }
1772
1773 if( !displayed || !m_boardLoaded || m_boardLoading )
1774 return;
1775
1777 auto& cfg = localSettings.m_NetInspectorPanel;
1778
1779 // User-defined filters / grouping
1780 cfg.filter_text = m_searchCtrl->GetValue();
1781 cfg.filter_by_net_name = m_filterByNetName;
1782 cfg.filter_by_netclass = m_filterByNetclass;
1783 cfg.group_by_netclass = m_groupByNetclass;
1784 cfg.group_by_constraint = m_groupByConstraint;
1785 cfg.show_zero_pad_nets = m_showZeroPadNets;
1786 cfg.show_unconnected_nets = m_showUnconnectedNets;
1787 cfg.show_time_domain_details = m_showTimeDomainDetails;
1788
1789 // Grid sorting
1790 wxDataViewColumn* sortingCol = m_netsList->GetSortingColumn();
1791 cfg.sorting_column = sortingCol ? static_cast<int>( sortingCol->GetModelColumn() ) : -1;
1792 cfg.sort_order_asc = sortingCol ? sortingCol->IsSortOrderAscending() : true;
1793
1794 // Column arrangement / sizes
1795 cfg.col_order.resize( m_dataModel->columnCount() );
1796 cfg.col_widths.resize( m_dataModel->columnCount() );
1797 cfg.col_hidden.resize( m_dataModel->columnCount() );
1798
1799 for( unsigned int ii = 0; ii < m_dataModel->columnCount(); ++ii )
1800 {
1801 cfg.col_order[ii] = (int) m_netsList->GetColumn( ii )->GetModelColumn();
1802 cfg.col_widths[ii] = m_netsList->GetColumn( ii )->GetWidth();
1803 cfg.col_hidden[ii] = m_netsList->GetColumn( ii )->IsHidden();
1804 }
1805
1806 // Expanded rows
1807 cfg.expanded_rows.clear();
1808 std::vector<std::pair<wxString, wxDataViewItem>> groupItems = m_dataModel->getGroupDataViewItems();
1809
1810 for( std::pair<wxString, wxDataViewItem>& item : groupItems )
1811 {
1812 if( m_netsList->IsExpanded( item.second ) )
1813 cfg.expanded_rows.push_back( item.first );
1814 }
1815
1816 // Customer group rules
1817 cfg.custom_group_rules.clear();
1818
1819 for( const std::unique_ptr<EDA_COMBINED_MATCHER>& rule : m_custom_group_rules )
1820 cfg.custom_group_rules.push_back( rule->GetPattern() );
1821}
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:79
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:317
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:322
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:125
The project local settings are things that are attached to a particular project, but also might be pa...
PANEL_NET_INSPECTOR_SETTINGS m_NetInspectorPanel
The state of the net inspector panel.
virtual PROJECT_LOCAL_SETTINGS & GetLocalSettings() const
Definition project.h:210
PROJECT & Prj() const
A helper while we are not MDI-capable – return the one and only project.
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:674
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:913
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.