rewrite select net dialog

This commit is contained in:
Oleg Endo 2020-04-13 04:53:45 +09:00 committed by Jon Evans
parent 2f1d23312f
commit 137fe48d88
3 changed files with 693 additions and 121 deletions

View File

@ -1,6 +1,7 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2020 Oleg Endo <olegendo@gcc.gnu.org>
* Copyright (C) 2019 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 1992-2019 KiCad Developers, see AUTHORS.txt for contributors.
*
@ -37,6 +38,86 @@
#include <connectivity/connectivity_data.h>
#include <connectivity/connectivity_algo.h>
struct DIALOG_SELECT_NET_FROM_LIST::COLUMN_ID
{
int col_num;
wxString display_name;
operator int() const
{
return col_num;
}
};
#define def_col( c, num, name ) \
const DIALOG_SELECT_NET_FROM_LIST::COLUMN_ID DIALOG_SELECT_NET_FROM_LIST::c = { num, name }
def_col( COLUMN_NET, 0, _( "Net" ) );
def_col( COLUMN_NAME, 1, _( "Name" ) );
def_col( COLUMN_PAD_COUNT, 2, _( "Pad Count" ) );
def_col( COLUMN_VIA_COUNT, 3, _( "Via Count" ) );
def_col( COLUMN_BOARD_LENGTH, 4, _( "Board Length" ) );
def_col( COLUMN_CHIP_LENGTH, 5, _( "Die Length" ) );
def_col( COLUMN_TOTAL_LENGTH, 6, _( "Length" ) );
#undef def_col
struct DIALOG_SELECT_NET_FROM_LIST::LIST_ITEM
{
LIST_ITEM( NETINFO_ITEM* aNet ) : m_net( aNet )
{
}
NETINFO_ITEM* m_net;
int m_pad_count = 0;
int m_via_count = 0;
int m_board_wire_length = 0;
int m_chip_wire_length = 0;
int m_total_length = 0;
};
struct DIALOG_SELECT_NET_FROM_LIST::LIST_ITEM_NET_CMP_LESS
{
const LIST_ITEM* m_base_ptr;
LIST_ITEM_NET_CMP_LESS( const std::vector<LIST_ITEM>& container )
: m_base_ptr( container.data() )
{
}
bool operator()( unsigned int a, unsigned int b ) const
{
return m_base_ptr[a].m_net < m_base_ptr[b].m_net;
}
bool operator()( unsigned int a, NETINFO_ITEM* b ) const
{
return m_base_ptr[a].m_net < b;
}
bool operator()( NETINFO_ITEM* a, unsigned int b ) const
{
return a < m_base_ptr[b].m_net;
}
};
struct DIALOG_SELECT_NET_FROM_LIST::ROW_DESC
{
int row_num = -1;
decltype( DIALOG_SELECT_NET_FROM_LIST::m_list_items )::iterator by_row;
decltype( DIALOG_SELECT_NET_FROM_LIST::m_list_items_by_net )::iterator by_net;
bool valid() const
{
return row_num != -1;
}
explicit operator bool() const
{
return valid();
}
};
DIALOG_SELECT_NET_FROM_LIST::DIALOG_SELECT_NET_FROM_LIST( PCB_EDIT_FRAME* aParent )
: DIALOG_SELECT_NET_FROM_LIST_BASE( aParent ), m_frame( aParent )
@ -44,13 +125,20 @@ DIALOG_SELECT_NET_FROM_LIST::DIALOG_SELECT_NET_FROM_LIST( PCB_EDIT_FRAME* aParen
m_brd = aParent->GetBoard();
m_wasSelected = false;
m_netsList->AppendTextColumn( getListColumnHeaderNet(), wxDATAVIEW_CELL_INERT, 0, wxALIGN_LEFT, 0 );
m_netsList->AppendTextColumn( getListColumnHeaderName(), wxDATAVIEW_CELL_INERT, 0, wxALIGN_LEFT, 0 );
m_netsList->AppendTextColumn( getListColumnHeaderCount(), wxDATAVIEW_CELL_INERT, 0, wxALIGN_CENTER, 0 );
m_netsList->AppendTextColumn( getListColumnHeaderVias(), wxDATAVIEW_CELL_INERT, 0, wxALIGN_CENTER, 0 );
m_netsList->AppendTextColumn( getListColumnHeaderBoard(), wxDATAVIEW_CELL_INERT, 0, wxALIGN_CENTER, 0 );
m_netsList->AppendTextColumn( getListColumnHeaderDie(), wxDATAVIEW_CELL_INERT, 0, wxALIGN_CENTER, 0 );
m_netsList->AppendTextColumn( getListColumnHeaderLength(), wxDATAVIEW_CELL_INERT, 0, wxALIGN_CENTER, 0 );
m_netsList->AppendTextColumn(
COLUMN_NET.display_name, wxDATAVIEW_CELL_INERT, 0, wxALIGN_LEFT, 0 );
m_netsList->AppendTextColumn(
COLUMN_NAME.display_name, wxDATAVIEW_CELL_INERT, 0, wxALIGN_LEFT, 0 );
m_netsList->AppendTextColumn(
COLUMN_PAD_COUNT.display_name, wxDATAVIEW_CELL_INERT, 0, wxALIGN_CENTER, 0 );
m_netsList->AppendTextColumn(
COLUMN_VIA_COUNT.display_name, wxDATAVIEW_CELL_INERT, 0, wxALIGN_CENTER, 0 );
m_netsList->AppendTextColumn(
COLUMN_BOARD_LENGTH.display_name, wxDATAVIEW_CELL_INERT, 0, wxALIGN_CENTER, 0 );
m_netsList->AppendTextColumn(
COLUMN_CHIP_LENGTH.display_name, wxDATAVIEW_CELL_INERT, 0, wxALIGN_CENTER, 0 );
m_netsList->AppendTextColumn(
COLUMN_TOTAL_LENGTH.display_name, wxDATAVIEW_CELL_INERT, 0, wxALIGN_CENTER, 0 );
// The fact that we're a list should keep the control from reserving space for the
// expander buttons... but it doesn't. Fix by forcing the indent to 0.
@ -63,109 +151,553 @@ DIALOG_SELECT_NET_FROM_LIST::DIALOG_SELECT_NET_FROM_LIST( PCB_EDIT_FRAME* aParen
m_sdbSizerOK->SetDefault();
FinishDialogSettings();
#define connect_event( e, f ) \
m_frame->Connect( e, wxCommandEventHandler( DIALOG_SELECT_NET_FROM_LIST::f ), nullptr, this )
connect_event( wxEVT_CLOSE_WINDOW, onParentWindowClosed );
connect_event( UNITS_CHANGED, onUnitsChanged );
connect_event( BOARD_CHANGED, onBoardChanged );
#undef connect_event
if( m_brd != nullptr )
m_brd->AddListener( this );
}
void DIALOG_SELECT_NET_FROM_LIST::buildNetsList()
DIALOG_SELECT_NET_FROM_LIST::~DIALOG_SELECT_NET_FROM_LIST()
{
wxString netFilter = m_textCtrlFilter->GetValue();
EDA_PATTERN_MATCH_WILDCARD filter;
#define disconnect_event( e, f ) \
m_frame->Disconnect( e, wxCommandEventHandler( DIALOG_SELECT_NET_FROM_LIST::f ), nullptr, this )
constexpr KICAD_T types[] = { PCB_TRACE_T, PCB_VIA_T, PCB_PAD_T, EOT };
disconnect_event( wxEVT_CLOSE_WINDOW, onParentWindowClosed );
disconnect_event( UNITS_CHANGED, onUnitsChanged );
disconnect_event( BOARD_CHANGED, onBoardChanged );
filter.SetPattern( netFilter.MakeUpper() );
#undef disconnect_event
if( m_brd != nullptr )
m_brd->RemoveListener( this );
}
void DIALOG_SELECT_NET_FROM_LIST::onParentWindowClosed( wxCommandEvent& event )
{
event.Skip();
}
void DIALOG_SELECT_NET_FROM_LIST::onUnitsChanged( wxCommandEvent& event )
{
this->m_units = m_frame->GetUserUnits();
buildNetsList();
m_netsList->Refresh();
event.Skip();
}
void DIALOG_SELECT_NET_FROM_LIST::onBoardChanged( wxCommandEvent& event )
{
if( m_brd != nullptr )
m_brd->RemoveListener( this );
m_brd = m_frame->GetBoard();
if( m_brd != nullptr )
m_brd->AddListener( this );
m_wasSelected = false;
buildNetsList();
m_netsList->Refresh();
event.Skip();
}
bool DIALOG_SELECT_NET_FROM_LIST::netFilterMatches( NETINFO_ITEM* aNet ) const
{
// Note: the filtering is case insensitive.
if( m_netFilter.GetPattern().IsEmpty() )
return true;
return m_netFilter.Find( UnescapeString( aNet->GetNetname() ).Upper() )
!= EDA_PATTERN_NOT_FOUND;
}
struct NETCODE_CMP_LESS
{
bool operator()( const CN_ITEM* a, const CN_ITEM* b ) const
{
return a->Net() < b->Net();
}
bool operator()( const CN_ITEM* a, int b ) const
{
return a->Net() < b;
}
bool operator()( int a, const CN_ITEM* b ) const
{
return a < b->Net();
}
};
std::vector<CN_ITEM*> DIALOG_SELECT_NET_FROM_LIST::relevantConnectivityItems() const
{
// pre-filter the connectivity items and sort them by netcode.
// this avoids quadratic runtime when building the whole net list and
// calculating the total length for each net.
const auto type_bits = std::bitset<MAX_STRUCT_TYPE_ID>()
.set( PCB_TRACE_T )
.set( PCB_VIA_T )
.set( PCB_PAD_T );
std::vector<CN_ITEM*> cn_items;
cn_items.reserve( 1024 );
m_netsList->DeleteAllItems();
m_netsInitialNames.Clear();
auto connectivity = m_brd->GetConnectivity();
auto units = GetUserUnits();
// Populate the nets list with nets names matching the filters:
// Note: the filtering is case insensitive.
for( unsigned netcode = 0; netcode < m_brd->GetNetCount(); netcode++ )
for( auto& cn_item : connectivity->GetConnectivityAlgo()->ItemList() )
{
NETINFO_ITEM* net = m_brd->GetNetInfo().GetNetItem( netcode );
if( !netFilter.IsEmpty() )
{
wxString netname = UnescapeString( net->GetNetname() );
if( filter.Find( netname.MakeUpper() ) == EDA_PATTERN_NOT_FOUND )
continue;
if( cn_item->Valid() && type_bits[cn_item->Parent()->Type()] )
cn_items.push_back( cn_item );
}
unsigned nodes = m_brd->GetNodesCount( netcode );
std::sort( cn_items.begin(), cn_items.end(), NETCODE_CMP_LESS() );
if( !m_cbShowZeroPad->IsChecked() && nodes == 0 )
continue;
return cn_items;
}
wxVector<wxVariant> dataLine;
dataLine.push_back( wxVariant( wxString::Format( "%.3d", netcode ) ) );
dataLine.push_back( wxVariant( UnescapeString( net->GetNetname() ) ) );
m_netsInitialNames.Add( net->GetNetname() );
if( netcode )
DIALOG_SELECT_NET_FROM_LIST::ROW_DESC DIALOG_SELECT_NET_FROM_LIST::findRow( int aNetCode )
{
dataLine.push_back( wxVariant( wxString::Format( "%u", nodes ) ) );
return findRow( m_brd->FindNet( aNetCode ) );
}
int lenPadToDie = 0;
int len = 0;
int viaCount = 0;
for( auto item : connectivity->GetNetItems( netcode, types ) )
DIALOG_SELECT_NET_FROM_LIST::ROW_DESC DIALOG_SELECT_NET_FROM_LIST::findRow( NETINFO_ITEM* aNet )
{
auto i = std::lower_bound( m_list_items_by_net.begin(), m_list_items_by_net.end(), aNet,
LIST_ITEM_NET_CMP_LESS( m_list_items ) );
if( i != m_list_items_by_net.end() && m_list_items[*i].m_net == aNet )
return { static_cast<int>( *i ), m_list_items.begin() + *i, i };
else
return {};
}
void DIALOG_SELECT_NET_FROM_LIST::deleteRow( const ROW_DESC& aRow )
{
if( !aRow )
return;
m_netsList->DeleteItem( aRow.row_num );
m_list_items.erase( aRow.by_row );
std::iter_swap( aRow.by_net, m_list_items_by_net.end() - 1 );
m_list_items_by_net.pop_back();
std::sort( m_list_items_by_net.begin(), m_list_items_by_net.end(),
LIST_ITEM_NET_CMP_LESS( m_list_items ) );
}
void DIALOG_SELECT_NET_FROM_LIST::setValue(
const ROW_DESC& aRow, const COLUMN_ID& aCol, wxString aVal )
{
if( aRow )
m_netsList->SetValue( aVal, aRow.row_num, aCol.col_num );
}
wxString DIALOG_SELECT_NET_FROM_LIST::formatNetCode( const NETINFO_ITEM* aNet ) const
{
return wxString::Format( "%.3d", aNet->GetNet() );
}
wxString DIALOG_SELECT_NET_FROM_LIST::formatNetName( const NETINFO_ITEM* aNet ) const
{
return UnescapeString( aNet->GetNetname() );
}
wxString DIALOG_SELECT_NET_FROM_LIST::formatCount( unsigned int aValue ) const
{
return wxString::Format( "%u", aValue );
}
wxString DIALOG_SELECT_NET_FROM_LIST::formatLength( int aValue ) const
{
return MessageTextFromValue( GetUserUnits(), aValue );
}
void DIALOG_SELECT_NET_FROM_LIST::OnBoardItemAdded( BOARD& aBoard, BOARD_ITEM* aBoardItem )
{
if( NETINFO_ITEM* net = dyn_cast<NETINFO_ITEM*>( aBoardItem ) )
{
// a new net has been added to the board. add it to our list if it
// passes the netname filter test.
if( netFilterMatches( net ) )
{
m_list_items.emplace_back( net );
m_list_items_by_net.push_back( m_list_items.size() - 1 );
std::sort( m_list_items_by_net.begin(), m_list_items_by_net.end(),
LIST_ITEM_NET_CMP_LESS( m_list_items ) );
auto& new_i = m_list_items.back();
new_i.m_pad_count = m_brd->GetNodesCount( net->GetNet() );
wxVector<wxVariant> new_row( 7 );
new_row[COLUMN_NET] = formatNetCode( net );
new_row[COLUMN_NAME] = formatNetName( net );
new_row[COLUMN_PAD_COUNT] = formatCount( new_i.m_pad_count );
new_row[COLUMN_VIA_COUNT] = formatCount( new_i.m_via_count );
new_row[COLUMN_BOARD_LENGTH] = formatLength( new_i.m_board_wire_length );
new_row[COLUMN_CHIP_LENGTH] = formatLength( new_i.m_chip_wire_length );
new_row[COLUMN_TOTAL_LENGTH] = formatLength( new_i.m_total_length );
m_netsList->AppendItem( new_row );
}
return;
}
else if( auto* i = dyn_cast<BOARD_CONNECTED_ITEM*>( aBoardItem ) )
{
auto r = findRow( i->GetNet() );
if( r )
{
// try to handle frequent operations quickly.
if( auto* track = dynamic_cast<TRACK*>( i ) )
{
int len = track->GetLength();
r.by_row->m_board_wire_length += len;
r.by_row->m_total_length += len;
setValue( r, COLUMN_BOARD_LENGTH, formatLength( r.by_row->m_board_wire_length ) );
setValue( r, COLUMN_TOTAL_LENGTH, formatLength( r.by_row->m_total_length ) );
if( track->Type() == PCB_VIA_T )
{
r.by_row->m_via_count += 1;
setValue( r, COLUMN_VIA_COUNT, formatCount( r.by_row->m_via_count ) );
}
return;
}
}
// resort to generic slower net update otherwise.
updateNet( i->GetNet() );
}
}
void DIALOG_SELECT_NET_FROM_LIST::OnBoardItemRemoved( BOARD& aBoard, BOARD_ITEM* aBoardItem )
{
if( auto* net = dyn_cast<NETINFO_ITEM*>( aBoardItem ) )
{
deleteRow( findRow( net ) );
return;
}
else if( auto* mod = dyn_cast<MODULE*>( aBoardItem ) )
{
for( const D_PAD* pad : mod->Pads() )
{
auto r = findRow( pad->GetNet() );
if( r )
{
r.by_row->m_pad_count -= 1;
if( r.by_row->m_pad_count == 0 && !m_cbShowZeroPad->IsChecked() )
deleteRow( r );
else
setValue( r, COLUMN_PAD_COUNT, formatCount( r.by_row->m_pad_count ) );
}
}
}
else if( auto* i = dyn_cast<BOARD_CONNECTED_ITEM*>( aBoardItem ) )
{
auto r = findRow( i->GetNet() );
if( r )
{
// try to handle frequent operations quickly.
if( auto* track = dynamic_cast<TRACK*>( i ) )
{
int len = track->GetLength();
r.by_row->m_board_wire_length -= len;
r.by_row->m_total_length -= len;
setValue( r, COLUMN_BOARD_LENGTH, formatLength( r.by_row->m_board_wire_length ) );
setValue( r, COLUMN_TOTAL_LENGTH, formatLength( r.by_row->m_total_length ) );
if( track->Type() == PCB_VIA_T )
{
r.by_row->m_via_count -= 1;
setValue( r, COLUMN_VIA_COUNT, formatCount( r.by_row->m_via_count ) );
}
return;
}
// resort to generic slower net update otherwise.
updateNet( i->GetNet() );
}
}
}
void DIALOG_SELECT_NET_FROM_LIST::OnBoardItemChanged( BOARD& aBoard, BOARD_ITEM* aBoardItem )
{
if( dynamic_cast<BOARD_CONNECTED_ITEM*>( aBoardItem ) != nullptr
|| dynamic_cast<MODULE*>( aBoardItem ) != nullptr )
{
buildNetsList();
m_netsList->Refresh();
}
}
void DIALOG_SELECT_NET_FROM_LIST::OnBoardHighlightNetChanged( BOARD& aBoard )
{
if( !m_brd->IsHighLightNetON() )
m_netsList->UnselectAll();
else
HighlightNet( m_brd->FindNet( m_brd->GetHighLightNetCode() ) );
}
void DIALOG_SELECT_NET_FROM_LIST::OnBoardNetSettingsChanged( BOARD& aBoard )
{
buildNetsList();
m_netsList->Refresh();
}
void DIALOG_SELECT_NET_FROM_LIST::updateNet( NETINFO_ITEM* aNet )
{
// something for the specified net has changed, update that row.
if( !netFilterMatches( aNet ) )
return;
// if the net had no pads before, it might not be in the displayed list yet.
// if it had pads and now doesn't anymore, we might need to remove it from the list.
auto cur_net_row = findRow( aNet );
const unsigned int node_count = m_brd->GetNodesCount( aNet->GetNet() );
if( node_count == 0 && !m_cbShowZeroPad->IsChecked() )
{
deleteRow( cur_net_row );
return;
}
auto all_cn_items = relevantConnectivityItems();
LIST_ITEM list_item( aNet );
list_item.m_pad_count = node_count;
const auto cn_items = std::equal_range(
all_cn_items.begin(), all_cn_items.end(), aNet->GetNet(), NETCODE_CMP_LESS() );
for( auto i = cn_items.first; i != cn_items.second; ++i )
{
auto item = ( *i )->Parent();
if( item->Type() == PCB_PAD_T )
list_item.m_chip_wire_length += static_cast<D_PAD*>( item )->GetPadToDieLength();
else if( auto* track = dynamic_cast<TRACK*>( item ) )
{
D_PAD *pad = dyn_cast<D_PAD*>( item );
lenPadToDie += pad->GetPadToDieLength();
}
else if( item->Type() == PCB_TRACE_T )
{
TRACK *track = dyn_cast<TRACK*>( item );
len += track->GetLength();
}
else if( item->Type() == PCB_VIA_T )
{
viaCount++;
list_item.m_board_wire_length += track->GetLength();
if( item->Type() == PCB_VIA_T )
list_item.m_via_count += 1;
}
}
dataLine.push_back( wxVariant( wxString::Format( "%u", viaCount ) ) );
dataLine.push_back( wxVariant( MessageTextFromValue( units, len ) ) );
dataLine.push_back( wxVariant( MessageTextFromValue( units, lenPadToDie ) ) );
dataLine.push_back( wxVariant( MessageTextFromValue( units, len + lenPadToDie ) ) );
}
else // For the net 0 (unconnected pads), the pad count is not known
list_item.m_total_length = list_item.m_board_wire_length + list_item.m_chip_wire_length;
if( !cur_net_row )
{
dataLine.push_back( wxVariant( "---" ) );
dataLine.push_back( wxVariant( "---" ) ); // vias
dataLine.push_back( wxVariant( "---" ) ); // board
dataLine.push_back( wxVariant( "---" ) ); // die
dataLine.push_back( wxVariant( "---" ) ); // length
m_list_items.push_back( list_item );
m_list_items_by_net.push_back( m_list_items.size() - 1 );
std::sort( m_list_items_by_net.begin(), m_list_items_by_net.end(),
LIST_ITEM_NET_CMP_LESS( m_list_items ) );
wxVector<wxVariant> new_row( 7 );
new_row[COLUMN_NET] = formatNetCode( aNet );
new_row[COLUMN_NAME] = formatNetName( aNet );
new_row[COLUMN_PAD_COUNT] = formatCount( list_item.m_pad_count );
new_row[COLUMN_VIA_COUNT] = formatCount( list_item.m_via_count );
new_row[COLUMN_BOARD_LENGTH] = formatLength( list_item.m_board_wire_length );
new_row[COLUMN_CHIP_LENGTH] = formatLength( list_item.m_chip_wire_length );
new_row[COLUMN_TOTAL_LENGTH] = formatLength( list_item.m_total_length );
m_netsList->AppendItem( new_row );
}
else
{
*cur_net_row.by_row = list_item;
setValue( cur_net_row, COLUMN_PAD_COUNT, formatCount( list_item.m_pad_count ) );
setValue( cur_net_row, COLUMN_VIA_COUNT, formatCount( list_item.m_via_count ) );
setValue( cur_net_row, COLUMN_BOARD_LENGTH, formatLength( list_item.m_board_wire_length ) );
setValue( cur_net_row, COLUMN_CHIP_LENGTH, formatLength( list_item.m_chip_wire_length ) );
setValue( cur_net_row, COLUMN_TOTAL_LENGTH, formatLength( list_item.m_total_length ) );
}
}
void DIALOG_SELECT_NET_FROM_LIST::buildNetsList()
{
// when rebuilding the netlist, try to keep the row selection
const int prev_selected_row = m_netsList->GetSelectedRow();
const int prev_selected_netcode =
prev_selected_row >= 0 ? m_list_items[prev_selected_row].m_net->GetNet() : -1;
m_netsList->DeleteAllItems();
m_list_items.clear();
std::vector<CN_ITEM*> prefiltered_cn_items = relevantConnectivityItems();
// collect all nets which pass the filter string.
struct NET_INFO
{
int netcode;
NETINFO_ITEM* net;
unsigned int pad_count;
};
struct NET_INFO_CMP_LESS
{
bool operator()( const NET_INFO& a, const NET_INFO& b ) const
{
return a.netcode < b.netcode;
}
bool operator()( const NET_INFO& a, int b ) const
{
return a.netcode < b;
}
bool operator()( int a, const NET_INFO& b ) const
{
return a < b.netcode;
}
};
std::vector<NET_INFO> nets;
nets.reserve( m_brd->GetNetInfo().NetsByNetcode().size() );
for( auto&& ni : m_brd->GetNetInfo().NetsByNetcode() )
{
if( netFilterMatches( ni.second ) )
nets.emplace_back( NET_INFO{ ni.first, ni.second, 0 } );
}
// count the pads for each net. since the nets are sorted by netcode
// this way around is faster than using counting pads for each net.
for( auto&& mod : m_brd->Modules() )
{
for( auto&& pad : mod->Pads() )
{
auto i = std::lower_bound(
nets.begin(), nets.end(), pad->GetNetCode(), NET_INFO_CMP_LESS() );
if( i != nets.end() && i->netcode == pad->GetNetCode() )
i->pad_count += 1;
}
}
for( auto&& ni : nets )
{
if( !m_cbShowZeroPad->IsChecked() && ni.pad_count == 0 )
continue;
m_list_items.emplace_back( ni.net );
auto& list_item = m_list_items.back();
const auto cn_items = std::equal_range( prefiltered_cn_items.begin(),
prefiltered_cn_items.end(), ni.netcode, NETCODE_CMP_LESS() );
for( auto i = cn_items.first; i != cn_items.second; ++i )
{
auto item = ( *i )->Parent();
if( item->Type() == PCB_PAD_T )
list_item.m_chip_wire_length += static_cast<D_PAD*>( item )->GetPadToDieLength();
else if( auto* track = dynamic_cast<TRACK*>( item ) )
{
list_item.m_board_wire_length += track->GetLength();
if( track->Type() == PCB_VIA_T )
list_item.m_via_count += 1;
}
}
list_item.m_pad_count = ni.pad_count;
list_item.m_total_length = list_item.m_board_wire_length + list_item.m_chip_wire_length;
}
wxVector<wxVariant> dataLine;
dataLine.resize( 7 );
for( auto& i : m_list_items )
{
dataLine[COLUMN_NET] = formatNetCode( i.m_net );
dataLine[COLUMN_NAME] = formatNetName( i.m_net );
dataLine[COLUMN_PAD_COUNT] = formatCount( i.m_pad_count );
dataLine[COLUMN_VIA_COUNT] = formatCount( i.m_via_count );
dataLine[COLUMN_BOARD_LENGTH] = formatLength( i.m_board_wire_length );
dataLine[COLUMN_CHIP_LENGTH] = formatLength( i.m_chip_wire_length );
dataLine[COLUMN_TOTAL_LENGTH] = formatLength( i.m_total_length );
m_netsList->AppendItem( dataLine );
}
m_list_items_by_net.clear();
m_list_items_by_net.reserve( m_list_items.size() );
for( unsigned int i = 0; i < m_list_items.size(); ++i )
m_list_items_by_net.push_back( i );
std::sort( m_list_items_by_net.begin(), m_list_items_by_net.end(),
LIST_ITEM_NET_CMP_LESS( m_list_items ) );
if( prev_selected_netcode == -1 )
m_wasSelected = false;
else
{
auto r = findRow( prev_selected_netcode );
if( r )
{
m_selection = r.by_row->m_net->GetNetname();
m_wasSelected = true;
auto i = m_netsList->RowToItem( r.row_num );
m_netsList->Select( i );
m_netsList->EnsureVisible( i );
}
}
}
void DIALOG_SELECT_NET_FROM_LIST::HighlightNet( const wxString& aNetName )
void DIALOG_SELECT_NET_FROM_LIST::HighlightNet( NETINFO_ITEM* aNet )
{
int netCode = -1;
if( !aNetName.IsEmpty() )
const auto r = findRow( aNet );
if( r )
{
NETINFO_ITEM* net = m_brd->FindNet( aNetName );
if( net )
netCode = net->GetNet();
auto i = m_netsList->RowToItem( r.row_num );
m_netsList->Select( i );
m_netsList->EnsureVisible( i );
}
else
m_netsList->UnselectAll();
}
void DIALOG_SELECT_NET_FROM_LIST::highlightNetOnBoard( NETINFO_ITEM* aNet ) const
{
int netCode = aNet != nullptr ? aNet->GetNet() : -1;
KIGFX::RENDER_SETTINGS *render = m_frame->GetCanvas()->GetView()->GetPainter()->GetSettings();
render->SetHighlight( netCode >= 0, netCode );
@ -175,13 +707,9 @@ void DIALOG_SELECT_NET_FROM_LIST::HighlightNet( const wxString& aNetName )
}
DIALOG_SELECT_NET_FROM_LIST::~DIALOG_SELECT_NET_FROM_LIST()
{
}
void DIALOG_SELECT_NET_FROM_LIST::onFilterChange( wxCommandEvent& event )
{
m_netFilter.SetPattern( m_textCtrlFilter->GetValue().Upper() );
buildNetsList();
}
@ -190,21 +718,19 @@ void DIALOG_SELECT_NET_FROM_LIST::onSelChanged( wxDataViewEvent& )
{
int selected_row = m_netsList->GetSelectedRow();
if( selected_row >= 0 )
if( selected_row >= 0 && selected_row < static_cast<int>( m_list_items.size() ) )
{
// We no not use the displayed net name returnded by
// m_netsList->GetTextValue( selected_row, 1 ); because we need the initial escaped net name
m_selection = m_netsInitialNames[ selected_row ];
m_wasSelected = true;
auto* net = m_list_items[selected_row].m_net;
HighlightNet( m_selection );
m_selection = net->GetNetname();
m_wasSelected = true;
highlightNetOnBoard( net );
return;
}
else
{
HighlightNet( "" );
highlightNetOnBoard( nullptr );
m_wasSelected = false;
}
}
void DIALOG_SELECT_NET_FROM_LIST::adjustListColumns()
@ -221,12 +747,12 @@ void DIALOG_SELECT_NET_FROM_LIST::adjustListColumns()
wxClientDC dc( GetParent() );
int h, minw, minw_col0;
dc.GetTextExtent( getListColumnHeaderNet()+"MM", &w0, &h );
dc.GetTextExtent( getListColumnHeaderCount()+"MM", &w2, &h );
dc.GetTextExtent( getListColumnHeaderVias()+"MM", &w3, &h );
dc.GetTextExtent( getListColumnHeaderBoard()+"MM", &w4, &h );
dc.GetTextExtent( getListColumnHeaderDie()+"MM", &w5, &h );
dc.GetTextExtent( getListColumnHeaderLength()+"MM", &w6, &h );
dc.GetTextExtent( COLUMN_NET.display_name + "MM", &w0, &h );
dc.GetTextExtent( COLUMN_PAD_COUNT.display_name + "MM", &w2, &h );
dc.GetTextExtent( COLUMN_VIA_COUNT.display_name + "MM", &w3, &h );
dc.GetTextExtent( COLUMN_BOARD_LENGTH.display_name + "MM", &w4, &h );
dc.GetTextExtent( COLUMN_CHIP_LENGTH.display_name + "MM", &w5, &h );
dc.GetTextExtent( COLUMN_TOTAL_LENGTH.display_name + "MM", &w6, &h );
dc.GetTextExtent( "M00000,000 mmM", &minw, &h );
dc.GetTextExtent( "M00000M", &minw_col0, &h );
@ -267,7 +793,7 @@ void DIALOG_SELECT_NET_FROM_LIST::onListSize( wxSizeEvent& aEvent )
}
bool DIALOG_SELECT_NET_FROM_LIST::GetNetName( wxString& aName )
bool DIALOG_SELECT_NET_FROM_LIST::GetNetName( wxString& aName ) const
{
aName = m_selection;
return m_wasSelected;
@ -300,14 +826,13 @@ void DIALOG_SELECT_NET_FROM_LIST::onReport( wxCommandEvent& aEvent )
// Print list of nets:
for( int row = 1; row < rows; row++ )
{
txt.Printf( "%s;\"%s\";%s;%s;%s;%s;%s;",
m_netsList->GetTextValue( row, 0 ), // net id
m_netsList->GetTextValue( row, 1 ), // net name
m_netsList->GetTextValue( row, 2 ), // Pad count
m_netsList->GetTextValue( row, 3 ), // Via count
m_netsList->GetTextValue( row, 4 ), // Board length
m_netsList->GetTextValue( row, 5 ), // Die length
m_netsList->GetTextValue( row, 6 ) ); // net length
txt.Printf( "%s;\"%s\";%s;%s;%s;%s;%s;", m_netsList->GetTextValue( row, COLUMN_NET ),
m_netsList->GetTextValue( row, COLUMN_NAME ),
m_netsList->GetTextValue( row, COLUMN_PAD_COUNT ),
m_netsList->GetTextValue( row, COLUMN_VIA_COUNT ),
m_netsList->GetTextValue( row, COLUMN_BOARD_LENGTH ),
m_netsList->GetTextValue( row, COLUMN_CHIP_LENGTH ),
m_netsList->GetTextValue( row, COLUMN_TOTAL_LENGTH ) );
f.AddLine( txt );
}

View File

@ -1,6 +1,7 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2020 Oleg Endo <olegendo@gcc.gnu.org>
* Copyright (C) 2019 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 1992-2019 KiCad Developers, see AUTHORS.txt for contributors.
*
@ -25,45 +26,91 @@
#pragma once
#include <dialog_select_net_from_list_base.h>
#include <eda_pattern_match.h>
class PCB_EDIT_FRAME;
class NETINFO_ITEM;
class BOARD;
class CN_ITEM;
class DIALOG_SELECT_NET_FROM_LIST : public DIALOG_SELECT_NET_FROM_LIST_BASE
class DIALOG_SELECT_NET_FROM_LIST : public DIALOG_SELECT_NET_FROM_LIST_BASE, public BOARD_LISTENER
{
private:
public:
DIALOG_SELECT_NET_FROM_LIST( PCB_EDIT_FRAME* aParent );
~DIALOG_SELECT_NET_FROM_LIST();
// returns true if a net was selected, and its name in aName
bool GetNetName( wxString& aName );
bool GetNetName( wxString& aName ) const;
/**
* Visually highlights a net.
* @param aNetName is the name of net to be highlighted. An empty string will unhighlight
* Visually highlights a net in the list view.
* @param aNet is the net item to be highlighted. Nullptr will unhighlight
* any currently highlighted net.
*/
void HighlightNet( const wxString& aNetName );
void HighlightNet( NETINFO_ITEM* aNet );
virtual void OnBoardItemAdded( BOARD& aBoard, BOARD_ITEM* aBoardItem ) override;
virtual void OnBoardItemRemoved( BOARD& aBoard, BOARD_ITEM* aBoardItem ) override;
virtual void OnBoardNetSettingsChanged( BOARD& aBoard ) override;
virtual void OnBoardItemChanged( BOARD& aBoard, BOARD_ITEM* aBoardItem ) override;
virtual void OnBoardHighlightNetChanged( BOARD& aBoard ) override;
private:
struct COLUMN_ID;
static const COLUMN_ID COLUMN_NET;
static const COLUMN_ID COLUMN_NAME;
static const COLUMN_ID COLUMN_PAD_COUNT;
static const COLUMN_ID COLUMN_VIA_COUNT;
static const COLUMN_ID COLUMN_BOARD_LENGTH;
static const COLUMN_ID COLUMN_CHIP_LENGTH;
static const COLUMN_ID COLUMN_TOTAL_LENGTH;
struct ROW_DESC;
ROW_DESC findRow( NETINFO_ITEM* aNet );
ROW_DESC findRow( int aNetCode );
void deleteRow( const ROW_DESC& aRow );
void setValue( const ROW_DESC& aRow, const COLUMN_ID& aCol, wxString aVal );
wxString formatNetCode( const NETINFO_ITEM* aNet ) const;
wxString formatNetName( const NETINFO_ITEM* aNet ) const;
wxString formatCount( unsigned int aValue ) const;
wxString formatLength( int aValue ) const;
std::vector<CN_ITEM*> relevantConnectivityItems() const;
bool netFilterMatches( NETINFO_ITEM* aNet ) const;
void updateNet( NETINFO_ITEM* aNet );
void highlightNetOnBoard( NETINFO_ITEM* aNet ) const;
void onSelChanged( wxDataViewEvent& event ) override;
void onFilterChange( wxCommandEvent& event ) override;
void onListSize( wxSizeEvent& event ) override;
void onReport( wxCommandEvent& event ) override;
void buildNetsList();
wxString getListColumnHeaderNet() { return _( "Net" ); };
wxString getListColumnHeaderName() { return _( "Name" ); };
wxString getListColumnHeaderCount() { return _( "Pad Count" ); };
wxString getListColumnHeaderVias() { return _( "Via Count" ); };
wxString getListColumnHeaderBoard() { return _( "Board Length" ); };
wxString getListColumnHeaderDie() { return _( "Die Length" ); };
wxString getListColumnHeaderLength() { return _( "Length" ); };
void adjustListColumns();
wxArrayString m_netsInitialNames; // The list of escaped netnames (original names)
void onParentWindowClosed( wxCommandEvent& event );
void onUnitsChanged( wxCommandEvent& event );
void onBoardChanged( wxCommandEvent& event );
// in addition to the displayed list data, we also keep some auxiliary
// data for each list item in order to speed up update of the displayed list.
struct LIST_ITEM;
struct LIST_ITEM_NET_CMP_LESS;
// primary vector, sorted by rows
std::vector<LIST_ITEM> m_list_items;
// we can't keep pointers to the elements in the primary vector because
// the underlyng storage might change when elements are added or removed.
// keep indices instead and look the them up in m_list_items.
std::vector<unsigned int> m_list_items_by_net;
EDA_PATTERN_MATCH_WILDCARD m_netFilter;
wxString m_selection;
bool m_wasSelected;
BOARD* m_brd;

View File

@ -451,7 +451,7 @@ int PCB_INSPECTION_TOOL::ListNets( const TOOL_EVENT& aEvent )
if( dlg.ShowModal() == wxID_CANCEL )
{
// Clear highlight
dlg.HighlightNet( "" );
dlg.HighlightNet( nullptr );
}
return 0;