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
637 const auto cn_items = std::equal_range( aCNItems.begin(), aCNItems.end(), aNet->GetNetCode(),
639
640 for( auto i = cn_items.first; i != cn_items.second; ++i )
641 {
642 BOARD_CONNECTED_ITEM* item = ( *i )->Parent();
643
644 if( item->Type() == PCB_PAD_T )
645 {
646 new_item->AddPadDieLength( static_cast<PAD*>( item )->GetPadToDieLength() );
647 }
648 else if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( item ) )
649 {
650 new_item->AddLayerWireLength( track->GetLength(),
651 static_cast<int>( 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
793 for( size_t ii = 0; ii < MAX_CU_LAYERS; ++ii )
794 cur_list_item->SetLayerWireLength( new_list_item->GetLayerWireLength( ii ), ii );
795
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
897 m_data_model->addItem( std::move( new_item ) );
898 }
899 }
900 else if( BOARD_CONNECTED_ITEM* i = dynamic_cast<BOARD_CONNECTED_ITEM*>( aBoardItem ) )
901 {
902 std::optional<LIST_ITEM_ITER> r = m_data_model->findItem( i->GetNet() );
903
904 if( r )
905 {
906 // try to handle frequent operations quickly.
907 if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( i ) )
908 {
909 const std::unique_ptr<LIST_ITEM>& list_item = *r.value();
910 int len = track->GetLength();
911
912 list_item->AddLayerWireLength( len, static_cast<int>( track->GetLayer() ) );
913
914 if( track->Type() == PCB_VIA_T )
915 {
916 list_item->AddViaCount( 1 );
917 list_item->AddViaLength( calculateViaLength( track ) );
918 }
919
921 return;
922 }
923 }
924
925 // resort to generic slower net update otherwise.
926 updateNet( i->GetNet() );
927 }
928 else if( FOOTPRINT* footprint = dynamic_cast<FOOTPRINT*>( aBoardItem ) )
929 {
930 for( const PAD* pad : footprint->Pads() )
931 {
932 std::optional<LIST_ITEM_ITER> r = m_data_model->findItem( pad->GetNet() );
933
934 if( !r )
935 {
936 // if show-zero-pads is off, we might not have this net
937 // in our list yet, so add it first.
938 // notice that at this point we are very certain that this net
939 // will have at least one pad.
940
941 if( netFilterMatches( pad->GetNet() ) )
942 r = m_data_model->addItem( std::make_unique<LIST_ITEM>( pad->GetNet() ) );
943 }
944
945 if( r )
946 {
947 const std::unique_ptr<LIST_ITEM>& list_item = *r.value();
948 int len = pad->GetPadToDieLength();
949
950 list_item->AddPadCount( 1 );
951 list_item->AddPadDieLength( len );
952
953 if( list_item->GetPadCount() == 0 && !m_show_zero_pad_nets )
954 m_data_model->deleteItem( r );
955 else
957 }
958 }
959 }
960}
961
962
964 std::vector<BOARD_ITEM*>& aBoardItems )
965{
966 if( !IsShownOnScreen() )
967 return;
968
969 // Rebuild full netlist for large changes
970 if( aBoardItems.size() > 25 )
971 {
973 m_netsList->Refresh();
974 }
975 else
976 {
977 for( BOARD_ITEM* item : aBoardItems )
978 {
979 OnBoardItemAdded( aBoard, item );
980 }
981 }
982}
983
984
986{
987 if( !IsShownOnScreen() )
988 return;
989
990 if( NETINFO_ITEM* net = dynamic_cast<NETINFO_ITEM*>( aBoardItem ) )
991 {
992 m_data_model->deleteItem( m_data_model->findItem( net ) );
993 }
994 else if( FOOTPRINT* footprint = dynamic_cast<FOOTPRINT*>( aBoardItem ) )
995 {
996 for( const PAD* pad : footprint->Pads() )
997 {
998 std::optional<LIST_ITEM_ITER> r = m_data_model->findItem( pad->GetNet() );
999
1000 if( r )
1001 {
1002 const std::unique_ptr<LIST_ITEM>& list_item = *r.value();
1003 int len = pad->GetPadToDieLength();
1004
1005 list_item->SubPadCount( 1 );
1006 list_item->SubPadDieLength( len );
1007
1008 if( list_item->GetPadCount() == 0 && !m_show_zero_pad_nets )
1009 m_data_model->deleteItem( r );
1010 else
1012 }
1013 }
1014 }
1015 else if( BOARD_CONNECTED_ITEM* i = dynamic_cast<BOARD_CONNECTED_ITEM*>( aBoardItem ) )
1016 {
1017 std::optional<LIST_ITEM_ITER> r = m_data_model->findItem( i->GetNet() );
1018
1019 if( r )
1020 {
1021 // try to handle frequent operations quickly.
1022 if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( i ) )
1023 {
1024 const std::unique_ptr<LIST_ITEM>& list_item = *r.value();
1025 int len = track->GetLength();
1026
1027 list_item->SubLayerWireLength( len, static_cast<int>( track->GetLayer() ) );
1028
1029 if( track->Type() == PCB_VIA_T )
1030 {
1031 list_item->SubViaCount( 1 );
1032 list_item->SubViaLength( calculateViaLength( track ) );
1033 }
1034
1036 return;
1037 }
1038
1039 // resort to generic slower net update otherwise.
1040 updateNet( i->GetNet() );
1041 }
1042 }
1043}
1044
1045
1047 std::vector<BOARD_ITEM*>& aBoardItems )
1048{
1049 if( !IsShownOnScreen() )
1050 return;
1051
1052 if( aBoardItems.size() > 25 )
1053 {
1054 buildNetsList();
1055 m_netsList->Refresh();
1056 }
1057 else
1058 {
1059 for( BOARD_ITEM* item : aBoardItems )
1060 {
1061 OnBoardItemRemoved( aBoard, item );
1062 }
1063 }
1064}
1065
1066
1068{
1069 if( !IsShownOnScreen() )
1070 return;
1071
1072 buildNetsList();
1073 m_netsList->Refresh();
1074}
1075
1076
1078{
1079 if( !IsShownOnScreen() )
1080 return;
1081
1082 if( dynamic_cast<BOARD_CONNECTED_ITEM*>( aBoardItem ) != nullptr
1083 || dynamic_cast<FOOTPRINT*>( aBoardItem ) != nullptr )
1084 {
1085 buildNetsList();
1086 m_netsList->Refresh();
1087 }
1088}
1089
1090
1092 std::vector<BOARD_ITEM*>& aBoardItems )
1093{
1094 if( !IsShownOnScreen() )
1095 return;
1096
1097 buildNetsList();
1098 m_netsList->Refresh();
1099}
1100
1101
1103 std::vector<BOARD_ITEM*>& aAddedItems,
1104 std::vector<BOARD_ITEM*>& aRemovedItems,
1105 std::vector<BOARD_ITEM*>& aDeletedItems )
1106{
1107 if( !IsShownOnScreen() )
1108 return;
1109
1110 buildNetsList();
1111 m_netsList->Refresh();
1112}
1113
1114
1116{
1117 if( m_highlighting_nets || !IsShownOnScreen() )
1118 return;
1119
1120 if( !m_brd->IsHighLightNetON() )
1121 {
1122 m_netsList->UnselectAll();
1123 }
1124 else
1125 {
1126 const std::set<int>& selected_codes = m_brd->GetHighLightNetCodes();
1127
1128 wxDataViewItemArray new_selection;
1129 new_selection.Alloc( selected_codes.size() );
1130
1131 for( int code : selected_codes )
1132 {
1133 if( std::optional<LIST_ITEM_ITER> r = m_data_model->findItem( code ) )
1134 new_selection.Add( wxDataViewItem( &***r ) );
1135 }
1136
1137 m_netsList->SetSelections( new_selection );
1138
1139 if( !new_selection.IsEmpty() )
1140 m_netsList->EnsureVisible( new_selection.Item( 0 ) );
1141 }
1142}
1143
1144
1145/*****************************************************************************************
1146 *
1147 * UI-generated event handling
1148 *
1149 * ***************************************************************************************/
1150
1152{
1153 buildNetsList();
1155}
1156
1157
1159{
1160 bool multipleSelections = false;
1161 const LIST_ITEM* selItem = nullptr;
1162
1163 if( m_netsList->GetSelectedItemsCount() == 1 )
1164 {
1165 selItem = static_cast<const LIST_ITEM*>( m_netsList->GetSelection().GetID() );
1166 }
1167 else
1168 {
1169 if( m_netsList->GetSelectedItemsCount() > 1 )
1170 multipleSelections = true;
1171 }
1172
1173 wxMenu menu;
1174
1175 // Net edit menu items
1176 wxMenuItem* highlightNet = new wxMenuItem( &menu, ID_HIGHLIGHT_SELECTED_NETS,
1177 _( "Highlight Selected Net" ),
1178 wxEmptyString, wxITEM_NORMAL );
1179 menu.Append( highlightNet );
1180
1181 wxMenuItem* clearHighlighting = new wxMenuItem( &menu, ID_CLEAR_HIGHLIGHTING,
1182 _( "Clear Net Highlighting" ),
1183 wxEmptyString, wxITEM_NORMAL );
1184 menu.Append( clearHighlighting );
1185
1186 RENDER_SETTINGS* renderSettings = m_frame->GetCanvas()->GetView()->GetPainter()->GetSettings();
1187 const std::set<int>& selected_codes = renderSettings->GetHighlightNetCodes();
1188
1189 if( selected_codes.size() == 0 )
1190 clearHighlighting->Enable( false );
1191
1192 menu.AppendSeparator();
1193
1194 wxMenuItem* renameNet = new wxMenuItem( &menu, ID_RENAME_NET, _( "Rename Selected Net" ),
1195 wxEmptyString, wxITEM_NORMAL );
1196 menu.Append( renameNet );
1197
1198 wxMenuItem* deleteNet = new wxMenuItem( &menu, ID_DELETE_NET, _( "Delete Selected Net" ),
1199 wxEmptyString, wxITEM_NORMAL );
1200 menu.Append( deleteNet );
1201
1202 menu.AppendSeparator();
1203
1204 wxMenuItem* addNet = new wxMenuItem( &menu, ID_ADD_NET, _( "Add Net" ),
1205 wxEmptyString, wxITEM_NORMAL );
1206 menu.Append( addNet );
1207
1208 if( !selItem && !multipleSelections )
1209 {
1210 highlightNet->Enable( false );
1211 deleteNet->Enable( false );
1212 renameNet->Enable( false );
1213 }
1214 else
1215 {
1216 if( multipleSelections || selItem->GetIsGroup() )
1217 {
1218 highlightNet->SetItemLabel( _( "Highlight Selected Nets" ) );
1219 renameNet->Enable( false );
1220 deleteNet->SetItemLabel( _( "Delete Selected Nets" ) );
1221 }
1222 }
1223
1224 menu.AppendSeparator();
1225
1226 wxMenuItem* removeSelectedGroup = new wxMenuItem( &menu, ID_REMOVE_SELECTED_GROUP,
1227 _( "Remove Selected Custom Group" ),
1228 wxEmptyString, wxITEM_NORMAL );
1229 menu.Append( removeSelectedGroup );
1230
1231 if( !selItem || !selItem->GetIsGroup() )
1232 removeSelectedGroup->Enable( false );
1233
1234 menu.Bind( wxEVT_COMMAND_MENU_SELECTED, &PCB_NET_INSPECTOR_PANEL::onSettingsMenu, this );
1235
1236 PopupMenu( &menu );
1237}
1238
1239
1241{
1242 SaveSettings();
1243 buildNetsList();
1244}
1245
1246
1248{
1249 wxString newGroupName;
1250 NETNAME_VALIDATOR validator( &newGroupName );
1251
1252 WX_TEXT_ENTRY_DIALOG dlg( this, _( "Group name / pattern:" ), _( "New Group" ), newGroupName );
1253 wxStaticText* help = new wxStaticText( &dlg, wxID_ANY,
1254 _( "(Use /.../ to indicate a regular expression.)" ) );
1255 help->SetFont( KIUI::GetInfoFont( this ).Italic() );
1256 dlg.m_ContentSizer->Add( help, 0, wxALL|wxEXPAND, 5 );
1257 dlg.SetTextValidator( validator );
1258 dlg.GetSizer()->SetSizeHints( &dlg );
1259
1260 if( dlg.ShowModal() != wxID_OK || dlg.GetValue().IsEmpty() )
1261 return; //Aborted by user
1262
1263 newGroupName = UnescapeString( dlg.GetValue() );
1264
1265 if( newGroupName == "" )
1266 return;
1267
1268 if( std::find_if( m_custom_group_rules.begin(), m_custom_group_rules.end(),
1269 [&]( std::unique_ptr<EDA_COMBINED_MATCHER>& rule )
1270 {
1271 return rule->GetPattern().Upper() == newGroupName.Upper();
1272 } ) == m_custom_group_rules.end() )
1273 {
1274 m_custom_group_rules.push_back( std::make_unique<EDA_COMBINED_MATCHER>( newGroupName,
1275 CTX_NET ) );
1276 SaveSettings();
1277 }
1278
1279 buildNetsList();
1280}
1281
1282
1284{
1285 m_highlighting_nets = true;
1286
1290
1291 m_highlighting_nets = false;
1292}
1293
1294
1296{
1297 if( !m_row_expanding )
1298 SaveSettings();
1299}
1300
1301
1303{
1304 wxMenu menu;
1306 menu.Bind( wxEVT_COMMAND_MENU_SELECTED, &PCB_NET_INSPECTOR_PANEL::onSettingsMenu, this );
1307 PopupMenu( &menu );
1308}
1309
1310
1311void PCB_NET_INSPECTOR_PANEL::OnConfigButton( wxCommandEvent& event )
1312{
1314 auto& cfg = localSettings.m_NetInspectorPanel;
1315
1316 const LIST_ITEM* selItem = nullptr;
1317
1318 if( m_netsList->GetSelectedItemsCount() == 1 )
1319 {
1320 selItem = static_cast<const LIST_ITEM*>( m_netsList->GetSelection().GetID() );
1321 }
1322
1323 wxMenu menu;
1324
1325 // Filtering menu items
1326 wxMenuItem* filterByNetName = new wxMenuItem( &menu, ID_FILTER_BY_NET_NAME,
1327 _( "Filter by Net Name" ),
1328 wxEmptyString, wxITEM_CHECK );
1329 filterByNetName->Check( cfg.filter_by_net_name );
1330 menu.Append( filterByNetName );
1331
1332 wxMenuItem* filterByNetclass = new wxMenuItem( &menu, ID_FILTER_BY_NETCLASS,
1333 _( "Filter by Netclass" ),
1334 wxEmptyString, wxITEM_CHECK );
1335 filterByNetclass->Check( cfg.filter_by_netclass );
1336 menu.Append( filterByNetclass );
1337
1338 menu.AppendSeparator();
1339
1340 // Grouping menu items
1341 //wxMenuItem* groupConstraint =
1342 // new wxMenuItem( &menu, ID_GROUP_BY_CONSTRAINT, _( "Group by DRC Constraint" ),
1343 // wxEmptyString, wxITEM_CHECK );
1344 //groupConstraint->Check( m_group_by_constraint );
1345 //menu.Append( groupConstraint );
1346
1347 wxMenuItem* groupNetclass = new wxMenuItem( &menu, ID_GROUP_BY_NETCLASS,
1348 _( "Group by Netclass" ),
1349 wxEmptyString, wxITEM_CHECK );
1350 groupNetclass->Check( m_group_by_netclass );
1351 menu.Append( groupNetclass );
1352
1353 menu.AppendSeparator();
1354
1355 wxMenuItem* addGroup = new wxMenuItem( &menu, ID_ADD_GROUP, _( "Add Custom Group" ),
1356 wxEmptyString, wxITEM_NORMAL );
1357 menu.Append( addGroup );
1358
1359 wxMenuItem* removeSelectedGroup = new wxMenuItem( &menu, ID_REMOVE_SELECTED_GROUP,
1360 _( "Remove Selected Custom Group" ),
1361 wxEmptyString, wxITEM_NORMAL );
1362 menu.Append( removeSelectedGroup );
1363
1364 if( !selItem || !selItem->GetIsGroup() )
1365 removeSelectedGroup->Enable( false );
1366
1367 wxMenuItem* removeCustomGroups = new wxMenuItem( &menu, ID_REMOVE_GROUPS,
1368 _( "Remove All Custom Groups" ),
1369 wxEmptyString, wxITEM_NORMAL );
1370 menu.Append( removeCustomGroups );
1371 removeCustomGroups->Enable( m_custom_group_rules.size() != 0 );
1372
1373 menu.AppendSeparator();
1374
1375 wxMenuItem* showZeroNetPads = new wxMenuItem( &menu, ID_SHOW_ZERO_NET_PADS,
1376 _( "Show Zero Pad Nets" ),
1377 wxEmptyString, wxITEM_CHECK );
1378 showZeroNetPads->Check( m_show_zero_pad_nets );
1379 menu.Append( showZeroNetPads );
1380
1381 wxMenuItem* showUnconnectedNets = new wxMenuItem( &menu, ID_SHOW_UNCONNECTED_NETS,
1382 _( "Show Unconnected Nets" ),
1383 wxEmptyString, wxITEM_CHECK );
1384 showUnconnectedNets->Check( m_show_unconnected_nets );
1385 menu.Append( showUnconnectedNets );
1386
1387 menu.AppendSeparator();
1388
1389 // Report generation
1390 wxMenuItem* generateReport = new wxMenuItem( &menu, ID_GENERATE_REPORT,
1391 _( "Save Net Inspector Report" ),
1392 wxEmptyString, wxITEM_NORMAL );
1393 menu.Append( generateReport );
1394
1395 menu.AppendSeparator();
1396
1397 // Show / hide columns menu items
1398 wxMenu* colsMenu = new wxMenu();
1399 generateShowHideColumnMenu( colsMenu );
1400 menu.AppendSubMenu( colsMenu, _( "Show / Hide Columns" ) );
1401
1402 menu.Bind( wxEVT_COMMAND_MENU_SELECTED, &PCB_NET_INSPECTOR_PANEL::onSettingsMenu, this );
1403
1404 PopupMenu( &menu );
1405}
1406
1407
1409{
1410 for( int i = 1; i <= COLUMN_LAST_STATIC_COL; ++i )
1411 {
1412 wxMenuItem* opt = new wxMenuItem( target, ID_HIDE_COLUMN + i, m_columns[i].display_name,
1413 wxEmptyString, wxITEM_CHECK );
1414 wxDataViewColumn* col = getDisplayedColumnForModelField( i );
1415 target->Append( opt );
1416 opt->Check( !col->IsHidden() );
1417 }
1418
1419 target->AppendSeparator();
1420
1421 for( std::size_t i = COLUMN_LAST_STATIC_COL + 1; i < m_columns.size(); ++i )
1422 {
1423 wxMenuItem* opt = new wxMenuItem( target, ID_HIDE_COLUMN + i, m_columns[i].display_name,
1424 wxEmptyString, wxITEM_CHECK );
1425 wxDataViewColumn* col = getDisplayedColumnForModelField( i );
1426 target->Append( opt );
1427 opt->Check( !col->IsHidden() );
1428 }
1429}
1430
1431
1432void PCB_NET_INSPECTOR_PANEL::onSettingsMenu( wxCommandEvent& event )
1433{
1434 bool saveAndRebuild = true;
1435
1436 switch( event.GetId() )
1437 {
1438 case ID_ADD_NET:
1439 onAddNet();
1440 break;
1441
1442 case ID_RENAME_NET:
1444 break;
1445
1446 case ID_DELETE_NET:
1448 break;
1449
1450 case ID_ADD_GROUP:
1451 onAddGroup();
1452 break;
1453
1456 break;
1457
1460 break;
1461
1464 break;
1465
1468 break;
1469
1472 break;
1473
1474 case ID_REMOVE_GROUPS:
1475 m_custom_group_rules.clear();
1476 break;
1477
1480 break;
1481
1484 break;
1485
1486 case ID_GENERATE_REPORT:
1488 saveAndRebuild = false;
1489 break;
1490
1493 saveAndRebuild = false;
1494 break;
1495
1498 saveAndRebuild = false;
1499 break;
1500
1501 default:
1502 if( event.GetId() >= ID_HIDE_COLUMN )
1503 {
1504 const int columnId = event.GetId() - ID_HIDE_COLUMN;
1505 wxDataViewColumn* col = getDisplayedColumnForModelField( columnId );
1506 // Make sure we end up with something non-zero so we can resize it
1507 col->SetWidth( std::max( col->GetWidth(), 10 ) );
1508 col->SetHidden( !col->IsHidden() );
1509 }
1510 break;
1511 }
1512
1513 if( saveAndRebuild )
1514 {
1515 SaveSettings();
1516 buildNetsList();
1517 }
1518}
1519
1520
1522{
1523 if( m_netsList->GetSelectedItemsCount() == 1 )
1524 {
1525 auto* selItem = static_cast<const LIST_ITEM*>( m_netsList->GetSelection().GetID() );
1526
1527 if( selItem->GetIsGroup() )
1528 {
1529 wxString groupName = selItem->GetGroupName();
1530 auto groupIter = std::find_if( m_custom_group_rules.begin(), m_custom_group_rules.end(),
1531 [&]( std::unique_ptr<EDA_COMBINED_MATCHER>& rule )
1532 {
1533 return rule->GetPattern() == groupName;
1534 } );
1535
1536 if( groupIter != m_custom_group_rules.end() )
1537 {
1538 m_custom_group_rules.erase( groupIter );
1539 SaveSettings();
1540 buildNetsList();
1541 }
1542 }
1543 }
1544}
1545
1546
1548{
1549 wxFileDialog dlg( this, _( "Save Net Inspector Report File" ), "", "",
1550 _( "Report file" ) + AddFileExtListToFilter( { "csv" } ),
1551 wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
1552
1553 if( dlg.ShowModal() == wxID_CANCEL )
1554 return;
1555
1556 wxTextFile f( dlg.GetPath() );
1557
1558 f.Create();
1559
1560 wxString txt;
1561
1562 m_in_reporting = true;
1563
1564 // Print Header:
1565 for( auto&& col : m_columns )
1566 {
1567 txt += '"';
1568
1569 if( col.has_units )
1570 {
1571 txt += wxString::Format( _( "%s (%s)" ),
1572 col.csv_name,
1574 }
1575 else
1576 {
1577 txt += col.csv_name;
1578 }
1579
1580 txt += wxT( "\";" );
1581 }
1582
1583 f.AddLine( txt );
1584
1585 // Print list of nets:
1586 const unsigned int num_rows = m_data_model->itemCount();
1587
1588 for( unsigned int row = 0; row < num_rows; row++ )
1589 {
1590 auto& i = m_data_model->itemAt( row );
1591
1592 if( i.GetIsGroup() || i.GetNetCode() == 0 )
1593 continue;
1594
1595 txt = "";
1596
1597 for( auto&& col : m_columns )
1598 {
1599 if( static_cast<int>( col.csv_flags ) & static_cast<int>( CSV_COLUMN_DESC::CSV_QUOTE ) )
1600 txt += '"' + m_data_model->valueAt( col.num, row ).GetString() + wxT( "\";" );
1601 else
1602 txt += m_data_model->valueAt( col.num, row ).GetString() + ';';
1603 }
1604
1605 f.AddLine( txt );
1606 }
1607
1608 m_in_reporting = false;
1609
1610 f.Write();
1611 f.Close();
1612}
1613
1614
1616{
1618}
1619
1620
1622{
1623 // ignore selection changes while the whole list is being rebuilt.
1625 return;
1626
1627 m_highlighting_nets = true;
1628
1629 RENDER_SETTINGS* renderSettings = m_frame->GetCanvas()->GetView()->GetPainter()->GetSettings();
1630
1631 if( m_netsList->HasSelection() )
1632 {
1633 wxDataViewItemArray sel;
1634 m_netsList->GetSelections( sel );
1635
1636 renderSettings->SetHighlight( false );
1637
1638 for( unsigned int i = 0; i < sel.GetCount(); ++i )
1639 {
1640 const LIST_ITEM* ii = static_cast<const LIST_ITEM*>( sel.Item( i ).GetID() );
1641
1642 if( ii->GetIsGroup() )
1643 {
1644 for( auto c = ii->ChildrenBegin(), end = ii->ChildrenEnd(); c != end; ++c )
1645 renderSettings->SetHighlight( true, ( *c )->GetNetCode(), true );
1646 }
1647 else
1648 {
1649 renderSettings->SetHighlight( true, ii->GetNetCode(), true );
1650 }
1651 }
1652 }
1653 else
1654 {
1655 renderSettings->SetHighlight( false );
1656 }
1657
1660
1661 m_highlighting_nets = false;
1662}
1663
1664
1665void PCB_NET_INSPECTOR_PANEL::OnColumnSorted( wxDataViewEvent& event )
1666{
1667 SaveSettings();
1668}
1669
1670
1672{
1673 // Rebuilt the nets list, and force rebuild of columns in case the stackup has chanaged
1674 buildNetsList( true );
1675 m_netsList->Refresh();
1676}
1677
1678
1680{
1681 wxString newNetName;
1682 NETNAME_VALIDATOR validator( &newNetName );
1683
1684 WX_TEXT_ENTRY_DIALOG dlg( this, _( "Net name:" ), _( "New Net" ), newNetName );
1685 dlg.SetTextValidator( validator );
1686
1687 while( true )
1688 {
1689 if( dlg.ShowModal() != wxID_OK || dlg.GetValue().IsEmpty() )
1690 return; //Aborted by user
1691
1692 newNetName = dlg.GetValue();
1693
1694 if( m_brd->FindNet( newNetName ) )
1695 {
1696 DisplayError( this,
1697 wxString::Format( _( "Net name '%s' is already in use." ), newNetName ) );
1698 newNetName = wxEmptyString;
1699 }
1700 else
1701 {
1702 break;
1703 }
1704 }
1705
1706 NETINFO_ITEM* newnet = new NETINFO_ITEM( m_brd, dlg.GetValue(), 0 );
1707
1708 m_brd->Add( newnet );
1709
1710 // We'll get an OnBoardItemAdded callback from this to update our listbox
1711 m_frame->OnModify();
1712}
1713
1714
1716{
1717 if( m_netsList->GetSelectedItemsCount() == 1 )
1718 {
1719 const LIST_ITEM* sel = static_cast<const LIST_ITEM*>( m_netsList->GetSelection().GetID() );
1720
1721 if( sel->GetIsGroup() )
1722 return;
1723
1724 NETINFO_ITEM* net = sel->GetNet();
1725 wxString fullNetName = net->GetNetname();
1726 wxString netPath;
1727 wxString shortNetName;
1728
1729 if( fullNetName.Contains( wxT( "/" ) ) )
1730 {
1731 netPath = fullNetName.BeforeLast( '/' ) + '/';
1732 shortNetName = fullNetName.AfterLast( '/' );
1733 }
1734 else
1735 {
1736 shortNetName = fullNetName;
1737 }
1738
1739 wxString unescapedShortName = UnescapeString( shortNetName );
1740
1741 WX_TEXT_ENTRY_DIALOG dlg( this, _( "Net name:" ), _( "Rename Net" ), unescapedShortName );
1742 NETNAME_VALIDATOR validator( &unescapedShortName );
1743 dlg.SetTextValidator( validator );
1744
1745 while( true )
1746 {
1747 if( dlg.ShowModal() != wxID_OK || dlg.GetValue() == unescapedShortName )
1748 return;
1749
1750 unescapedShortName = dlg.GetValue();
1751
1752 if( unescapedShortName.IsEmpty() )
1753 {
1754 DisplayError( this, wxString::Format( _( "Net name cannot be empty." ),
1755 unescapedShortName ) );
1756 continue;
1757 }
1758
1759 shortNetName = EscapeString( unescapedShortName, CTX_NETNAME );
1760 fullNetName = netPath + shortNetName;
1761
1762 if( m_brd->FindNet( shortNetName ) || m_brd->FindNet( fullNetName ) )
1763 {
1764 DisplayError( this, wxString::Format( _( "Net name '%s' is already in use." ),
1765 unescapedShortName ) );
1766 unescapedShortName = wxEmptyString;
1767 }
1768 else
1769 {
1770 break;
1771 }
1772 }
1773
1774 for( BOARD_CONNECTED_ITEM* boardItem : m_frame->GetBoard()->AllConnectedItems() )
1775 {
1776 if( boardItem->GetNet() == net )
1777 boardItem->SetFlags( CANDIDATE );
1778 else
1779 boardItem->ClearFlags( CANDIDATE );
1780 }
1781
1782 // the changed name might require re-grouping. remove/re-insert is easier.
1783 auto removed_item = m_data_model->deleteItem( m_data_model->findItem( net ) );
1784
1785 m_brd->Remove( net );
1786 net->SetNetname( fullNetName );
1787 m_brd->Add( net );
1788
1789 for( BOARD_CONNECTED_ITEM* boardItem : m_frame->GetBoard()->AllConnectedItems() )
1790 {
1791 if( boardItem->GetFlags() & CANDIDATE )
1792 boardItem->SetNet( net );
1793 }
1794
1795 buildNetsList();
1796
1797 if( std::optional<LIST_ITEM_ITER> r = m_data_model->findItem( net ) )
1798 m_netsList->Select( wxDataViewItem( r.value()->get() ) );
1799
1800 m_frame->OnModify();
1801
1802 // Currently only tracks and pads have netname annotations and need to be redrawn,
1803 // but zones are likely to follow. Since we don't have a way to ask what is current,
1804 // just refresh all items.
1807 }
1808}
1809
1810
1812{
1813 if( !m_netsList->HasSelection() )
1814 return;
1815
1816 wxDataViewItemArray sel;
1817 m_netsList->GetSelections( sel );
1818
1819 auto delete_one = [this]( const LIST_ITEM* i )
1820 {
1821 if( i->GetPadCount() == 0
1822 || IsOK( this, wxString::Format( _( "Net '%s' is in use. Delete anyway?" ),
1823 i->GetNetName() ) ) )
1824 {
1825 // This is a bit hacky, but it will do for now, since this is the only path
1826 // outside the netlist updater where you can remove a net from a BOARD.
1827 int removedCode = i->GetNetCode();
1828
1830 [removedCode]( KIGFX::VIEW_ITEM* aItem ) -> int
1831 {
1832 auto boardItem = dynamic_cast<BOARD_CONNECTED_ITEM*>( aItem );
1833
1834 if( boardItem && boardItem->GetNetCode() == removedCode )
1835 return KIGFX::REPAINT;
1836
1837 EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( aItem );
1838
1839 if( text && text->HasTextVars() )
1840 {
1841 text->ClearRenderCache();
1842 text->ClearBoundingBoxCache();
1844 }
1845
1846 return 0;
1847 } );
1848
1849 m_brd->Remove( i->GetNet() );
1850 m_frame->OnModify();
1851
1852 // We'll get an OnBoardItemRemoved callback from this to update our listbox
1853 }
1854 };
1855
1856 for( unsigned int i = 0; i < sel.GetCount(); ++i )
1857 {
1858 const LIST_ITEM* ii = static_cast<const LIST_ITEM*>( sel.Item( i ).GetID() );
1859
1860 if( ii->GetIsGroup() )
1861 {
1862 if( ii->ChildrenCount() != 0
1863 && IsOK( this, wxString::Format( _( "Delete all nets in group '%s'?" ),
1864 ii->GetGroupName() ) ) )
1865 {
1866 // we can't be iterating the children container and deleting items from
1867 // it at the same time. thus take a copy of it first.
1868 std::vector<const LIST_ITEM*> children;
1869 children.reserve( ii->ChildrenCount() );
1870 std::copy( ii->ChildrenBegin(), ii->ChildrenEnd(), std::back_inserter( children ) );
1871
1872 for( const LIST_ITEM* c : children )
1873 delete_one( c );
1874 }
1875 }
1876 else
1877 {
1878 delete_one( ii );
1879 }
1880 }
1881}
1882
1883/*****************************************************************************************
1884 *
1885 * Application-generated event handling
1886 *
1887 * ***************************************************************************************/
1888
1889
1891{
1892 SaveSettings();
1893 buildNetsList( true );
1894 m_data_model->updateAllItems();
1895}
1896
1897
1898void PCB_NET_INSPECTOR_PANEL::onUnitsChanged( wxCommandEvent& event )
1899{
1900 m_data_model->updateAllItems();
1901 event.Skip();
1902}
1903
1904
1905/*****************************************************************************************
1906 *
1907 * Settings persistence
1908 *
1909 * ***************************************************************************************/
1910
1911
1913{
1914 // Don't save settings if a board has not yet been loaded - events fire while we set up the
1915 // panel which overwrites the settings we haven't yet loaded
1917 return;
1918
1920 auto& cfg = localSettings.m_NetInspectorPanel;
1921
1922 // User-defined filters / grouping
1923 cfg.filter_text = m_searchCtrl->GetValue();
1924 cfg.filter_by_net_name = m_filter_by_net_name;
1925 cfg.filter_by_netclass = m_filter_by_netclass;
1926 cfg.group_by_netclass = m_group_by_netclass;
1927 cfg.group_by_constraint = m_group_by_constraint;
1928 cfg.show_zero_pad_nets = m_show_zero_pad_nets;
1929 cfg.show_unconnected_nets = m_show_unconnected_nets;
1930
1931 // Grid sorting
1932 wxDataViewColumn* sortingCol = m_netsList->GetSortingColumn();
1933 cfg.sorting_column = sortingCol ? static_cast<int>( sortingCol->GetModelColumn() ) : -1;
1934 cfg.sort_order_asc = sortingCol ? sortingCol->IsSortOrderAscending() : true;
1935
1936 // Column arrangement / sizes
1937 cfg.col_order.resize( m_data_model->columnCount() );
1938 cfg.col_widths.resize( m_data_model->columnCount() );
1939 cfg.col_hidden.resize( m_data_model->columnCount() );
1940
1941 for( unsigned int ii = 0; ii < m_data_model->columnCount(); ++ii )
1942 {
1943 cfg.col_order[ii] = (int) m_netsList->GetColumn( ii )->GetModelColumn();
1944 cfg.col_widths[ii] = m_netsList->GetColumn( ii )->GetWidth();
1945 cfg.col_hidden[ii] = m_netsList->GetColumn( ii )->IsHidden();
1946 }
1947
1948 // Expanded rows
1949 cfg.expanded_rows.clear();
1950 std::vector<std::pair<wxString, wxDataViewItem>> groupItems =
1951 m_data_model->getGroupDataViewItems();
1952
1953 for( std::pair<wxString, wxDataViewItem>& item : groupItems )
1954 {
1955 if( m_netsList->IsExpanded( item.second ) )
1956 cfg.expanded_rows.push_back( item.first );
1957 }
1958
1959 // Customer group rules
1960 cfg.custom_group_rules.clear();
1961
1962 for( const std::unique_ptr<EDA_COMBINED_MATCHER>& rule : m_custom_group_rules )
1963 cfg.custom_group_rules.push_back( rule->GetPattern() );
1964}
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:77
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:282
const NETINFO_LIST & GetNetInfo() const
Definition: board.h:853
LSET GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition: board.cpp:677
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
Definition: board.cpp:882
const std::set< int > & GetHighLightNetCodes() const
Definition: board.h:517
const std::vector< BOARD_CONNECTED_ITEM * > AllConnectedItems()
Definition: board.cpp:2437
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:2492
NETINFO_ITEM * FindNet(int aNetcode) const
Search for a net with the given netcode.
Definition: board.cpp:1803
const FOOTPRINTS & Footprints() const
Definition: board.h:323
unsigned GetNodesCount(int aNet=-1) const
Definition: board.cpp:1535
bool IsHighLightNetON() const
Definition: board.h:533
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition: board.cpp:564
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:794
void RemoveListener(BOARD_LISTENER *aListener)
Remove the specified listener.
Definition: board.cpp:2499
void Remove(BOARD_ITEM *aBoardItem, REMOVE_MODE aMode=REMOVE_MODE::NORMAL) override
Removes an item from the container.
Definition: board.cpp:1020
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Return a list of missing connections between components/tracks.
Definition: board.h:460
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:100
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition: eda_text.h:83
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:766
void UpdateAllItems(int aUpdateFlags)
Update all items in the view according to the given flags.
Definition: view.cpp:1513
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition: view.h:215
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:1523
LSEQ Seq(const PCB_LAYER_ID *aWishListSequence, unsigned aCount) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:418
A collection of nets and the parameters used to route or test these nets.
Definition: netclass.h:44
const wxString GetName() const
Definition: netclass.h:62
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:53
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:172
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
#define MAX_CU_LAYERS
Definition: layer_ids.h:142
bool IsCopperLayer(int aLayerId)
Tests whether a layer is a copper layer.
Definition: layer_ids.h:882
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
@ B_Cu
Definition: layer_ids.h:95
@ 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:1059
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.