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 (C) 2024 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
25#include <confirm.h>
28#include <footprint.h>
29#include <pad.h>
30#include <pcb_edit_frame.h>
31#include <pcb_painter.h>
32#include <pcb_track.h>
33#include <pgm_base.h>
35#include <validators.h>
37#include <eda_pattern_match.h>
38
39#include <wx/wupdlock.h>
40#include <wx/headerctrl.h>
41#include <wx/filedlg.h>
42
43#include <algorithm>
44
46 NET_INSPECTOR_PANEL( parent, aFrame ), m_zero_netitem( nullptr ), m_frame( aFrame )
47{
49
50 m_data_model = new DATA_MODEL( *this );
51 m_netsList->AssociateModel( &*m_data_model );
52
53 // Rebuild nets list
54 buildNetsList( true );
55
56 // Register the panel to receive board change notifications
57 if( m_brd != nullptr )
58 {
60 m_brd->AddListener( this );
61 }
62
63 // Connect to board events
64 m_frame->Bind( EDA_EVT_UNITS_CHANGED, &PCB_NET_INSPECTOR_PANEL::onUnitsChanged, this );
65
66 // Connect to wxDataViewCtrl events
67 m_netsList->Bind( wxEVT_DATAVIEW_ITEM_EXPANDED, &PCB_NET_INSPECTOR_PANEL::OnExpandCollapseRow,
68 this );
69 m_netsList->Bind( wxEVT_DATAVIEW_ITEM_COLLAPSED, &PCB_NET_INSPECTOR_PANEL::OnExpandCollapseRow,
70 this );
71 m_netsList->Bind( wxEVT_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK,
73 m_netsList->Bind( wxEVT_DATAVIEW_ITEM_CONTEXT_MENU,
75 m_netsList->Bind( wxEVT_DATAVIEW_ITEM_ACTIVATED,
77 m_netsList->Bind( wxEVT_DATAVIEW_COLUMN_SORTED,
79}
80
82{
84
85 m_netsList->AssociateModel( nullptr );
86
87 if( m_brd != nullptr )
88 m_brd->RemoveListener( this );
89
90 // Disconnect from board events
91 m_frame->Unbind( EDA_EVT_UNITS_CHANGED, &PCB_NET_INSPECTOR_PANEL::onUnitsChanged, this );
92
93 // Connect to wxDataViewCtrl events
94 m_netsList->Unbind( wxEVT_DATAVIEW_ITEM_EXPANDED, &PCB_NET_INSPECTOR_PANEL::OnExpandCollapseRow,
95 this );
96 m_netsList->Unbind( wxEVT_DATAVIEW_ITEM_COLLAPSED,
98 m_netsList->Unbind( wxEVT_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK,
100 m_netsList->Unbind( wxEVT_DATAVIEW_ITEM_CONTEXT_MENU,
102 m_netsList->Unbind( wxEVT_DATAVIEW_ITEM_ACTIVATED,
104 m_netsList->Unbind( wxEVT_DATAVIEW_COLUMN_SORTED,
106}
107
108
109/*****************************************************************************************
110 *
111 * Grid / model columns configuration
112 *
113 * ***************************************************************************************/
114
115
117{
118 m_columns.clear();
119
120 // Set up the column display vector
121 m_columns.emplace_back( 0u, UNDEFINED_LAYER, _( "Name" ), _( "Net Name" ),
123 m_columns.emplace_back( 1u, UNDEFINED_LAYER, _( "Netclass" ), _( "Netclass" ),
125 m_columns.emplace_back( 2u, UNDEFINED_LAYER, _( "Total Length" ), _( "Net Length" ),
127 m_columns.emplace_back( 3u, UNDEFINED_LAYER, _( "Via Count" ), _( "Via Count" ),
129 m_columns.emplace_back( 4u, UNDEFINED_LAYER, _( "Via Length" ), _( "Via Length" ),
131 m_columns.emplace_back( 5u, UNDEFINED_LAYER, _( "Track Length" ), _( "Track Length" ),
133 m_columns.emplace_back( 6u, UNDEFINED_LAYER, _( "Die Length" ), _( "Die Length" ),
135 m_columns.emplace_back( 7u, UNDEFINED_LAYER, _( "Pad Count" ), _( "Pad Count" ),
137
138 std::vector<std::function<void( void )>> add_col{
139 [&]()
140 {
141 m_netsList->AppendTextColumn( m_columns[COLUMN_NAME].display_name,
142 m_columns[COLUMN_NAME], wxDATAVIEW_CELL_INERT, -1,
143 wxALIGN_LEFT,
144 wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE );
145 },
146 [&]()
147 {
148 m_netsList->AppendTextColumn( m_columns[COLUMN_NETCLASS].display_name,
149 m_columns[COLUMN_NETCLASS], wxDATAVIEW_CELL_INERT, -1,
150 wxALIGN_LEFT,
151 wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_REORDERABLE
152 | wxDATAVIEW_COL_SORTABLE );
153 },
154 [&]()
155 {
156 m_netsList->AppendTextColumn( m_columns[COLUMN_TOTAL_LENGTH].display_name,
157 m_columns[COLUMN_TOTAL_LENGTH], wxDATAVIEW_CELL_INERT, -1,
158 wxALIGN_CENTER,
159 wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_REORDERABLE
160 | wxDATAVIEW_COL_SORTABLE );
161 },
162 [&]()
163 {
164 m_netsList->AppendTextColumn( m_columns[COLUMN_VIA_COUNT].display_name,
165 m_columns[COLUMN_VIA_COUNT], wxDATAVIEW_CELL_INERT, -1,
166 wxALIGN_CENTER,
167 wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_REORDERABLE
168 | wxDATAVIEW_COL_SORTABLE );
169 },
170 [&]()
171 {
172 m_netsList->AppendTextColumn( m_columns[COLUMN_VIA_LENGTH].display_name,
173 m_columns[COLUMN_VIA_LENGTH], wxDATAVIEW_CELL_INERT, -1,
174 wxALIGN_CENTER,
175 wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_REORDERABLE
176 | wxDATAVIEW_COL_SORTABLE );
177 },
178 [&]()
179 {
180 m_netsList->AppendTextColumn( m_columns[COLUMN_BOARD_LENGTH].display_name,
181 m_columns[COLUMN_BOARD_LENGTH], wxDATAVIEW_CELL_INERT, -1,
182 wxALIGN_CENTER,
183 wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_REORDERABLE
184 | wxDATAVIEW_COL_SORTABLE );
185 },
186 [&]()
187 {
188 m_netsList->AppendTextColumn( m_columns[COLUMN_PAD_DIE_LENGTH].display_name,
189 m_columns[COLUMN_PAD_DIE_LENGTH], wxDATAVIEW_CELL_INERT,
190 -1, wxALIGN_CENTER,
191 wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_REORDERABLE
192 | wxDATAVIEW_COL_SORTABLE );
193 },
194 [&]()
195 {
196 m_netsList->AppendTextColumn( m_columns[COLUMN_PAD_COUNT].display_name,
197 m_columns[COLUMN_PAD_COUNT], wxDATAVIEW_CELL_INERT, -1,
198 wxALIGN_CENTER,
199 wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_REORDERABLE
200 | wxDATAVIEW_COL_SORTABLE );
201 }
202 };
203
204 // If we have not yet loaded the first board, use a dummy local settings object to ensure we
205 // don't over-write existing board settings (note that PCB_EDIT_FRAME loads the local settings
206 // object prior to loading the board; the two are not synced and we need to account for that)
207 PANEL_NET_INSPECTOR_SETTINGS* cfg = nullptr;
208
209 if( m_board_loaded )
210 {
212 cfg = &localSettings.m_NetInspectorPanel;
213 }
214 else
215 {
217 }
218
219 // Count number of copper layers
221
222 for( PCB_LAYER_ID layer : m_brd->GetEnabledLayers().Seq() )
223 {
224 if( IsCopperLayer( layer ) )
226 }
227
228 // Reset the column display settings if column count doesn't match
229 const int totalNumColumns = add_col.size() + m_num_copper_layers;
230
231 if( (int) cfg->col_order.size() != totalNumColumns
232 || (int) cfg->col_hidden.size() != totalNumColumns )
233 {
234 cfg->col_order.resize( totalNumColumns );
235 cfg->col_hidden.resize( totalNumColumns );
236
237 for( int i = 0; i < totalNumColumns; ++i )
238 {
239 cfg->col_order[i] = i;
240 cfg->col_hidden[i] = false;
241 }
242 }
243
244 // Check that all rows are unique to protect against corrupted settings data
245 std::set<int> col_order_set( cfg->col_order.begin(), cfg->col_order.end() );
246 if( col_order_set.size() != cfg->col_order.size() )
247 {
248 for( std::size_t i = 0; i < cfg->col_order.size(); ++i )
249 cfg->col_order[i] = i;
250 }
251
252 // Add column records for copper layers
253 for( PCB_LAYER_ID layer : m_brd->GetEnabledLayers().Seq() )
254 {
255 if( !IsCopperLayer( layer ) )
256 continue;
257
258 m_columns.emplace_back( m_columns.size(), layer, m_brd->GetLayerName( layer ),
260 }
261
262 // Add display columns in settings order
263 for( std::size_t i = 0; i < cfg->col_order.size(); ++i )
264 {
265 const int addModelColumn = cfg->col_order[i];
266
267 if( addModelColumn >= (int) add_col.size() )
268 {
269 m_netsList->AppendTextColumn( m_brd->GetLayerName( m_columns[addModelColumn].layer ),
270 m_columns[addModelColumn], wxDATAVIEW_CELL_INERT, -1,
271 wxALIGN_CENTER,
272 wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_REORDERABLE
273 | wxDATAVIEW_COL_SORTABLE );
274 }
275 else
276 {
277 add_col.at( cfg->col_order[i] )();
278 }
279 }
280
281 // Set the name column as the expander row
282 if( wxDataViewColumn* col = getDisplayedColumnForModelField( COLUMN_NAME ) )
283 {
284 m_netsList->SetExpanderColumn( col );
285 }
286
288
289 // Delete the temporary config if used
290 if( !m_board_loaded )
291 {
292 delete cfg;
293 }
294}
295
296
298{
299 wxWindowUpdateLocker locker( m_netsList );
300
301 if( cfg->col_widths.size() != m_columns.size() )
302 {
303 int minValueWidth = GetTextExtent( wxT( "00000,000 mm" ) ).x;
304 int minNumberWidth = GetTextExtent( wxT( "000" ) ).x;
305 int minNameWidth = GetTextExtent( wxT( "MMMMMMMMMMMM" ) ).x;
306
307 // Considering left and right margins.
308 // For wxRenderGeneric it is 5px.
309 // Also account for the sorting arrow in the column header.
310 // Column 0 also needs space for any potential expander icons.
311 const int margins = 15;
312 const int extra_width = 30;
313
314 auto getTargetWidth = [&]( int columnID )
315 {
316 switch( columnID )
317 {
318 case COLUMN_NAME: return minNameWidth + extra_width;
319 case COLUMN_NETCLASS: return minNameWidth + margins;
320 case COLUMN_VIA_COUNT: return minNumberWidth + margins;
321 case COLUMN_PAD_COUNT: return minNumberWidth + margins;
322 default: return minValueWidth + margins;
323 }
324 };
325
326 wxASSERT( m_columns.size() == cfg->col_order.size() );
327
328 for( size_t i = 0; i < m_columns.size(); ++i )
329 {
330 const int modelColumn = cfg->col_order[i];
331 int titleSize = GetTextExtent( m_columns[modelColumn].display_name ).x;
332 titleSize = modelColumn == COLUMN_NAME ? titleSize + extra_width : titleSize + margins;
333 const int valSize = getTargetWidth( modelColumn );
334 m_netsList->GetColumn( i )->SetWidth( std::max( titleSize, valSize ) );
335 }
336 }
337 else
338 {
339 wxASSERT( m_columns.size() == cfg->col_hidden.size() );
340 wxASSERT( m_columns.size() == cfg->col_widths.size() );
341
342 for( size_t ii = 0; ii < m_columns.size(); ++ii )
343 {
344 const int newWidth = cfg->col_widths[ii];
345 // Make sure we end up with something non-zero so we can resize it
346 m_netsList->GetColumn( ii )->SetWidth( std::max( newWidth, 10 ) );
347 m_netsList->GetColumn( ii )->SetHidden( cfg->col_hidden[ii] );
348 }
349 }
350
351 m_netsList->Refresh();
352}
353
354
355bool PCB_NET_INSPECTOR_PANEL::restoreSortColumn( int sortingColumnId, bool sortOrderAsc )
356{
357 if( sortingColumnId != -1 )
358 {
359 if( wxDataViewColumn* col = getDisplayedColumnForModelField( sortingColumnId ) )
360 {
361 col->SetSortOrder( sortOrderAsc );
362 m_data_model->Resort();
363 return true;
364 }
365 }
366
367 return false;
368}
369
370
372{
373 for( unsigned int i = 0; i < m_netsList->GetColumnCount(); ++i )
374 {
375 wxDataViewColumn* col = m_netsList->GetColumn( i );
376
377 if( (int) col->GetModelColumn() == columnId )
378 {
379 return col;
380 }
381 }
382
383 return nullptr;
384}
385
386
387/*****************************************************************************************
388 *
389 * Nets list generation
390 *
391 * ***************************************************************************************/
392
393
394void PCB_NET_INSPECTOR_PANEL::buildNetsList( bool rebuildColumns )
395{
396 // Only build the list of nets if there is a board present
397 if( !m_brd )
398 return;
399
401
404
405 // Refresh all filtering / grouping settings
411
412 // when rebuilding the netlist, try to keep the row selection
413 wxDataViewItemArray sel;
414 m_netsList->GetSelections( sel );
415
416 std::vector<int> prev_selected_netcodes;
417 prev_selected_netcodes.reserve( sel.GetCount() );
418
419 for( unsigned int i = 0; i < sel.GetCount(); ++i )
420 {
421 const LIST_ITEM* item = static_cast<const LIST_ITEM*>( sel.Item( i ).GetID() );
422 prev_selected_netcodes.push_back( item->GetNetCode() );
423 }
424
425 int sorting_column_id = cfg->sorting_column;
426 bool sort_order_asc = cfg->sort_order_asc;
427
428 if( wxDataViewColumn* sorting_column = m_netsList->GetSortingColumn() )
429 {
430 if( !m_board_loading )
431 {
432 sorting_column_id = static_cast<int>( sorting_column->GetModelColumn() );
433 sort_order_asc = sorting_column->IsSortOrderAscending();
434 }
435
436 // On GTK, wxDVC will crash if you rebuild with a sorting column set.
437 sorting_column->UnsetAsSortKey();
438 }
439
440 if( rebuildColumns )
441 {
442 m_netsList->ClearColumns();
443 buildColumns();
444 }
445
446 m_data_model->deleteAllItems();
447
448 m_custom_group_rules.clear();
449
450 for( const wxString& rule : cfg->custom_group_rules )
451 m_custom_group_rules.push_back( std::make_unique<EDA_COMBINED_MATCHER>( rule, CTX_NET ) );
452
453 m_data_model->addCustomGroups();
454
455 std::vector<std::unique_ptr<LIST_ITEM>> new_items;
456
457 std::vector<CN_ITEM*> prefiltered_cn_items = relevantConnectivityItems();
458
459 struct NET_INFO
460 {
461 int netcode;
462 NETINFO_ITEM* net;
463 unsigned int pad_count;
464 };
465
466 struct NET_INFO_CMP_LESS
467 {
468 bool operator()( const NET_INFO& a, const NET_INFO& b ) const
469 {
470 return a.netcode < b.netcode;
471 }
472 bool operator()( const NET_INFO& a, int b ) const { return a.netcode < b; }
473 bool operator()( int a, const NET_INFO& b ) const { return a < b.netcode; }
474 };
475
476 std::vector<NET_INFO> nets;
477 nets.reserve( m_brd->GetNetInfo().NetsByNetcode().size() );
478
479 for( const std::pair<int, NETINFO_ITEM*> ni : m_brd->GetNetInfo().NetsByNetcode() )
480 {
481 if( ni.first == 0 )
482 m_zero_netitem = ni.second;
483
484 if( netFilterMatches( ni.second, cfg ) )
485 nets.emplace_back( NET_INFO{ ni.first, ni.second, 0 } );
486 }
487
488 // count the pads for each net. since the nets are sorted by netcode
489 // iterating over the footprints' pads is faster.
490 for( FOOTPRINT* footprint : m_brd->Footprints() )
491 {
492 for( PAD* pad : footprint->Pads() )
493 {
494 auto i = std::lower_bound( nets.begin(), nets.end(), pad->GetNetCode(),
495 NET_INFO_CMP_LESS() );
496
497 if( i != nets.end() && i->netcode == pad->GetNetCode() )
498 i->pad_count += 1;
499 }
500 }
501
502 for( NET_INFO& ni : nets )
503 {
504 if( m_show_zero_pad_nets || ni.pad_count > 0 )
505 new_items.emplace_back( buildNewItem( ni.net, ni.pad_count, prefiltered_cn_items ) );
506 }
507
508 m_data_model->addItems( std::move( new_items ) );
509
510 // Re-enable the sorting column
511 if( !restoreSortColumn( sorting_column_id, sort_order_asc ))
512 {
513 // By default sort by Name column
515 }
516
517 // Try to restore the expanded groups
518 if( m_board_loaded )
519 {
520 m_row_expanding = true;
521
522 std::vector<std::pair<wxString, wxDataViewItem>> groupItems =
523 m_data_model->getGroupDataViewItems();
524
525 for( wxString& groupName : cfg->expanded_rows )
526 {
527 auto pred =
528 [&groupName]( const std::pair<wxString, wxDataViewItem>& item )
529 {
530 return groupName == item.first;
531 };
532
533 auto tableItem = std::find_if( groupItems.begin(), groupItems.end(), pred );
534
535 if( tableItem != groupItems.end() )
536 m_netsList->Expand( tableItem->second );
537 }
538
539 m_row_expanding = false;
540 }
541
542 // try to restore the selected rows. Set the ones that we can't find any more to -1.
543 sel.Clear();
544
545 for( int& nc : prev_selected_netcodes )
546 {
547 std::optional<LIST_ITEM_ITER> r = m_data_model->findItem( nc );
548
549 if( r )
550 {
551 const std::unique_ptr<LIST_ITEM>& list_item = *r.value();
552 sel.Add( wxDataViewItem( list_item.get() ) );
553 }
554 else
555 {
556 nc = -1;
557 }
558 }
559
560 if( !sel.IsEmpty() )
561 {
562 m_netsList->SetSelections( sel );
563 m_netsList->EnsureVisible( sel.Item( 0 ) );
564 }
565 else
566 {
567 m_netsList->UnselectAll();
568 }
569
570 alg::delete_matching( prev_selected_netcodes, -1 );
571
572 m_in_build_nets_list = false;
573}
574
575
578{
579 if( cfg == nullptr )
580 {
582 cfg = &localSettings.m_NetInspectorPanel;
583 }
584
585 // Never show the unconnected net
586 if( aNet->GetNetCode() <= 0 )
587 return false;
588
589 wxString filterString = UnescapeString( m_searchCtrl->GetValue() ).Upper();
590 wxString netName = UnescapeString( aNet->GetNetname() ).Upper();
591 NETCLASS* netClass = aNet->GetNetClass();
592 wxString netClassName = UnescapeString( netClass->GetName() ).Upper();
593
594 bool matched = false;
595
596 // No filter - match all
597 if( filterString.Length() == 0 )
598 matched = true;
599
600 // Search on Netclass
601 if( !matched && cfg->filter_by_netclass && netClassName.Find( filterString ) != wxNOT_FOUND )
602 matched = true;
603
604 // Search on Net name
605 if( !matched && cfg->filter_by_net_name && netName.Find( filterString ) != wxNOT_FOUND )
606 matched = true;
607
608 // Remove unconnected nets if required
609 if( matched )
610 {
612 matched = !netName.StartsWith( wxT( "UNCONNECTED-(" ) );
613 }
614
615 return matched;
616}
617
618
620{
621 bool operator()( const CN_ITEM* a, const CN_ITEM* b ) const { return a->Net() < b->Net(); }
622
623 bool operator()( const CN_ITEM* a, int b ) const { return a->Net() < b; }
624
625 bool operator()( int a, const CN_ITEM* b ) const { return a < b->Net(); }
626};
627
628
629std::unique_ptr<PCB_NET_INSPECTOR_PANEL::LIST_ITEM>
631 const std::vector<CN_ITEM*>& aCNItems )
632{
633 std::unique_ptr<LIST_ITEM> new_item = std::make_unique<LIST_ITEM>( aNet );
634
635 new_item->SetPadCount( aPadCount );
636 new_item->SetLayerCount( m_brd->GetCopperLayerCount() );
637
638 const auto cn_items = std::equal_range( aCNItems.begin(), aCNItems.end(), aNet->GetNetCode(),
640
641 for( auto i = cn_items.first; i != cn_items.second; ++i )
642 {
643 BOARD_CONNECTED_ITEM* item = ( *i )->Parent();
644
645 if( item->Type() == PCB_PAD_T )
646 {
647 new_item->AddPadDieLength( static_cast<PAD*>( item )->GetPadToDieLength() );
648 }
649 else if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( item ) )
650 {
651 new_item->AddLayerWireLength( track->GetLength(), track->GetLayer() );
652
653 if( item->Type() == PCB_VIA_T )
654 {
655 new_item->AddViaCount( 1 );
656 new_item->AddViaLength( calculateViaLength( track ) );
657 }
658 }
659 }
660
661 return new_item;
662}
663
664
666{
667 // pre-filter the connectivity items and sort them by netcode.
668 // this avoids quadratic runtime when building the whole net list and
669 // calculating the total length for each net.
670 const auto type_bits = std::bitset<MAX_STRUCT_TYPE_ID>()
671 .set( PCB_TRACE_T )
672 .set( PCB_ARC_T )
673 .set( PCB_VIA_T )
674 .set( PCB_PAD_T );
675
676 std::vector<CN_ITEM*> cn_items;
677 cn_items.reserve( 1024 );
678
679 for( CN_ITEM* cn_item : m_brd->GetConnectivity()->GetConnectivityAlgo()->ItemList() )
680 {
681 if( cn_item->Valid() && type_bits[cn_item->Parent()->Type()] )
682 cn_items.push_back( cn_item );
683 }
684
685 std::sort( cn_items.begin(), cn_items.end(), NETCODE_CMP_LESS() );
686
687 return cn_items;
688}
689
690
692{
693 const PCB_VIA* via = dynamic_cast<const PCB_VIA*>( aTrack );
694
695 if( !via )
696 return 0;
697
699
700 // Must be static to keep from raising its ugly head in performance profiles
701 static std::initializer_list<KICAD_T> traceAndPadTypes = { PCB_TRACE_T, PCB_ARC_T, PCB_PAD_T };
702
703 // calculate the via length individually from the board stackup and via's start and end layer.
704 if( bds.m_HasStackup )
705 {
706 PCB_LAYER_ID top_layer = UNDEFINED_LAYER;
707 PCB_LAYER_ID bottom_layer = UNDEFINED_LAYER;
708 LSET layers = bds.GetEnabledLayers();
709
710 for( auto layer_it = layers.copper_layers_begin();
711 layer_it != layers.copper_layers_end();
712 ++layer_it )
713 {
714 if( m_brd->GetConnectivity()->IsConnectedOnLayer( via, *layer_it, traceAndPadTypes ) )
715 {
716 if( top_layer == UNDEFINED_LAYER )
717 top_layer = PCB_LAYER_ID( *layer_it );
718 else
719 bottom_layer = PCB_LAYER_ID( *layer_it );
720 }
721 }
722
723 if( top_layer == UNDEFINED_LAYER )
724 top_layer = via->TopLayer();
725 if( bottom_layer == UNDEFINED_LAYER )
726 bottom_layer = via->BottomLayer();
727
728 const BOARD_STACKUP& stackup = bds.GetStackupDescriptor();
729 return stackup.GetLayerDistance( top_layer, bottom_layer );
730 }
731 else
732 {
733 int dielectricLayers = bds.GetCopperLayerCount() - 1;
734 // TODO: not all dielectric layers are the same thickness!
735 int layerThickness = bds.GetBoardThickness() / dielectricLayers;
736 int effectiveBottomLayer;
737
738 if( via->BottomLayer() == B_Cu )
739 effectiveBottomLayer = F_Cu + dielectricLayers;
740 else
741 effectiveBottomLayer = via->BottomLayer();
742
743 int layerCount = effectiveBottomLayer - via->TopLayer();
744
745 return layerCount * layerThickness;
746 }
747}
748
749
751{
752 // something for the specified net has changed, update that row.
753 // ignore nets that are not in our list because the filter doesn't match.
754 if( !netFilterMatches( aNet ) )
755 {
756 m_data_model->deleteItem( m_data_model->findItem( aNet ) );
757 return;
758 }
759
760 // if the net had no pads before, it might not be in the displayed list yet.
761 // if it had pads and now doesn't anymore, we might need to remove it from the list.
762 std::optional<LIST_ITEM_ITER> cur_net_row = m_data_model->findItem( aNet );
763
764 const unsigned int node_count = m_brd->GetNodesCount( aNet->GetNetCode() );
765
766 if( node_count == 0 && !m_show_zero_pad_nets )
767 {
768 m_data_model->deleteItem( cur_net_row );
769 return;
770 }
771
772 std::unique_ptr<LIST_ITEM> new_list_item = buildNewItem( aNet, node_count,
774
775 if( !cur_net_row )
776 {
777 m_data_model->addItem( std::move( new_list_item ) );
778 return;
779 }
780
781 const std::unique_ptr<LIST_ITEM>& cur_list_item = *cur_net_row.value();
782
783 if( cur_list_item->GetNetName() != new_list_item->GetNetName() )
784 {
785 // if the name has changed, it might require re-grouping.
786 // it's easier to remove and re-insert it
787 m_data_model->deleteItem( cur_net_row );
788 m_data_model->addItem( std::move( new_list_item ) );
789 }
790 else
791 {
792 // update fields only
793 cur_list_item->SetPadCount( new_list_item->GetPadCount() );
794 cur_list_item->SetViaCount( new_list_item->GetViaCount() );
795 cur_list_item->SetLayerWireLength( new_list_item->GetLayerWireLength() );
796 cur_list_item->SetPadDieLength( new_list_item->GetPadDieLength() );
797
798 updateDisplayedRowValues( cur_net_row );
799 }
800}
801
802
803/*****************************************************************************************
804 *
805 * Formatting helpers
806 *
807 * ***************************************************************************************/
808
809
811{
812 return wxString::Format( wxT( "%.3d" ), aNet->GetNetCode() );
813}
814
815
817{
818 return UnescapeString( aNet->GetNetname() );
819}
820
821
822wxString PCB_NET_INSPECTOR_PANEL::formatCount( unsigned int aValue ) const
823{
824 return wxString::Format( wxT( "%u" ), aValue );
825}
826
827
828wxString PCB_NET_INSPECTOR_PANEL::formatLength( int64_t aValue ) const
829{
830 return m_frame->MessageTextFromValue( static_cast<long long int>( aValue ),
831 // don't include unit label in the string when reporting
833}
834
835
836void PCB_NET_INSPECTOR_PANEL::updateDisplayedRowValues( const std::optional<LIST_ITEM_ITER>& aRow )
837{
838 if( !aRow )
839 return;
840
841 wxDataViewItemArray sel;
842 m_netsList->GetSelections( sel );
843
844 m_data_model->updateItem( aRow );
845
846 if( !sel.IsEmpty() )
847 {
848 m_netsList->SetSelections( sel );
849 m_netsList->EnsureVisible( sel.Item( 0 ) );
850 }
851}
852
853
854/*****************************************************************************************
855 *
856 * BOARD_LISTENER event handling
857 *
858 * ***************************************************************************************/
859
860
862{
864
865 if( m_brd != nullptr )
866 m_brd->AddListener( this );
867
868 m_board_loaded = true;
869 m_board_loading = true;
870
872 auto& cfg = localSettings.m_NetInspectorPanel;
873 m_searchCtrl->SetValue( cfg.filter_text );
874
875 buildNetsList( true );
876
877 m_board_loading = false;
878}
879
881{
882 if( !IsShownOnScreen() )
883 return;
884
885 if( NETINFO_ITEM* net = dynamic_cast<NETINFO_ITEM*>( aBoardItem ) )
886 {
887 // a new net has been added to the board. add it to our list if it
888 // passes the netname filter test.
889
890 if( netFilterMatches( net ) )
891 {
892 std::unique_ptr<LIST_ITEM> new_item = std::make_unique<LIST_ITEM>( net );
893
894 // the new net could have some pads already assigned, count them.
895 new_item->SetPadCount( m_brd->GetNodesCount( net->GetNetCode() ) );
896 new_item->SetLayerCount( m_brd->GetCopperLayerCount() );
897
898 m_data_model->addItem( std::move( new_item ) );
899 }
900 }
901 else if( BOARD_CONNECTED_ITEM* i = dynamic_cast<BOARD_CONNECTED_ITEM*>( aBoardItem ) )
902 {
903 std::optional<LIST_ITEM_ITER> r = m_data_model->findItem( i->GetNet() );
904
905 if( r )
906 {
907 // try to handle frequent operations quickly.
908 if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( i ) )
909 {
910 const std::unique_ptr<LIST_ITEM>& list_item = *r.value();
911 int len = track->GetLength();
912
913 list_item->AddLayerWireLength( len, track->GetLayer() );
914
915 if( track->Type() == PCB_VIA_T )
916 {
917 list_item->AddViaCount( 1 );
918 list_item->AddViaLength( calculateViaLength( track ) );
919 }
920
922 return;
923 }
924 }
925
926 // resort to generic slower net update otherwise.
927 updateNet( i->GetNet() );
928 }
929 else if( FOOTPRINT* footprint = dynamic_cast<FOOTPRINT*>( aBoardItem ) )
930 {
931 for( const PAD* pad : footprint->Pads() )
932 {
933 std::optional<LIST_ITEM_ITER> r = m_data_model->findItem( pad->GetNet() );
934
935 if( !r )
936 {
937 // if show-zero-pads is off, we might not have this net
938 // in our list yet, so add it first.
939 // notice that at this point we are very certain that this net
940 // will have at least one pad.
941
942 if( netFilterMatches( pad->GetNet() ) )
943 r = m_data_model->addItem( std::make_unique<LIST_ITEM>( pad->GetNet() ) );
944 }
945
946 if( r )
947 {
948 const std::unique_ptr<LIST_ITEM>& list_item = *r.value();
949 int len = pad->GetPadToDieLength();
950
951 list_item->AddPadCount( 1 );
952 list_item->AddPadDieLength( len );
953 list_item->SetLayerCount( m_brd->GetCopperLayerCount() );
954
955 if( list_item->GetPadCount() == 0 && !m_show_zero_pad_nets )
956 m_data_model->deleteItem( r );
957 else
959 }
960 }
961 }
962}
963
964
966 std::vector<BOARD_ITEM*>& aBoardItems )
967{
968 if( !IsShownOnScreen() )
969 return;
970
971 // Rebuild full netlist for large changes
972 if( aBoardItems.size() > 25 )
973 {
975 m_netsList->Refresh();
976 }
977 else
978 {
979 for( BOARD_ITEM* item : aBoardItems )
980 {
981 OnBoardItemAdded( aBoard, item );
982 }
983 }
984}
985
986
988{
989 if( !IsShownOnScreen() )
990 return;
991
992 if( NETINFO_ITEM* net = dynamic_cast<NETINFO_ITEM*>( aBoardItem ) )
993 {
994 m_data_model->deleteItem( m_data_model->findItem( net ) );
995 }
996 else if( FOOTPRINT* footprint = dynamic_cast<FOOTPRINT*>( aBoardItem ) )
997 {
998 for( const PAD* pad : footprint->Pads() )
999 {
1000 std::optional<LIST_ITEM_ITER> r = m_data_model->findItem( pad->GetNet() );
1001
1002 if( r )
1003 {
1004 const std::unique_ptr<LIST_ITEM>& list_item = *r.value();
1005 int len = pad->GetPadToDieLength();
1006
1007 list_item->SubPadCount( 1 );
1008 list_item->SubPadDieLength( len );
1009
1010 if( list_item->GetPadCount() == 0 && !m_show_zero_pad_nets )
1011 m_data_model->deleteItem( r );
1012 else
1014 }
1015 }
1016 }
1017 else if( BOARD_CONNECTED_ITEM* i = dynamic_cast<BOARD_CONNECTED_ITEM*>( aBoardItem ) )
1018 {
1019 std::optional<LIST_ITEM_ITER> r = m_data_model->findItem( i->GetNet() );
1020
1021 if( r )
1022 {
1023 // try to handle frequent operations quickly.
1024 if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( i ) )
1025 {
1026 const std::unique_ptr<LIST_ITEM>& list_item = *r.value();
1027 int len = track->GetLength();
1028
1029 list_item->SubLayerWireLength( len, track->GetLayer() );
1030
1031 if( track->Type() == PCB_VIA_T )
1032 {
1033 list_item->SubViaCount( 1 );
1034 list_item->SubViaLength( calculateViaLength( track ) );
1035 }
1036
1038 return;
1039 }
1040
1041 // resort to generic slower net update otherwise.
1042 updateNet( i->GetNet() );
1043 }
1044 }
1045}
1046
1047
1049 std::vector<BOARD_ITEM*>& aBoardItems )
1050{
1051 if( !IsShownOnScreen() )
1052 return;
1053
1054 if( aBoardItems.size() > 25 )
1055 {
1056 buildNetsList();
1057 m_netsList->Refresh();
1058 }
1059 else
1060 {
1061 for( BOARD_ITEM* item : aBoardItems )
1062 {
1063 OnBoardItemRemoved( aBoard, item );
1064 }
1065 }
1066}
1067
1068
1070{
1071 if( !IsShownOnScreen() )
1072 return;
1073
1074 buildNetsList();
1075 m_netsList->Refresh();
1076}
1077
1078
1080{
1081 if( !IsShownOnScreen() )
1082 return;
1083
1084 if( dynamic_cast<BOARD_CONNECTED_ITEM*>( aBoardItem ) != nullptr
1085 || dynamic_cast<FOOTPRINT*>( aBoardItem ) != nullptr )
1086 {
1087 buildNetsList();
1088 m_netsList->Refresh();
1089 }
1090}
1091
1092
1094 std::vector<BOARD_ITEM*>& aBoardItems )
1095{
1096 if( !IsShownOnScreen() )
1097 return;
1098
1099 buildNetsList();
1100 m_netsList->Refresh();
1101}
1102
1103
1105 std::vector<BOARD_ITEM*>& aAddedItems,
1106 std::vector<BOARD_ITEM*>& aRemovedItems,
1107 std::vector<BOARD_ITEM*>& aDeletedItems )
1108{
1109 if( !IsShownOnScreen() )
1110 return;
1111
1112 buildNetsList();
1113 m_netsList->Refresh();
1114}
1115
1116
1118{
1119 if( m_highlighting_nets || !IsShownOnScreen() )
1120 return;
1121
1122 if( !m_brd->IsHighLightNetON() )
1123 {
1124 m_netsList->UnselectAll();
1125 }
1126 else
1127 {
1128 const std::set<int>& selected_codes = m_brd->GetHighLightNetCodes();
1129
1130 wxDataViewItemArray new_selection;
1131 new_selection.Alloc( selected_codes.size() );
1132
1133 for( int code : selected_codes )
1134 {
1135 if( std::optional<LIST_ITEM_ITER> r = m_data_model->findItem( code ) )
1136 new_selection.Add( wxDataViewItem( &***r ) );
1137 }
1138
1139 m_netsList->SetSelections( new_selection );
1140
1141 if( !new_selection.IsEmpty() )
1142 m_netsList->EnsureVisible( new_selection.Item( 0 ) );
1143 }
1144}
1145
1146
1147/*****************************************************************************************
1148 *
1149 * UI-generated event handling
1150 *
1151 * ***************************************************************************************/
1152
1154{
1155 buildNetsList();
1157}
1158
1159
1161{
1162 bool multipleSelections = false;
1163 const LIST_ITEM* selItem = nullptr;
1164
1165 if( m_netsList->GetSelectedItemsCount() == 1 )
1166 {
1167 selItem = static_cast<const LIST_ITEM*>( m_netsList->GetSelection().GetID() );
1168 }
1169 else
1170 {
1171 if( m_netsList->GetSelectedItemsCount() > 1 )
1172 multipleSelections = true;
1173 }
1174
1175 wxMenu menu;
1176
1177 // Net edit menu items
1178 wxMenuItem* highlightNet = new wxMenuItem( &menu, ID_HIGHLIGHT_SELECTED_NETS,
1179 _( "Highlight Selected Net" ),
1180 wxEmptyString, wxITEM_NORMAL );
1181 menu.Append( highlightNet );
1182
1183 wxMenuItem* clearHighlighting = new wxMenuItem( &menu, ID_CLEAR_HIGHLIGHTING,
1184 _( "Clear Net Highlighting" ),
1185 wxEmptyString, wxITEM_NORMAL );
1186 menu.Append( clearHighlighting );
1187
1188 RENDER_SETTINGS* renderSettings = m_frame->GetCanvas()->GetView()->GetPainter()->GetSettings();
1189 const std::set<int>& selected_codes = renderSettings->GetHighlightNetCodes();
1190
1191 if( selected_codes.size() == 0 )
1192 clearHighlighting->Enable( false );
1193
1194 menu.AppendSeparator();
1195
1196 wxMenuItem* renameNet = new wxMenuItem( &menu, ID_RENAME_NET, _( "Rename Selected Net" ),
1197 wxEmptyString, wxITEM_NORMAL );
1198 menu.Append( renameNet );
1199
1200 wxMenuItem* deleteNet = new wxMenuItem( &menu, ID_DELETE_NET, _( "Delete Selected Net" ),
1201 wxEmptyString, wxITEM_NORMAL );
1202 menu.Append( deleteNet );
1203
1204 menu.AppendSeparator();
1205
1206 wxMenuItem* addNet = new wxMenuItem( &menu, ID_ADD_NET, _( "Add Net" ),
1207 wxEmptyString, wxITEM_NORMAL );
1208 menu.Append( addNet );
1209
1210 if( !selItem && !multipleSelections )
1211 {
1212 highlightNet->Enable( false );
1213 deleteNet->Enable( false );
1214 renameNet->Enable( false );
1215 }
1216 else
1217 {
1218 if( multipleSelections || selItem->GetIsGroup() )
1219 {
1220 highlightNet->SetItemLabel( _( "Highlight Selected Nets" ) );
1221 renameNet->Enable( false );
1222 deleteNet->SetItemLabel( _( "Delete Selected Nets" ) );
1223 }
1224 }
1225
1226 menu.AppendSeparator();
1227
1228 wxMenuItem* removeSelectedGroup = new wxMenuItem( &menu, ID_REMOVE_SELECTED_GROUP,
1229 _( "Remove Selected Custom Group" ),
1230 wxEmptyString, wxITEM_NORMAL );
1231 menu.Append( removeSelectedGroup );
1232
1233 if( !selItem || !selItem->GetIsGroup() )
1234 removeSelectedGroup->Enable( false );
1235
1236 menu.Bind( wxEVT_COMMAND_MENU_SELECTED, &PCB_NET_INSPECTOR_PANEL::onSettingsMenu, this );
1237
1238 PopupMenu( &menu );
1239}
1240
1241
1243{
1244 SaveSettings();
1245 buildNetsList();
1246}
1247
1248
1250{
1251 wxString newGroupName;
1252 NETNAME_VALIDATOR validator( &newGroupName );
1253
1254 WX_TEXT_ENTRY_DIALOG dlg( this, _( "Group name / pattern:" ), _( "New Group" ), newGroupName );
1255 wxStaticText* help = new wxStaticText( &dlg, wxID_ANY,
1256 _( "(Use /.../ to indicate a regular expression.)" ) );
1257 help->SetFont( KIUI::GetInfoFont( this ).Italic() );
1258 dlg.m_ContentSizer->Add( help, 0, wxALL|wxEXPAND, 5 );
1259 dlg.SetTextValidator( validator );
1260 dlg.GetSizer()->SetSizeHints( &dlg );
1261
1262 if( dlg.ShowModal() != wxID_OK || dlg.GetValue().IsEmpty() )
1263 return; //Aborted by user
1264
1265 newGroupName = UnescapeString( dlg.GetValue() );
1266
1267 if( newGroupName == "" )
1268 return;
1269
1270 if( std::find_if( m_custom_group_rules.begin(), m_custom_group_rules.end(),
1271 [&]( std::unique_ptr<EDA_COMBINED_MATCHER>& rule )
1272 {
1273 return rule->GetPattern().Upper() == newGroupName.Upper();
1274 } ) == m_custom_group_rules.end() )
1275 {
1276 m_custom_group_rules.push_back( std::make_unique<EDA_COMBINED_MATCHER>( newGroupName,
1277 CTX_NET ) );
1278 SaveSettings();
1279 }
1280
1281 buildNetsList();
1282}
1283
1284
1286{
1287 m_highlighting_nets = true;
1288
1292
1293 m_highlighting_nets = false;
1294}
1295
1296
1298{
1299 if( !m_row_expanding )
1300 SaveSettings();
1301}
1302
1303
1305{
1306 wxMenu menu;
1308 menu.Bind( wxEVT_COMMAND_MENU_SELECTED, &PCB_NET_INSPECTOR_PANEL::onSettingsMenu, this );
1309 PopupMenu( &menu );
1310}
1311
1312
1313void PCB_NET_INSPECTOR_PANEL::OnConfigButton( wxCommandEvent& event )
1314{
1316 auto& cfg = localSettings.m_NetInspectorPanel;
1317
1318 const LIST_ITEM* selItem = nullptr;
1319
1320 if( m_netsList->GetSelectedItemsCount() == 1 )
1321 {
1322 selItem = static_cast<const LIST_ITEM*>( m_netsList->GetSelection().GetID() );
1323 }
1324
1325 wxMenu menu;
1326
1327 // Filtering menu items
1328 wxMenuItem* filterByNetName = new wxMenuItem( &menu, ID_FILTER_BY_NET_NAME,
1329 _( "Filter by Net Name" ),
1330 wxEmptyString, wxITEM_CHECK );
1331 filterByNetName->Check( cfg.filter_by_net_name );
1332 menu.Append( filterByNetName );
1333
1334 wxMenuItem* filterByNetclass = new wxMenuItem( &menu, ID_FILTER_BY_NETCLASS,
1335 _( "Filter by Netclass" ),
1336 wxEmptyString, wxITEM_CHECK );
1337 filterByNetclass->Check( cfg.filter_by_netclass );
1338 menu.Append( filterByNetclass );
1339
1340 menu.AppendSeparator();
1341
1342 // Grouping menu items
1343 //wxMenuItem* groupConstraint =
1344 // new wxMenuItem( &menu, ID_GROUP_BY_CONSTRAINT, _( "Group by DRC Constraint" ),
1345 // wxEmptyString, wxITEM_CHECK );
1346 //groupConstraint->Check( m_group_by_constraint );
1347 //menu.Append( groupConstraint );
1348
1349 wxMenuItem* groupNetclass = new wxMenuItem( &menu, ID_GROUP_BY_NETCLASS,
1350 _( "Group by Netclass" ),
1351 wxEmptyString, wxITEM_CHECK );
1352 groupNetclass->Check( m_group_by_netclass );
1353 menu.Append( groupNetclass );
1354
1355 menu.AppendSeparator();
1356
1357 wxMenuItem* addGroup = new wxMenuItem( &menu, ID_ADD_GROUP, _( "Add Custom Group" ),
1358 wxEmptyString, wxITEM_NORMAL );
1359 menu.Append( addGroup );
1360
1361 wxMenuItem* removeSelectedGroup = new wxMenuItem( &menu, ID_REMOVE_SELECTED_GROUP,
1362 _( "Remove Selected Custom Group" ),
1363 wxEmptyString, wxITEM_NORMAL );
1364 menu.Append( removeSelectedGroup );
1365
1366 if( !selItem || !selItem->GetIsGroup() )
1367 removeSelectedGroup->Enable( false );
1368
1369 wxMenuItem* removeCustomGroups = new wxMenuItem( &menu, ID_REMOVE_GROUPS,
1370 _( "Remove All Custom Groups" ),
1371 wxEmptyString, wxITEM_NORMAL );
1372 menu.Append( removeCustomGroups );
1373 removeCustomGroups->Enable( m_custom_group_rules.size() != 0 );
1374
1375 menu.AppendSeparator();
1376
1377 wxMenuItem* showZeroNetPads = new wxMenuItem( &menu, ID_SHOW_ZERO_NET_PADS,
1378 _( "Show Zero Pad Nets" ),
1379 wxEmptyString, wxITEM_CHECK );
1380 showZeroNetPads->Check( m_show_zero_pad_nets );
1381 menu.Append( showZeroNetPads );
1382
1383 wxMenuItem* showUnconnectedNets = new wxMenuItem( &menu, ID_SHOW_UNCONNECTED_NETS,
1384 _( "Show Unconnected Nets" ),
1385 wxEmptyString, wxITEM_CHECK );
1386 showUnconnectedNets->Check( m_show_unconnected_nets );
1387 menu.Append( showUnconnectedNets );
1388
1389 menu.AppendSeparator();
1390
1391 // Report generation
1392 wxMenuItem* generateReport = new wxMenuItem( &menu, ID_GENERATE_REPORT,
1393 _( "Save Net Inspector Report" ),
1394 wxEmptyString, wxITEM_NORMAL );
1395 menu.Append( generateReport );
1396
1397 menu.AppendSeparator();
1398
1399 // Show / hide columns menu items
1400 wxMenu* colsMenu = new wxMenu();
1401 generateShowHideColumnMenu( colsMenu );
1402 menu.AppendSubMenu( colsMenu, _( "Show / Hide Columns" ) );
1403
1404 menu.Bind( wxEVT_COMMAND_MENU_SELECTED, &PCB_NET_INSPECTOR_PANEL::onSettingsMenu, this );
1405
1406 PopupMenu( &menu );
1407}
1408
1409
1411{
1412 for( int i = 1; i <= COLUMN_LAST_STATIC_COL; ++i )
1413 {
1414 wxMenuItem* opt = new wxMenuItem( target, ID_HIDE_COLUMN + i, m_columns[i].display_name,
1415 wxEmptyString, wxITEM_CHECK );
1416 wxDataViewColumn* col = getDisplayedColumnForModelField( i );
1417 target->Append( opt );
1418 opt->Check( !col->IsHidden() );
1419 }
1420
1421 target->AppendSeparator();
1422
1423 for( std::size_t i = COLUMN_LAST_STATIC_COL + 1; i < m_columns.size(); ++i )
1424 {
1425 wxMenuItem* opt = new wxMenuItem( target, ID_HIDE_COLUMN + i, m_columns[i].display_name,
1426 wxEmptyString, wxITEM_CHECK );
1427 wxDataViewColumn* col = getDisplayedColumnForModelField( i );
1428 target->Append( opt );
1429 opt->Check( !col->IsHidden() );
1430 }
1431}
1432
1433
1434void PCB_NET_INSPECTOR_PANEL::onSettingsMenu( wxCommandEvent& event )
1435{
1436 bool saveAndRebuild = true;
1437
1438 switch( event.GetId() )
1439 {
1440 case ID_ADD_NET:
1441 onAddNet();
1442 break;
1443
1444 case ID_RENAME_NET:
1446 break;
1447
1448 case ID_DELETE_NET:
1450 break;
1451
1452 case ID_ADD_GROUP:
1453 onAddGroup();
1454 break;
1455
1458 break;
1459
1462 break;
1463
1466 break;
1467
1470 break;
1471
1474 break;
1475
1476 case ID_REMOVE_GROUPS:
1477 m_custom_group_rules.clear();
1478 break;
1479
1482 break;
1483
1486 break;
1487
1488 case ID_GENERATE_REPORT:
1490 saveAndRebuild = false;
1491 break;
1492
1495 saveAndRebuild = false;
1496 break;
1497
1500 saveAndRebuild = false;
1501 break;
1502
1503 default:
1504 if( event.GetId() >= ID_HIDE_COLUMN )
1505 {
1506 const int columnId = event.GetId() - ID_HIDE_COLUMN;
1507 wxDataViewColumn* col = getDisplayedColumnForModelField( columnId );
1508 // Make sure we end up with something non-zero so we can resize it
1509 col->SetWidth( std::max( col->GetWidth(), 10 ) );
1510 col->SetHidden( !col->IsHidden() );
1511 }
1512 break;
1513 }
1514
1515 if( saveAndRebuild )
1516 {
1517 SaveSettings();
1518 buildNetsList();
1519 }
1520}
1521
1522
1524{
1525 if( m_netsList->GetSelectedItemsCount() == 1 )
1526 {
1527 auto* selItem = static_cast<const LIST_ITEM*>( m_netsList->GetSelection().GetID() );
1528
1529 if( selItem->GetIsGroup() )
1530 {
1531 wxString groupName = selItem->GetGroupName();
1532 auto groupIter = std::find_if( m_custom_group_rules.begin(), m_custom_group_rules.end(),
1533 [&]( std::unique_ptr<EDA_COMBINED_MATCHER>& rule )
1534 {
1535 return rule->GetPattern() == groupName;
1536 } );
1537
1538 if( groupIter != m_custom_group_rules.end() )
1539 {
1540 m_custom_group_rules.erase( groupIter );
1541 SaveSettings();
1542 buildNetsList();
1543 }
1544 }
1545 }
1546}
1547
1548
1550{
1551 wxFileDialog dlg( this, _( "Save Net Inspector Report File" ), "", "",
1552 _( "Report file" ) + AddFileExtListToFilter( { "csv" } ),
1553 wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
1554
1555 if( dlg.ShowModal() == wxID_CANCEL )
1556 return;
1557
1558 wxTextFile f( dlg.GetPath() );
1559
1560 f.Create();
1561
1562 wxString txt;
1563
1564 m_in_reporting = true;
1565
1566 // Print Header:
1567 for( auto&& col : m_columns )
1568 {
1569 txt += '"';
1570
1571 if( col.has_units )
1572 {
1573 txt += wxString::Format( _( "%s (%s)" ),
1574 col.csv_name,
1576 }
1577 else
1578 {
1579 txt += col.csv_name;
1580 }
1581
1582 txt += wxT( "\";" );
1583 }
1584
1585 f.AddLine( txt );
1586
1587 // Print list of nets:
1588 const unsigned int num_rows = m_data_model->itemCount();
1589
1590 for( unsigned int row = 0; row < num_rows; row++ )
1591 {
1592 auto& i = m_data_model->itemAt( row );
1593
1594 if( i.GetIsGroup() || i.GetNetCode() == 0 )
1595 continue;
1596
1597 txt = "";
1598
1599 for( auto&& col : m_columns )
1600 {
1601 if( static_cast<int>( col.csv_flags ) & static_cast<int>( CSV_COLUMN_DESC::CSV_QUOTE ) )
1602 txt += '"' + m_data_model->valueAt( col.num, row ).GetString() + wxT( "\";" );
1603 else
1604 txt += m_data_model->valueAt( col.num, row ).GetString() + ';';
1605 }
1606
1607 f.AddLine( txt );
1608 }
1609
1610 m_in_reporting = false;
1611
1612 f.Write();
1613 f.Close();
1614}
1615
1616
1618{
1620}
1621
1622
1624{
1625 // ignore selection changes while the whole list is being rebuilt.
1627 return;
1628
1629 m_highlighting_nets = true;
1630
1631 RENDER_SETTINGS* renderSettings = m_frame->GetCanvas()->GetView()->GetPainter()->GetSettings();
1632
1633 if( m_netsList->HasSelection() )
1634 {
1635 wxDataViewItemArray sel;
1636 m_netsList->GetSelections( sel );
1637
1638 renderSettings->SetHighlight( false );
1639
1640 for( unsigned int i = 0; i < sel.GetCount(); ++i )
1641 {
1642 const LIST_ITEM* ii = static_cast<const LIST_ITEM*>( sel.Item( i ).GetID() );
1643
1644 if( ii->GetIsGroup() )
1645 {
1646 for( auto c = ii->ChildrenBegin(), end = ii->ChildrenEnd(); c != end; ++c )
1647 renderSettings->SetHighlight( true, ( *c )->GetNetCode(), true );
1648 }
1649 else
1650 {
1651 renderSettings->SetHighlight( true, ii->GetNetCode(), true );
1652 }
1653 }
1654 }
1655 else
1656 {
1657 renderSettings->SetHighlight( false );
1658 }
1659
1662
1663 m_highlighting_nets = false;
1664}
1665
1666
1667void PCB_NET_INSPECTOR_PANEL::OnColumnSorted( wxDataViewEvent& event )
1668{
1669 SaveSettings();
1670}
1671
1672
1674{
1675 // Rebuilt the nets list, and force rebuild of columns in case the stackup has chanaged
1676 buildNetsList( true );
1677 m_netsList->Refresh();
1678}
1679
1680
1682{
1683 wxString newNetName;
1684 NETNAME_VALIDATOR validator( &newNetName );
1685
1686 WX_TEXT_ENTRY_DIALOG dlg( this, _( "Net name:" ), _( "New Net" ), newNetName );
1687 dlg.SetTextValidator( validator );
1688
1689 while( true )
1690 {
1691 if( dlg.ShowModal() != wxID_OK || dlg.GetValue().IsEmpty() )
1692 return; //Aborted by user
1693
1694 newNetName = dlg.GetValue();
1695
1696 if( m_brd->FindNet( newNetName ) )
1697 {
1698 DisplayError( this,
1699 wxString::Format( _( "Net name '%s' is already in use." ), newNetName ) );
1700 newNetName = wxEmptyString;
1701 }
1702 else
1703 {
1704 break;
1705 }
1706 }
1707
1708 NETINFO_ITEM* newnet = new NETINFO_ITEM( m_brd, dlg.GetValue(), 0 );
1709
1710 m_brd->Add( newnet );
1711
1712 // We'll get an OnBoardItemAdded callback from this to update our listbox
1713 m_frame->OnModify();
1714}
1715
1716
1718{
1719 if( m_netsList->GetSelectedItemsCount() == 1 )
1720 {
1721 const LIST_ITEM* sel = static_cast<const LIST_ITEM*>( m_netsList->GetSelection().GetID() );
1722
1723 if( sel->GetIsGroup() )
1724 return;
1725
1726 NETINFO_ITEM* net = sel->GetNet();
1727 wxString fullNetName = net->GetNetname();
1728 wxString netPath;
1729 wxString shortNetName;
1730
1731 if( fullNetName.Contains( wxT( "/" ) ) )
1732 {
1733 netPath = fullNetName.BeforeLast( '/' ) + '/';
1734 shortNetName = fullNetName.AfterLast( '/' );
1735 }
1736 else
1737 {
1738 shortNetName = fullNetName;
1739 }
1740
1741 wxString unescapedShortName = UnescapeString( shortNetName );
1742
1743 WX_TEXT_ENTRY_DIALOG dlg( this, _( "Net name:" ), _( "Rename Net" ), unescapedShortName );
1744 NETNAME_VALIDATOR validator( &unescapedShortName );
1745 dlg.SetTextValidator( validator );
1746
1747 while( true )
1748 {
1749 if( dlg.ShowModal() != wxID_OK || dlg.GetValue() == unescapedShortName )
1750 return;
1751
1752 unescapedShortName = dlg.GetValue();
1753
1754 if( unescapedShortName.IsEmpty() )
1755 {
1756 DisplayError( this, wxString::Format( _( "Net name cannot be empty." ),
1757 unescapedShortName ) );
1758 continue;
1759 }
1760
1761 shortNetName = EscapeString( unescapedShortName, CTX_NETNAME );
1762 fullNetName = netPath + shortNetName;
1763
1764 if( m_brd->FindNet( shortNetName ) || m_brd->FindNet( fullNetName ) )
1765 {
1766 DisplayError( this, wxString::Format( _( "Net name '%s' is already in use." ),
1767 unescapedShortName ) );
1768 unescapedShortName = wxEmptyString;
1769 }
1770 else
1771 {
1772 break;
1773 }
1774 }
1775
1776 for( BOARD_CONNECTED_ITEM* boardItem : m_frame->GetBoard()->AllConnectedItems() )
1777 {
1778 if( boardItem->GetNet() == net )
1779 boardItem->SetFlags( CANDIDATE );
1780 else
1781 boardItem->ClearFlags( CANDIDATE );
1782 }
1783
1784 // the changed name might require re-grouping. remove/re-insert is easier.
1785 auto removed_item = m_data_model->deleteItem( m_data_model->findItem( net ) );
1786
1787 m_brd->Remove( net );
1788 net->SetNetname( fullNetName );
1789 m_brd->Add( net );
1790
1791 for( BOARD_CONNECTED_ITEM* boardItem : m_frame->GetBoard()->AllConnectedItems() )
1792 {
1793 if( boardItem->GetFlags() & CANDIDATE )
1794 boardItem->SetNet( net );
1795 }
1796
1797 buildNetsList();
1798
1799 if( std::optional<LIST_ITEM_ITER> r = m_data_model->findItem( net ) )
1800 m_netsList->Select( wxDataViewItem( r.value()->get() ) );
1801
1802 m_frame->OnModify();
1803
1804 // Currently only tracks and pads have netname annotations and need to be redrawn,
1805 // but zones are likely to follow. Since we don't have a way to ask what is current,
1806 // just refresh all items.
1809 }
1810}
1811
1812
1814{
1815 if( !m_netsList->HasSelection() )
1816 return;
1817
1818 wxDataViewItemArray sel;
1819 m_netsList->GetSelections( sel );
1820
1821 auto delete_one = [this]( const LIST_ITEM* i )
1822 {
1823 if( i->GetPadCount() == 0
1824 || IsOK( this, wxString::Format( _( "Net '%s' is in use. Delete anyway?" ),
1825 i->GetNetName() ) ) )
1826 {
1827 // This is a bit hacky, but it will do for now, since this is the only path
1828 // outside the netlist updater where you can remove a net from a BOARD.
1829 int removedCode = i->GetNetCode();
1830
1832 [removedCode]( KIGFX::VIEW_ITEM* aItem ) -> int
1833 {
1834 auto boardItem = dynamic_cast<BOARD_CONNECTED_ITEM*>( aItem );
1835
1836 if( boardItem && boardItem->GetNetCode() == removedCode )
1837 return KIGFX::REPAINT;
1838
1839 EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( aItem );
1840
1841 if( text && text->HasTextVars() )
1842 {
1843 text->ClearRenderCache();
1844 text->ClearBoundingBoxCache();
1846 }
1847
1848 return 0;
1849 } );
1850
1851 m_brd->Remove( i->GetNet() );
1852 m_frame->OnModify();
1853
1854 // We'll get an OnBoardItemRemoved callback from this to update our listbox
1855 }
1856 };
1857
1858 for( unsigned int i = 0; i < sel.GetCount(); ++i )
1859 {
1860 const LIST_ITEM* ii = static_cast<const LIST_ITEM*>( sel.Item( i ).GetID() );
1861
1862 if( ii->GetIsGroup() )
1863 {
1864 if( ii->ChildrenCount() != 0
1865 && IsOK( this, wxString::Format( _( "Delete all nets in group '%s'?" ),
1866 ii->GetGroupName() ) ) )
1867 {
1868 // we can't be iterating the children container and deleting items from
1869 // it at the same time. thus take a copy of it first.
1870 std::vector<const LIST_ITEM*> children;
1871 children.reserve( ii->ChildrenCount() );
1872 std::copy( ii->ChildrenBegin(), ii->ChildrenEnd(), std::back_inserter( children ) );
1873
1874 for( const LIST_ITEM* c : children )
1875 delete_one( c );
1876 }
1877 }
1878 else
1879 {
1880 delete_one( ii );
1881 }
1882 }
1883}
1884
1885/*****************************************************************************************
1886 *
1887 * Application-generated event handling
1888 *
1889 * ***************************************************************************************/
1890
1891
1893{
1894 SaveSettings();
1895 buildNetsList( true );
1896 m_data_model->updateAllItems();
1897}
1898
1899
1900void PCB_NET_INSPECTOR_PANEL::onUnitsChanged( wxCommandEvent& event )
1901{
1902 m_data_model->updateAllItems();
1903 event.Skip();
1904}
1905
1906
1907/*****************************************************************************************
1908 *
1909 * Settings persistence
1910 *
1911 * ***************************************************************************************/
1912
1913
1915{
1916 // Don't save settings if a board has not yet been loaded - events fire while we set up the
1917 // panel which overwrites the settings we haven't yet loaded
1919 return;
1920
1922 auto& cfg = localSettings.m_NetInspectorPanel;
1923
1924 // User-defined filters / grouping
1925 cfg.filter_text = m_searchCtrl->GetValue();
1926 cfg.filter_by_net_name = m_filter_by_net_name;
1927 cfg.filter_by_netclass = m_filter_by_netclass;
1928 cfg.group_by_netclass = m_group_by_netclass;
1929 cfg.group_by_constraint = m_group_by_constraint;
1930 cfg.show_zero_pad_nets = m_show_zero_pad_nets;
1931 cfg.show_unconnected_nets = m_show_unconnected_nets;
1932
1933 // Grid sorting
1934 wxDataViewColumn* sortingCol = m_netsList->GetSortingColumn();
1935 cfg.sorting_column = sortingCol ? static_cast<int>( sortingCol->GetModelColumn() ) : -1;
1936 cfg.sort_order_asc = sortingCol ? sortingCol->IsSortOrderAscending() : true;
1937
1938 // Column arrangement / sizes
1939 cfg.col_order.resize( m_data_model->columnCount() );
1940 cfg.col_widths.resize( m_data_model->columnCount() );
1941 cfg.col_hidden.resize( m_data_model->columnCount() );
1942
1943 for( unsigned int ii = 0; ii < m_data_model->columnCount(); ++ii )
1944 {
1945 cfg.col_order[ii] = (int) m_netsList->GetColumn( ii )->GetModelColumn();
1946 cfg.col_widths[ii] = m_netsList->GetColumn( ii )->GetWidth();
1947 cfg.col_hidden[ii] = m_netsList->GetColumn( ii )->IsHidden();
1948 }
1949
1950 // Expanded rows
1951 cfg.expanded_rows.clear();
1952 std::vector<std::pair<wxString, wxDataViewItem>> groupItems =
1953 m_data_model->getGroupDataViewItems();
1954
1955 for( std::pair<wxString, wxDataViewItem>& item : groupItems )
1956 {
1957 if( m_netsList->IsExpanded( item.second ) )
1958 cfg.expanded_rows.push_back( item.first );
1959 }
1960
1961 // Customer group rules
1962 cfg.custom_group_rules.clear();
1963
1964 for( const std::unique_ptr<EDA_COMBINED_MATCHER>& rule : m_custom_group_rules )
1965 cfg.custom_group_rules.push_back( rule->GetPattern() );
1966}
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
Container for design settings for a BOARD object.
LSET GetEnabledLayers() const
Return a bit-mask of all the layers that are enabled.
int GetBoardThickness() const
The full thickness of the board including copper and masks.
BOARD_STACKUP & GetStackupDescriptor()
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:79
Manage layers needed to make a physical board.
int GetLayerDistance(PCB_LAYER_ID aFirstLayer, PCB_LAYER_ID aSecondLayer) const
Calculate the distance (height) between the two given copper layers.
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:290
const NETINFO_LIST & GetNetInfo() const
Definition: board.h:871
LSET GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition: board.cpp:775
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
Definition: board.cpp:1000
const std::set< int > & GetHighLightNetCodes() const
Definition: board.h:532
const std::vector< BOARD_CONNECTED_ITEM * > AllConnectedItems()
Definition: board.cpp:2610
void AddListener(BOARD_LISTENER *aListener)
Add a listener to the board to receive calls whenever something on the board has been modified.
Definition: board.cpp:2665
NETINFO_ITEM * FindNet(int aNetcode) const
Search for a net with the given netcode.
Definition: board.cpp:1918
int GetCopperLayerCount() const
Definition: board.cpp:738
const FOOTPRINTS & Footprints() const
Definition: board.h:331
unsigned GetNodesCount(int aNet=-1) const
Definition: board.cpp:1653
bool IsHighLightNetON() const
Definition: board.h:548
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition: board.cpp:579
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:892
void RemoveListener(BOARD_LISTENER *aListener)
Remove the specified listener.
Definition: board.cpp:2672
void Remove(BOARD_ITEM *aBoardItem, REMOVE_MODE aMode=REMOVE_MODE::NORMAL) override
Removes an item from the container.
Definition: board.cpp:1138
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Return a list of missing connections between components/tracks.
Definition: board.h:475
CN_ITEM represents a BOARD_CONNETED_ITEM in the connectivity system (ie: a pad, track/arc/via,...
int Net() const
int ShowModal() override
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:101
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition: eda_text.h:79
virtual RENDER_SETTINGS * GetSettings()=0
Return a pointer to current settings that are going to be used when drawing items.
Container for all the knowledge about how graphical objects are drawn on any output surface/device.
const std::set< int > & GetHighlightNetCodes() const
Return the netcode of currently highlighted net.
void SetHighlight(bool aEnabled, int aNetcode=-1, bool aMulti=false)
Turns on/off highlighting.
An abstract base class for deriving all objects that can be added to a VIEW.
Definition: view_item.h:84
void UpdateAllLayersColor()
Apply the new coloring scheme to all layers.
Definition: view.cpp:804
void UpdateAllItems(int aUpdateFlags)
Update all items in the view according to the given flags.
Definition: view.cpp:1563
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition: view.h:221
void UpdateAllItemsConditionally(int aUpdateFlags, std::function< bool(VIEW_ITEM *)> aCondition)
Update items in the view according to the given flags and condition.
Definition: view.cpp:1573
LSET is a set of PCB_LAYER_IDs.
Definition: lset.h:36
copper_layers_iterator copper_layers_end() const
Definition: lset.cpp:967
copper_layers_iterator copper_layers_begin() const
Definition: lset.cpp:962
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:410
A collection of nets and the parameters used to route or test these nets.
Definition: netclass.h:44
const wxString GetName() const
Gets the consolidated name of this netclass (which may be an aggregate)
Definition: netclass.cpp:151
Handle the data for a net.
Definition: netinfo.h:56
void SetNetname(const wxString &aNewName)
Set the long netname to aNetName, the short netname to the last token in the long netname's path,...
Definition: netinfo.h:139
const wxString & GetNetname() const
Definition: netinfo.h:114
NETCLASS * GetNetClass()
Definition: netinfo.h:101
int GetNetCode() const
Definition: netinfo.h:108
const NETCODES_MAP & NetsByNetcode() const
Return the netcode map, at least for python.
Definition: netinfo.h:375
A base class used to implement docking net inspector panels.
wxDataViewCtrl * m_netsList
wxSearchCtrl * m_searchCtrl
Definition: pad.h:54
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
BOARD * GetBoard() const
virtual KIGFX::PCB_VIEW * GetView() const override
Return a pointer to the #VIEW instance used in the panel.
The main frame for Pcbnew.
void OnModify() override
Must be called after a board change to set the modified flag.
Data model for display in the Net Inspector panel.
Primary data item for entries in the Net Inspector list.
virtual void OnBoardItemRemoved(BOARD &aBoard, BOARD_ITEM *aBoardItem) override
virtual void OnBoardHighlightNetChanged(BOARD &aBoard) override
void generateReport()
Generates a CSV report from currently disaplyed data.
wxString formatCount(unsigned int aValue) const
PCB_NET_INSPECTOR_PANEL(wxWindow *parent, PCB_EDIT_FRAME *aFrame)
virtual void OnBoardItemsChanged(BOARD &aBoard, std::vector< BOARD_ITEM * > &aBoardItems) override
virtual void OnSearchTextChanged(wxCommandEvent &event) override
virtual void OnBoardItemsRemoved(BOARD &aBoard, std::vector< BOARD_ITEM * > &aBoardItems) override
virtual void OnBoardChanged() override
Update panel when board is changed.
void generateShowHideColumnMenu(wxMenu *target)
Generates a sub-menu for the show / hide columns submenu.
wxString formatNetCode(const NETINFO_ITEM *aNet) const
std::unique_ptr< LIST_ITEM > buildNewItem(NETINFO_ITEM *aNet, unsigned int aPadCount, const std::vector< CN_ITEM * > &aCNItems)
Constructs a LIST_ITEM for storage in the data model from a board net item.
std::vector< std::unique_ptr< EDA_COMBINED_MATCHER > > m_custom_group_rules
wxString formatNetName(const NETINFO_ITEM *aNet) const
void onSettingsMenu(wxCommandEvent &event)
std::vector< CN_ITEM * > relevantConnectivityItems() const
Filters connectivity items from a board update to remove those not related to net / track metrics.
unsigned int calculateViaLength(const PCB_TRACK *) const
Calculates the length of a via from the board stackup.
void highlightSelectedNets()
Highlight the currently selected net.
virtual void OnBoardCompositeUpdate(BOARD &aBoard, std::vector< BOARD_ITEM * > &aAddedItems, std::vector< BOARD_ITEM * > &aRemovedItems, std::vector< BOARD_ITEM * > &aDeletedItems) override
virtual void OnBoardItemsAdded(BOARD &aBoard, std::vector< BOARD_ITEM * > &aBoardItems) override
wxObjectDataPtr< DATA_MODEL > m_data_model
void updateNet(NETINFO_ITEM *aNet)
Updates the stored LIST_ITEMs for a given updated board net item.
virtual void OnLanguageChangedImpl() override
Reloads strings on an application language change.
void OnNetsListContextMenu(wxDataViewEvent &event)
virtual void OnBoardNetSettingsChanged(BOARD &aBoard) override
void OnNetsListItemActivated(wxDataViewEvent &event)
void OnColumnSorted(wxDataViewEvent &event)
void updateDisplayedRowValues(const std::optional< LIST_ITEM_ITER > &aRow)
virtual void OnBoardItemAdded(BOARD &aBoard, BOARD_ITEM *aBoardItem) override
virtual 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.
virtual void OnConfigButton(wxCommandEvent &event) override
void buildNetsList(bool rebuildColumns=false)
bool restoreSortColumn(int sortingColumnId, bool sortOrderAsc)
Sets the sort column in the grid to that showing the given model ID column.
wxString formatLength(int64_t aValue) const
virtual void SaveSettings() override
Persist the net inspector configuration to project / global settings.
void onUnitsChanged(wxCommandEvent &event)
void OnExpandCollapseRow(wxCommandEvent &event)
wxDataViewColumn * getDisplayedColumnForModelField(int columnId)
Fetches the displayed grid view column for the given model column ID.
void adjustListColumnSizes(PANEL_NET_INSPECTOR_SETTINGS *cfg)
Adjust the sizing of list columns.
virtual void OnBoardItemChanged(BOARD &aBoard, BOARD_ITEM *aBoardItem) override
std::vector< COLUMN_DESC > m_columns
All displayed (or hidden) columns.
virtual void OnShowPanel() override
Prepare the panel when shown in the editor.
virtual SETTINGS_MANAGER & GetSettingsManager() const
Definition: pgm_base.h:142
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:206
PROJECT & Prj() const
A helper while we are not MDI-capable – return the one and only project.
wxString MessageTextFromValue(double aValue, bool aAddUnitLabel=true, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
A lower-precision version of StringFromValue().
EDA_UNITS GetUserUnits() const
wxBoxSizer * m_ContentSizer
A KICAD version of wxTextEntryDialog which supports the various improvements/work-arounds from DIALOG...
wxString GetValue() const
void SetTextValidator(wxTextValidatorStyle style)
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition: confirm.cpp:250
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:170
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)
Tests whether a layer is a copper layer.
Definition: layer_ids.h:531
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
@ B_Cu
Definition: layer_ids.h:65
@ UNDEFINED_LAYER
Definition: layer_ids.h:61
@ F_Cu
Definition: layer_ids.h:64
KICOMMON_API wxString GetLabel(EDA_UNITS aUnits, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
Get the units string for a given units type.
Definition: eda_units.cpp:155
@ REPAINT
Item needs to be redrawn.
Definition: view_item.h:57
@ GEOMETRY
Position or shape has changed.
Definition: view_item.h:54
KICOMMON_API wxFont GetInfoFont(wxWindow *aWindow)
Definition: ui_common.cpp:154
void delete_matching(_Container &__c, _Value __value)
Covers for the horrifically named std::remove and std::remove_if (neither of which remove anything).
Definition: kicad_algo.h:165
PGM_BASE & Pgm()
The global Program "get" accessor.
Definition: pgm_base.cpp:1060
see class PGM_BASE
static bool highlightNet(TOOL_MANAGER *aToolMgr, const VECTOR2D &aPosition)
wxString UnescapeString(const wxString &aSource)
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
@ CTX_NETNAME
Definition: string_utils.h:53
bool operator()(const CN_ITEM *a, const CN_ITEM *b) const
bool operator()(int a, const CN_ITEM *b) const
bool operator()(const CN_ITEM *a, int b) const
Persisted state for the net inspector panel.
std::vector< wxString > expanded_rows
std::vector< wxString > custom_group_rules
@ 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.