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