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
709 for( int layer = via->TopLayer(); layer <= via->BottomLayer(); ++layer )
710 {
711 if( m_brd->GetConnectivity()->IsConnectedOnLayer( via, layer, traceAndPadTypes ) )
712 {
713 if( top_layer == UNDEFINED_LAYER )
714 top_layer = PCB_LAYER_ID( layer );
715 else
716 bottom_layer = PCB_LAYER_ID( layer );
717 }
718 }
719
720 if( top_layer == UNDEFINED_LAYER )
721 top_layer = via->TopLayer();
722 if( bottom_layer == UNDEFINED_LAYER )
723 bottom_layer = via->BottomLayer();
724
725 const BOARD_STACKUP& stackup = bds.GetStackupDescriptor();
726 return stackup.GetLayerDistance( top_layer, bottom_layer );
727 }
728 else
729 {
730 int dielectricLayers = bds.GetCopperLayerCount() - 1;
731 // TODO: not all dielectric layers are the same thickness!
732 int layerThickness = bds.GetBoardThickness() / dielectricLayers;
733 int effectiveBottomLayer;
734
735 if( via->BottomLayer() == B_Cu )
736 effectiveBottomLayer = F_Cu + dielectricLayers;
737 else
738 effectiveBottomLayer = via->BottomLayer();
739
740 int layerCount = effectiveBottomLayer - via->TopLayer();
741
742 return layerCount * layerThickness;
743 }
744}
745
746
748{
749 // something for the specified net has changed, update that row.
750 // ignore nets that are not in our list because the filter doesn't match.
751 if( !netFilterMatches( aNet ) )
752 {
753 m_data_model->deleteItem( m_data_model->findItem( aNet ) );
754 return;
755 }
756
757 // if the net had no pads before, it might not be in the displayed list yet.
758 // if it had pads and now doesn't anymore, we might need to remove it from the list.
759 std::optional<LIST_ITEM_ITER> cur_net_row = m_data_model->findItem( aNet );
760
761 const unsigned int node_count = m_brd->GetNodesCount( aNet->GetNetCode() );
762
763 if( node_count == 0 && !m_show_zero_pad_nets )
764 {
765 m_data_model->deleteItem( cur_net_row );
766 return;
767 }
768
769 std::unique_ptr<LIST_ITEM> new_list_item = buildNewItem( aNet, node_count,
771
772 if( !cur_net_row )
773 {
774 m_data_model->addItem( std::move( new_list_item ) );
775 return;
776 }
777
778 const std::unique_ptr<LIST_ITEM>& cur_list_item = *cur_net_row.value();
779
780 if( cur_list_item->GetNetName() != new_list_item->GetNetName() )
781 {
782 // if the name has changed, it might require re-grouping.
783 // it's easier to remove and re-insert it
784 m_data_model->deleteItem( cur_net_row );
785 m_data_model->addItem( std::move( new_list_item ) );
786 }
787 else
788 {
789 // update fields only
790 cur_list_item->SetPadCount( new_list_item->GetPadCount() );
791 cur_list_item->SetViaCount( new_list_item->GetViaCount() );
792 cur_list_item->SetLayerWireLength( new_list_item->GetLayerWireLength() );
793 cur_list_item->SetPadDieLength( new_list_item->GetPadDieLength() );
794
795 updateDisplayedRowValues( cur_net_row );
796 }
797}
798
799
800/*****************************************************************************************
801 *
802 * Formatting helpers
803 *
804 * ***************************************************************************************/
805
806
808{
809 return wxString::Format( wxT( "%.3d" ), aNet->GetNetCode() );
810}
811
812
814{
815 return UnescapeString( aNet->GetNetname() );
816}
817
818
819wxString PCB_NET_INSPECTOR_PANEL::formatCount( unsigned int aValue ) const
820{
821 return wxString::Format( wxT( "%u" ), aValue );
822}
823
824
825wxString PCB_NET_INSPECTOR_PANEL::formatLength( int64_t aValue ) const
826{
827 return m_frame->MessageTextFromValue( static_cast<long long int>( aValue ),
828 // don't include unit label in the string when reporting
830}
831
832
833void PCB_NET_INSPECTOR_PANEL::updateDisplayedRowValues( const std::optional<LIST_ITEM_ITER>& aRow )
834{
835 if( !aRow )
836 return;
837
838 wxDataViewItemArray sel;
839 m_netsList->GetSelections( sel );
840
841 m_data_model->updateItem( aRow );
842
843 if( !sel.IsEmpty() )
844 {
845 m_netsList->SetSelections( sel );
846 m_netsList->EnsureVisible( sel.Item( 0 ) );
847 }
848}
849
850
851/*****************************************************************************************
852 *
853 * BOARD_LISTENER event handling
854 *
855 * ***************************************************************************************/
856
857
859{
861
862 if( m_brd != nullptr )
863 m_brd->AddListener( this );
864
865 m_board_loaded = true;
866 m_board_loading = true;
867
869 auto& cfg = localSettings.m_NetInspectorPanel;
870 m_searchCtrl->SetValue( cfg.filter_text );
871
872 buildNetsList( true );
873
874 m_board_loading = false;
875}
876
878{
879 if( !IsShownOnScreen() )
880 return;
881
882 if( NETINFO_ITEM* net = dynamic_cast<NETINFO_ITEM*>( aBoardItem ) )
883 {
884 // a new net has been added to the board. add it to our list if it
885 // passes the netname filter test.
886
887 if( netFilterMatches( net ) )
888 {
889 std::unique_ptr<LIST_ITEM> new_item = std::make_unique<LIST_ITEM>( net );
890
891 // the new net could have some pads already assigned, count them.
892 new_item->SetPadCount( m_brd->GetNodesCount( net->GetNetCode() ) );
893 new_item->SetLayerCount( m_brd->GetCopperLayerCount() );
894
895 m_data_model->addItem( std::move( new_item ) );
896 }
897 }
898 else if( BOARD_CONNECTED_ITEM* i = dynamic_cast<BOARD_CONNECTED_ITEM*>( aBoardItem ) )
899 {
900 std::optional<LIST_ITEM_ITER> r = m_data_model->findItem( i->GetNet() );
901
902 if( r )
903 {
904 // try to handle frequent operations quickly.
905 if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( i ) )
906 {
907 const std::unique_ptr<LIST_ITEM>& list_item = *r.value();
908 int len = track->GetLength();
909
910 list_item->AddLayerWireLength( len, track->GetLayer() );
911
912 if( track->Type() == PCB_VIA_T )
913 {
914 list_item->AddViaCount( 1 );
915 list_item->AddViaLength( calculateViaLength( track ) );
916 }
917
919 return;
920 }
921 }
922
923 // resort to generic slower net update otherwise.
924 updateNet( i->GetNet() );
925 }
926 else if( FOOTPRINT* footprint = dynamic_cast<FOOTPRINT*>( aBoardItem ) )
927 {
928 for( const PAD* pad : footprint->Pads() )
929 {
930 std::optional<LIST_ITEM_ITER> r = m_data_model->findItem( pad->GetNet() );
931
932 if( !r )
933 {
934 // if show-zero-pads is off, we might not have this net
935 // in our list yet, so add it first.
936 // notice that at this point we are very certain that this net
937 // will have at least one pad.
938
939 if( netFilterMatches( pad->GetNet() ) )
940 r = m_data_model->addItem( std::make_unique<LIST_ITEM>( pad->GetNet() ) );
941 }
942
943 if( r )
944 {
945 const std::unique_ptr<LIST_ITEM>& list_item = *r.value();
946 int len = pad->GetPadToDieLength();
947
948 list_item->AddPadCount( 1 );
949 list_item->AddPadDieLength( len );
950 list_item->SetLayerCount( m_brd->GetCopperLayerCount() );
951
952 if( list_item->GetPadCount() == 0 && !m_show_zero_pad_nets )
953 m_data_model->deleteItem( r );
954 else
956 }
957 }
958 }
959}
960
961
963 std::vector<BOARD_ITEM*>& aBoardItems )
964{
965 if( !IsShownOnScreen() )
966 return;
967
968 // Rebuild full netlist for large changes
969 if( aBoardItems.size() > 25 )
970 {
972 m_netsList->Refresh();
973 }
974 else
975 {
976 for( BOARD_ITEM* item : aBoardItems )
977 {
978 OnBoardItemAdded( aBoard, item );
979 }
980 }
981}
982
983
985{
986 if( !IsShownOnScreen() )
987 return;
988
989 if( NETINFO_ITEM* net = dynamic_cast<NETINFO_ITEM*>( aBoardItem ) )
990 {
991 m_data_model->deleteItem( m_data_model->findItem( net ) );
992 }
993 else if( FOOTPRINT* footprint = dynamic_cast<FOOTPRINT*>( aBoardItem ) )
994 {
995 for( const PAD* pad : footprint->Pads() )
996 {
997 std::optional<LIST_ITEM_ITER> r = m_data_model->findItem( pad->GetNet() );
998
999 if( r )
1000 {
1001 const std::unique_ptr<LIST_ITEM>& list_item = *r.value();
1002 int len = pad->GetPadToDieLength();
1003
1004 list_item->SubPadCount( 1 );
1005 list_item->SubPadDieLength( len );
1006
1007 if( list_item->GetPadCount() == 0 && !m_show_zero_pad_nets )
1008 m_data_model->deleteItem( r );
1009 else
1011 }
1012 }
1013 }
1014 else if( BOARD_CONNECTED_ITEM* i = dynamic_cast<BOARD_CONNECTED_ITEM*>( aBoardItem ) )
1015 {
1016 std::optional<LIST_ITEM_ITER> r = m_data_model->findItem( i->GetNet() );
1017
1018 if( r )
1019 {
1020 // try to handle frequent operations quickly.
1021 if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( i ) )
1022 {
1023 const std::unique_ptr<LIST_ITEM>& list_item = *r.value();
1024 int len = track->GetLength();
1025
1026 list_item->SubLayerWireLength( len, track->GetLayer() );
1027
1028 if( track->Type() == PCB_VIA_T )
1029 {
1030 list_item->SubViaCount( 1 );
1031 list_item->SubViaLength( calculateViaLength( track ) );
1032 }
1033
1035 return;
1036 }
1037
1038 // resort to generic slower net update otherwise.
1039 updateNet( i->GetNet() );
1040 }
1041 }
1042}
1043
1044
1046 std::vector<BOARD_ITEM*>& aBoardItems )
1047{
1048 if( !IsShownOnScreen() )
1049 return;
1050
1051 if( aBoardItems.size() > 25 )
1052 {
1053 buildNetsList();
1054 m_netsList->Refresh();
1055 }
1056 else
1057 {
1058 for( BOARD_ITEM* item : aBoardItems )
1059 {
1060 OnBoardItemRemoved( aBoard, item );
1061 }
1062 }
1063}
1064
1065
1067{
1068 if( !IsShownOnScreen() )
1069 return;
1070
1071 buildNetsList();
1072 m_netsList->Refresh();
1073}
1074
1075
1077{
1078 if( !IsShownOnScreen() )
1079 return;
1080
1081 if( dynamic_cast<BOARD_CONNECTED_ITEM*>( aBoardItem ) != nullptr
1082 || dynamic_cast<FOOTPRINT*>( aBoardItem ) != nullptr )
1083 {
1084 buildNetsList();
1085 m_netsList->Refresh();
1086 }
1087}
1088
1089
1091 std::vector<BOARD_ITEM*>& aBoardItems )
1092{
1093 if( !IsShownOnScreen() )
1094 return;
1095
1096 buildNetsList();
1097 m_netsList->Refresh();
1098}
1099
1100
1102 std::vector<BOARD_ITEM*>& aAddedItems,
1103 std::vector<BOARD_ITEM*>& aRemovedItems,
1104 std::vector<BOARD_ITEM*>& aDeletedItems )
1105{
1106 if( !IsShownOnScreen() )
1107 return;
1108
1109 buildNetsList();
1110 m_netsList->Refresh();
1111}
1112
1113
1115{
1116 if( m_highlighting_nets || !IsShownOnScreen() )
1117 return;
1118
1119 if( !m_brd->IsHighLightNetON() )
1120 {
1121 m_netsList->UnselectAll();
1122 }
1123 else
1124 {
1125 const std::set<int>& selected_codes = m_brd->GetHighLightNetCodes();
1126
1127 wxDataViewItemArray new_selection;
1128 new_selection.Alloc( selected_codes.size() );
1129
1130 for( int code : selected_codes )
1131 {
1132 if( std::optional<LIST_ITEM_ITER> r = m_data_model->findItem( code ) )
1133 new_selection.Add( wxDataViewItem( &***r ) );
1134 }
1135
1136 m_netsList->SetSelections( new_selection );
1137
1138 if( !new_selection.IsEmpty() )
1139 m_netsList->EnsureVisible( new_selection.Item( 0 ) );
1140 }
1141}
1142
1143
1144/*****************************************************************************************
1145 *
1146 * UI-generated event handling
1147 *
1148 * ***************************************************************************************/
1149
1151{
1152 buildNetsList();
1154}
1155
1156
1158{
1159 bool multipleSelections = false;
1160 const LIST_ITEM* selItem = nullptr;
1161
1162 if( m_netsList->GetSelectedItemsCount() == 1 )
1163 {
1164 selItem = static_cast<const LIST_ITEM*>( m_netsList->GetSelection().GetID() );
1165 }
1166 else
1167 {
1168 if( m_netsList->GetSelectedItemsCount() > 1 )
1169 multipleSelections = true;
1170 }
1171
1172 wxMenu menu;
1173
1174 // Net edit menu items
1175 wxMenuItem* highlightNet = new wxMenuItem( &menu, ID_HIGHLIGHT_SELECTED_NETS,
1176 _( "Highlight Selected Net" ),
1177 wxEmptyString, wxITEM_NORMAL );
1178 menu.Append( highlightNet );
1179
1180 wxMenuItem* clearHighlighting = new wxMenuItem( &menu, ID_CLEAR_HIGHLIGHTING,
1181 _( "Clear Net Highlighting" ),
1182 wxEmptyString, wxITEM_NORMAL );
1183 menu.Append( clearHighlighting );
1184
1185 RENDER_SETTINGS* renderSettings = m_frame->GetCanvas()->GetView()->GetPainter()->GetSettings();
1186 const std::set<int>& selected_codes = renderSettings->GetHighlightNetCodes();
1187
1188 if( selected_codes.size() == 0 )
1189 clearHighlighting->Enable( false );
1190
1191 menu.AppendSeparator();
1192
1193 wxMenuItem* renameNet = new wxMenuItem( &menu, ID_RENAME_NET, _( "Rename Selected Net" ),
1194 wxEmptyString, wxITEM_NORMAL );
1195 menu.Append( renameNet );
1196
1197 wxMenuItem* deleteNet = new wxMenuItem( &menu, ID_DELETE_NET, _( "Delete Selected Net" ),
1198 wxEmptyString, wxITEM_NORMAL );
1199 menu.Append( deleteNet );
1200
1201 menu.AppendSeparator();
1202
1203 wxMenuItem* addNet = new wxMenuItem( &menu, ID_ADD_NET, _( "Add Net" ),
1204 wxEmptyString, wxITEM_NORMAL );
1205 menu.Append( addNet );
1206
1207 if( !selItem && !multipleSelections )
1208 {
1209 highlightNet->Enable( false );
1210 deleteNet->Enable( false );
1211 renameNet->Enable( false );
1212 }
1213 else
1214 {
1215 if( multipleSelections || selItem->GetIsGroup() )
1216 {
1217 highlightNet->SetItemLabel( _( "Highlight Selected Nets" ) );
1218 renameNet->Enable( false );
1219 deleteNet->SetItemLabel( _( "Delete Selected Nets" ) );
1220 }
1221 }
1222
1223 menu.AppendSeparator();
1224
1225 wxMenuItem* removeSelectedGroup = new wxMenuItem( &menu, ID_REMOVE_SELECTED_GROUP,
1226 _( "Remove Selected Custom Group" ),
1227 wxEmptyString, wxITEM_NORMAL );
1228 menu.Append( removeSelectedGroup );
1229
1230 if( !selItem || !selItem->GetIsGroup() )
1231 removeSelectedGroup->Enable( false );
1232
1233 menu.Bind( wxEVT_COMMAND_MENU_SELECTED, &PCB_NET_INSPECTOR_PANEL::onSettingsMenu, this );
1234
1235 PopupMenu( &menu );
1236}
1237
1238
1240{
1241 SaveSettings();
1242 buildNetsList();
1243}
1244
1245
1247{
1248 wxString newGroupName;
1249 NETNAME_VALIDATOR validator( &newGroupName );
1250
1251 WX_TEXT_ENTRY_DIALOG dlg( this, _( "Group name / pattern:" ), _( "New Group" ), newGroupName );
1252 wxStaticText* help = new wxStaticText( &dlg, wxID_ANY,
1253 _( "(Use /.../ to indicate a regular expression.)" ) );
1254 help->SetFont( KIUI::GetInfoFont( this ).Italic() );
1255 dlg.m_ContentSizer->Add( help, 0, wxALL|wxEXPAND, 5 );
1256 dlg.SetTextValidator( validator );
1257 dlg.GetSizer()->SetSizeHints( &dlg );
1258
1259 if( dlg.ShowModal() != wxID_OK || dlg.GetValue().IsEmpty() )
1260 return; //Aborted by user
1261
1262 newGroupName = UnescapeString( dlg.GetValue() );
1263
1264 if( newGroupName == "" )
1265 return;
1266
1267 if( std::find_if( m_custom_group_rules.begin(), m_custom_group_rules.end(),
1268 [&]( std::unique_ptr<EDA_COMBINED_MATCHER>& rule )
1269 {
1270 return rule->GetPattern().Upper() == newGroupName.Upper();
1271 } ) == m_custom_group_rules.end() )
1272 {
1273 m_custom_group_rules.push_back( std::make_unique<EDA_COMBINED_MATCHER>( newGroupName,
1274 CTX_NET ) );
1275 SaveSettings();
1276 }
1277
1278 buildNetsList();
1279}
1280
1281
1283{
1284 m_highlighting_nets = true;
1285
1289
1290 m_highlighting_nets = false;
1291}
1292
1293
1295{
1296 if( !m_row_expanding )
1297 SaveSettings();
1298}
1299
1300
1302{
1303 wxMenu menu;
1305 menu.Bind( wxEVT_COMMAND_MENU_SELECTED, &PCB_NET_INSPECTOR_PANEL::onSettingsMenu, this );
1306 PopupMenu( &menu );
1307}
1308
1309
1310void PCB_NET_INSPECTOR_PANEL::OnConfigButton( wxCommandEvent& event )
1311{
1313 auto& cfg = localSettings.m_NetInspectorPanel;
1314
1315 const LIST_ITEM* selItem = nullptr;
1316
1317 if( m_netsList->GetSelectedItemsCount() == 1 )
1318 {
1319 selItem = static_cast<const LIST_ITEM*>( m_netsList->GetSelection().GetID() );
1320 }
1321
1322 wxMenu menu;
1323
1324 // Filtering menu items
1325 wxMenuItem* filterByNetName = new wxMenuItem( &menu, ID_FILTER_BY_NET_NAME,
1326 _( "Filter by Net Name" ),
1327 wxEmptyString, wxITEM_CHECK );
1328 filterByNetName->Check( cfg.filter_by_net_name );
1329 menu.Append( filterByNetName );
1330
1331 wxMenuItem* filterByNetclass = new wxMenuItem( &menu, ID_FILTER_BY_NETCLASS,
1332 _( "Filter by Netclass" ),
1333 wxEmptyString, wxITEM_CHECK );
1334 filterByNetclass->Check( cfg.filter_by_netclass );
1335 menu.Append( filterByNetclass );
1336
1337 menu.AppendSeparator();
1338
1339 // Grouping menu items
1340 //wxMenuItem* groupConstraint =
1341 // new wxMenuItem( &menu, ID_GROUP_BY_CONSTRAINT, _( "Group by DRC Constraint" ),
1342 // wxEmptyString, wxITEM_CHECK );
1343 //groupConstraint->Check( m_group_by_constraint );
1344 //menu.Append( groupConstraint );
1345
1346 wxMenuItem* groupNetclass = new wxMenuItem( &menu, ID_GROUP_BY_NETCLASS,
1347 _( "Group by Netclass" ),
1348 wxEmptyString, wxITEM_CHECK );
1349 groupNetclass->Check( m_group_by_netclass );
1350 menu.Append( groupNetclass );
1351
1352 menu.AppendSeparator();
1353
1354 wxMenuItem* addGroup = new wxMenuItem( &menu, ID_ADD_GROUP, _( "Add Custom Group" ),
1355 wxEmptyString, wxITEM_NORMAL );
1356 menu.Append( addGroup );
1357
1358 wxMenuItem* removeSelectedGroup = new wxMenuItem( &menu, ID_REMOVE_SELECTED_GROUP,
1359 _( "Remove Selected Custom Group" ),
1360 wxEmptyString, wxITEM_NORMAL );
1361 menu.Append( removeSelectedGroup );
1362
1363 if( !selItem || !selItem->GetIsGroup() )
1364 removeSelectedGroup->Enable( false );
1365
1366 wxMenuItem* removeCustomGroups = new wxMenuItem( &menu, ID_REMOVE_GROUPS,
1367 _( "Remove All Custom Groups" ),
1368 wxEmptyString, wxITEM_NORMAL );
1369 menu.Append( removeCustomGroups );
1370 removeCustomGroups->Enable( m_custom_group_rules.size() != 0 );
1371
1372 menu.AppendSeparator();
1373
1374 wxMenuItem* showZeroNetPads = new wxMenuItem( &menu, ID_SHOW_ZERO_NET_PADS,
1375 _( "Show Zero Pad Nets" ),
1376 wxEmptyString, wxITEM_CHECK );
1377 showZeroNetPads->Check( m_show_zero_pad_nets );
1378 menu.Append( showZeroNetPads );
1379
1380 wxMenuItem* showUnconnectedNets = new wxMenuItem( &menu, ID_SHOW_UNCONNECTED_NETS,
1381 _( "Show Unconnected Nets" ),
1382 wxEmptyString, wxITEM_CHECK );
1383 showUnconnectedNets->Check( m_show_unconnected_nets );
1384 menu.Append( showUnconnectedNets );
1385
1386 menu.AppendSeparator();
1387
1388 // Report generation
1389 wxMenuItem* generateReport = new wxMenuItem( &menu, ID_GENERATE_REPORT,
1390 _( "Save Net Inspector Report" ),
1391 wxEmptyString, wxITEM_NORMAL );
1392 menu.Append( generateReport );
1393
1394 menu.AppendSeparator();
1395
1396 // Show / hide columns menu items
1397 wxMenu* colsMenu = new wxMenu();
1398 generateShowHideColumnMenu( colsMenu );
1399 menu.AppendSubMenu( colsMenu, _( "Show / Hide Columns" ) );
1400
1401 menu.Bind( wxEVT_COMMAND_MENU_SELECTED, &PCB_NET_INSPECTOR_PANEL::onSettingsMenu, this );
1402
1403 PopupMenu( &menu );
1404}
1405
1406
1408{
1409 for( int i = 1; i <= COLUMN_LAST_STATIC_COL; ++i )
1410 {
1411 wxMenuItem* opt = new wxMenuItem( target, ID_HIDE_COLUMN + i, m_columns[i].display_name,
1412 wxEmptyString, wxITEM_CHECK );
1413 wxDataViewColumn* col = getDisplayedColumnForModelField( i );
1414 target->Append( opt );
1415 opt->Check( !col->IsHidden() );
1416 }
1417
1418 target->AppendSeparator();
1419
1420 for( std::size_t i = COLUMN_LAST_STATIC_COL + 1; i < m_columns.size(); ++i )
1421 {
1422 wxMenuItem* opt = new wxMenuItem( target, ID_HIDE_COLUMN + i, m_columns[i].display_name,
1423 wxEmptyString, wxITEM_CHECK );
1424 wxDataViewColumn* col = getDisplayedColumnForModelField( i );
1425 target->Append( opt );
1426 opt->Check( !col->IsHidden() );
1427 }
1428}
1429
1430
1431void PCB_NET_INSPECTOR_PANEL::onSettingsMenu( wxCommandEvent& event )
1432{
1433 bool saveAndRebuild = true;
1434
1435 switch( event.GetId() )
1436 {
1437 case ID_ADD_NET:
1438 onAddNet();
1439 break;
1440
1441 case ID_RENAME_NET:
1443 break;
1444
1445 case ID_DELETE_NET:
1447 break;
1448
1449 case ID_ADD_GROUP:
1450 onAddGroup();
1451 break;
1452
1455 break;
1456
1459 break;
1460
1463 break;
1464
1467 break;
1468
1471 break;
1472
1473 case ID_REMOVE_GROUPS:
1474 m_custom_group_rules.clear();
1475 break;
1476
1479 break;
1480
1483 break;
1484
1485 case ID_GENERATE_REPORT:
1487 saveAndRebuild = false;
1488 break;
1489
1492 saveAndRebuild = false;
1493 break;
1494
1497 saveAndRebuild = false;
1498 break;
1499
1500 default:
1501 if( event.GetId() >= ID_HIDE_COLUMN )
1502 {
1503 const int columnId = event.GetId() - ID_HIDE_COLUMN;
1504 wxDataViewColumn* col = getDisplayedColumnForModelField( columnId );
1505 // Make sure we end up with something non-zero so we can resize it
1506 col->SetWidth( std::max( col->GetWidth(), 10 ) );
1507 col->SetHidden( !col->IsHidden() );
1508 }
1509 break;
1510 }
1511
1512 if( saveAndRebuild )
1513 {
1514 SaveSettings();
1515 buildNetsList();
1516 }
1517}
1518
1519
1521{
1522 if( m_netsList->GetSelectedItemsCount() == 1 )
1523 {
1524 auto* selItem = static_cast<const LIST_ITEM*>( m_netsList->GetSelection().GetID() );
1525
1526 if( selItem->GetIsGroup() )
1527 {
1528 wxString groupName = selItem->GetGroupName();
1529 auto groupIter = std::find_if( m_custom_group_rules.begin(), m_custom_group_rules.end(),
1530 [&]( std::unique_ptr<EDA_COMBINED_MATCHER>& rule )
1531 {
1532 return rule->GetPattern() == groupName;
1533 } );
1534
1535 if( groupIter != m_custom_group_rules.end() )
1536 {
1537 m_custom_group_rules.erase( groupIter );
1538 SaveSettings();
1539 buildNetsList();
1540 }
1541 }
1542 }
1543}
1544
1545
1547{
1548 wxFileDialog dlg( this, _( "Save Net Inspector Report File" ), "", "",
1549 _( "Report file" ) + AddFileExtListToFilter( { "csv" } ),
1550 wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
1551
1552 if( dlg.ShowModal() == wxID_CANCEL )
1553 return;
1554
1555 wxTextFile f( dlg.GetPath() );
1556
1557 f.Create();
1558
1559 wxString txt;
1560
1561 m_in_reporting = true;
1562
1563 // Print Header:
1564 for( auto&& col : m_columns )
1565 {
1566 txt += '"';
1567
1568 if( col.has_units )
1569 {
1570 txt += wxString::Format( _( "%s (%s)" ),
1571 col.csv_name,
1573 }
1574 else
1575 {
1576 txt += col.csv_name;
1577 }
1578
1579 txt += wxT( "\";" );
1580 }
1581
1582 f.AddLine( txt );
1583
1584 // Print list of nets:
1585 const unsigned int num_rows = m_data_model->itemCount();
1586
1587 for( unsigned int row = 0; row < num_rows; row++ )
1588 {
1589 auto& i = m_data_model->itemAt( row );
1590
1591 if( i.GetIsGroup() || i.GetNetCode() == 0 )
1592 continue;
1593
1594 txt = "";
1595
1596 for( auto&& col : m_columns )
1597 {
1598 if( static_cast<int>( col.csv_flags ) & static_cast<int>( CSV_COLUMN_DESC::CSV_QUOTE ) )
1599 txt += '"' + m_data_model->valueAt( col.num, row ).GetString() + wxT( "\";" );
1600 else
1601 txt += m_data_model->valueAt( col.num, row ).GetString() + ';';
1602 }
1603
1604 f.AddLine( txt );
1605 }
1606
1607 m_in_reporting = false;
1608
1609 f.Write();
1610 f.Close();
1611}
1612
1613
1615{
1617}
1618
1619
1621{
1622 // ignore selection changes while the whole list is being rebuilt.
1624 return;
1625
1626 m_highlighting_nets = true;
1627
1628 RENDER_SETTINGS* renderSettings = m_frame->GetCanvas()->GetView()->GetPainter()->GetSettings();
1629
1630 if( m_netsList->HasSelection() )
1631 {
1632 wxDataViewItemArray sel;
1633 m_netsList->GetSelections( sel );
1634
1635 renderSettings->SetHighlight( false );
1636
1637 for( unsigned int i = 0; i < sel.GetCount(); ++i )
1638 {
1639 const LIST_ITEM* ii = static_cast<const LIST_ITEM*>( sel.Item( i ).GetID() );
1640
1641 if( ii->GetIsGroup() )
1642 {
1643 for( auto c = ii->ChildrenBegin(), end = ii->ChildrenEnd(); c != end; ++c )
1644 renderSettings->SetHighlight( true, ( *c )->GetNetCode(), true );
1645 }
1646 else
1647 {
1648 renderSettings->SetHighlight( true, ii->GetNetCode(), true );
1649 }
1650 }
1651 }
1652 else
1653 {
1654 renderSettings->SetHighlight( false );
1655 }
1656
1659
1660 m_highlighting_nets = false;
1661}
1662
1663
1664void PCB_NET_INSPECTOR_PANEL::OnColumnSorted( wxDataViewEvent& event )
1665{
1666 SaveSettings();
1667}
1668
1669
1671{
1672 // Rebuilt the nets list, and force rebuild of columns in case the stackup has chanaged
1673 buildNetsList( true );
1674 m_netsList->Refresh();
1675}
1676
1677
1679{
1680 wxString newNetName;
1681 NETNAME_VALIDATOR validator( &newNetName );
1682
1683 WX_TEXT_ENTRY_DIALOG dlg( this, _( "Net name:" ), _( "New Net" ), newNetName );
1684 dlg.SetTextValidator( validator );
1685
1686 while( true )
1687 {
1688 if( dlg.ShowModal() != wxID_OK || dlg.GetValue().IsEmpty() )
1689 return; //Aborted by user
1690
1691 newNetName = dlg.GetValue();
1692
1693 if( m_brd->FindNet( newNetName ) )
1694 {
1695 DisplayError( this,
1696 wxString::Format( _( "Net name '%s' is already in use." ), newNetName ) );
1697 newNetName = wxEmptyString;
1698 }
1699 else
1700 {
1701 break;
1702 }
1703 }
1704
1705 NETINFO_ITEM* newnet = new NETINFO_ITEM( m_brd, dlg.GetValue(), 0 );
1706
1707 m_brd->Add( newnet );
1708
1709 // We'll get an OnBoardItemAdded callback from this to update our listbox
1710 m_frame->OnModify();
1711}
1712
1713
1715{
1716 if( m_netsList->GetSelectedItemsCount() == 1 )
1717 {
1718 const LIST_ITEM* sel = static_cast<const LIST_ITEM*>( m_netsList->GetSelection().GetID() );
1719
1720 if( sel->GetIsGroup() )
1721 return;
1722
1723 NETINFO_ITEM* net = sel->GetNet();
1724 wxString fullNetName = net->GetNetname();
1725 wxString netPath;
1726 wxString shortNetName;
1727
1728 if( fullNetName.Contains( wxT( "/" ) ) )
1729 {
1730 netPath = fullNetName.BeforeLast( '/' ) + '/';
1731 shortNetName = fullNetName.AfterLast( '/' );
1732 }
1733 else
1734 {
1735 shortNetName = fullNetName;
1736 }
1737
1738 wxString unescapedShortName = UnescapeString( shortNetName );
1739
1740 WX_TEXT_ENTRY_DIALOG dlg( this, _( "Net name:" ), _( "Rename Net" ), unescapedShortName );
1741 NETNAME_VALIDATOR validator( &unescapedShortName );
1742 dlg.SetTextValidator( validator );
1743
1744 while( true )
1745 {
1746 if( dlg.ShowModal() != wxID_OK || dlg.GetValue() == unescapedShortName )
1747 return;
1748
1749 unescapedShortName = dlg.GetValue();
1750
1751 if( unescapedShortName.IsEmpty() )
1752 {
1753 DisplayError( this, wxString::Format( _( "Net name cannot be empty." ),
1754 unescapedShortName ) );
1755 continue;
1756 }
1757
1758 shortNetName = EscapeString( unescapedShortName, CTX_NETNAME );
1759 fullNetName = netPath + shortNetName;
1760
1761 if( m_brd->FindNet( shortNetName ) || m_brd->FindNet( fullNetName ) )
1762 {
1763 DisplayError( this, wxString::Format( _( "Net name '%s' is already in use." ),
1764 unescapedShortName ) );
1765 unescapedShortName = wxEmptyString;
1766 }
1767 else
1768 {
1769 break;
1770 }
1771 }
1772
1773 for( BOARD_CONNECTED_ITEM* boardItem : m_frame->GetBoard()->AllConnectedItems() )
1774 {
1775 if( boardItem->GetNet() == net )
1776 boardItem->SetFlags( CANDIDATE );
1777 else
1778 boardItem->ClearFlags( CANDIDATE );
1779 }
1780
1781 // the changed name might require re-grouping. remove/re-insert is easier.
1782 auto removed_item = m_data_model->deleteItem( m_data_model->findItem( net ) );
1783
1784 m_brd->Remove( net );
1785 net->SetNetname( fullNetName );
1786 m_brd->Add( net );
1787
1788 for( BOARD_CONNECTED_ITEM* boardItem : m_frame->GetBoard()->AllConnectedItems() )
1789 {
1790 if( boardItem->GetFlags() & CANDIDATE )
1791 boardItem->SetNet( net );
1792 }
1793
1794 buildNetsList();
1795
1796 if( std::optional<LIST_ITEM_ITER> r = m_data_model->findItem( net ) )
1797 m_netsList->Select( wxDataViewItem( r.value()->get() ) );
1798
1799 m_frame->OnModify();
1800
1801 // Currently only tracks and pads have netname annotations and need to be redrawn,
1802 // but zones are likely to follow. Since we don't have a way to ask what is current,
1803 // just refresh all items.
1806 }
1807}
1808
1809
1811{
1812 if( !m_netsList->HasSelection() )
1813 return;
1814
1815 wxDataViewItemArray sel;
1816 m_netsList->GetSelections( sel );
1817
1818 auto delete_one = [this]( const LIST_ITEM* i )
1819 {
1820 if( i->GetPadCount() == 0
1821 || IsOK( this, wxString::Format( _( "Net '%s' is in use. Delete anyway?" ),
1822 i->GetNetName() ) ) )
1823 {
1824 // This is a bit hacky, but it will do for now, since this is the only path
1825 // outside the netlist updater where you can remove a net from a BOARD.
1826 int removedCode = i->GetNetCode();
1827
1829 [removedCode]( KIGFX::VIEW_ITEM* aItem ) -> int
1830 {
1831 auto boardItem = dynamic_cast<BOARD_CONNECTED_ITEM*>( aItem );
1832
1833 if( boardItem && boardItem->GetNetCode() == removedCode )
1834 return KIGFX::REPAINT;
1835
1836 EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( aItem );
1837
1838 if( text && text->HasTextVars() )
1839 {
1840 text->ClearRenderCache();
1841 text->ClearBoundingBoxCache();
1843 }
1844
1845 return 0;
1846 } );
1847
1848 m_brd->Remove( i->GetNet() );
1849 m_frame->OnModify();
1850
1851 // We'll get an OnBoardItemRemoved callback from this to update our listbox
1852 }
1853 };
1854
1855 for( unsigned int i = 0; i < sel.GetCount(); ++i )
1856 {
1857 const LIST_ITEM* ii = static_cast<const LIST_ITEM*>( sel.Item( i ).GetID() );
1858
1859 if( ii->GetIsGroup() )
1860 {
1861 if( ii->ChildrenCount() != 0
1862 && IsOK( this, wxString::Format( _( "Delete all nets in group '%s'?" ),
1863 ii->GetGroupName() ) ) )
1864 {
1865 // we can't be iterating the children container and deleting items from
1866 // it at the same time. thus take a copy of it first.
1867 std::vector<const LIST_ITEM*> children;
1868 children.reserve( ii->ChildrenCount() );
1869 std::copy( ii->ChildrenBegin(), ii->ChildrenEnd(), std::back_inserter( children ) );
1870
1871 for( const LIST_ITEM* c : children )
1872 delete_one( c );
1873 }
1874 }
1875 else
1876 {
1877 delete_one( ii );
1878 }
1879 }
1880}
1881
1882/*****************************************************************************************
1883 *
1884 * Application-generated event handling
1885 *
1886 * ***************************************************************************************/
1887
1888
1890{
1891 SaveSettings();
1892 buildNetsList( true );
1893 m_data_model->updateAllItems();
1894}
1895
1896
1897void PCB_NET_INSPECTOR_PANEL::onUnitsChanged( wxCommandEvent& event )
1898{
1899 m_data_model->updateAllItems();
1900 event.Skip();
1901}
1902
1903
1904/*****************************************************************************************
1905 *
1906 * Settings persistence
1907 *
1908 * ***************************************************************************************/
1909
1910
1912{
1913 // Don't save settings if a board has not yet been loaded - events fire while we set up the
1914 // panel which overwrites the settings we haven't yet loaded
1916 return;
1917
1919 auto& cfg = localSettings.m_NetInspectorPanel;
1920
1921 // User-defined filters / grouping
1922 cfg.filter_text = m_searchCtrl->GetValue();
1923 cfg.filter_by_net_name = m_filter_by_net_name;
1924 cfg.filter_by_netclass = m_filter_by_netclass;
1925 cfg.group_by_netclass = m_group_by_netclass;
1926 cfg.group_by_constraint = m_group_by_constraint;
1927 cfg.show_zero_pad_nets = m_show_zero_pad_nets;
1928 cfg.show_unconnected_nets = m_show_unconnected_nets;
1929
1930 // Grid sorting
1931 wxDataViewColumn* sortingCol = m_netsList->GetSortingColumn();
1932 cfg.sorting_column = sortingCol ? static_cast<int>( sortingCol->GetModelColumn() ) : -1;
1933 cfg.sort_order_asc = sortingCol ? sortingCol->IsSortOrderAscending() : true;
1934
1935 // Column arrangement / sizes
1936 cfg.col_order.resize( m_data_model->columnCount() );
1937 cfg.col_widths.resize( m_data_model->columnCount() );
1938 cfg.col_hidden.resize( m_data_model->columnCount() );
1939
1940 for( unsigned int ii = 0; ii < m_data_model->columnCount(); ++ii )
1941 {
1942 cfg.col_order[ii] = (int) m_netsList->GetColumn( ii )->GetModelColumn();
1943 cfg.col_widths[ii] = m_netsList->GetColumn( ii )->GetWidth();
1944 cfg.col_hidden[ii] = m_netsList->GetColumn( ii )->IsHidden();
1945 }
1946
1947 // Expanded rows
1948 cfg.expanded_rows.clear();
1949 std::vector<std::pair<wxString, wxDataViewItem>> groupItems =
1950 m_data_model->getGroupDataViewItems();
1951
1952 for( std::pair<wxString, wxDataViewItem>& item : groupItems )
1953 {
1954 if( m_netsList->IsExpanded( item.second ) )
1955 cfg.expanded_rows.push_back( item.first );
1956 }
1957
1958 // Customer group rules
1959 cfg.custom_group_rules.clear();
1960
1961 for( const std::unique_ptr<EDA_COMBINED_MATCHER>& rule : m_custom_group_rules )
1962 cfg.custom_group_rules.push_back( rule->GetPattern() );
1963}
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.
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:80
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:773
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
Definition: board.cpp:998
const std::set< int > & GetHighLightNetCodes() const
Definition: board.h:532
const std::vector< BOARD_CONNECTED_ITEM * > AllConnectedItems()
Definition: board.cpp:2608
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:2663
NETINFO_ITEM * FindNet(int aNetcode) const
Search for a net with the given netcode.
Definition: board.cpp:1916
int GetCopperLayerCount() const
Definition: board.cpp:736
const FOOTPRINTS & Footprints() const
Definition: board.h:331
unsigned GetNodesCount(int aNet=-1) const
Definition: board.cpp:1651
bool IsHighLightNetON() const
Definition: board.h:548
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition: board.cpp:577
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:890
void RemoveListener(BOARD_LISTENER *aListener)
Remove the specified listener.
Definition: board.cpp:2670
void Remove(BOARD_ITEM *aBoardItem, REMOVE_MODE aMode=REMOVE_MODE::NORMAL) override
Removes an item from the container.
Definition: board.cpp:1136
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
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
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:530
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.