rewrite select net dialog
This commit is contained in:
parent
2f1d23312f
commit
137fe48d88
|
@ -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,111 +151,555 @@ 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( cn_item->Valid() && type_bits[cn_item->Parent()->Type()] )
|
||||
cn_items.push_back( cn_item );
|
||||
}
|
||||
|
||||
if( !netFilter.IsEmpty() )
|
||||
std::sort( cn_items.begin(), cn_items.end(), NETCODE_CMP_LESS() );
|
||||
|
||||
return cn_items;
|
||||
}
|
||||
|
||||
DIALOG_SELECT_NET_FROM_LIST::ROW_DESC DIALOG_SELECT_NET_FROM_LIST::findRow( int aNetCode )
|
||||
{
|
||||
return findRow( m_brd->FindNet( aNetCode ) );
|
||||
}
|
||||
|
||||
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 ) )
|
||||
{
|
||||
wxString netname = UnescapeString( net->GetNetname() );
|
||||
m_list_items.emplace_back( net );
|
||||
m_list_items_by_net.push_back( m_list_items.size() - 1 );
|
||||
|
||||
if( filter.Find( netname.MakeUpper() ) == EDA_PATTERN_NOT_FOUND )
|
||||
continue;
|
||||
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 );
|
||||
}
|
||||
|
||||
unsigned nodes = m_brd->GetNodesCount( netcode );
|
||||
|
||||
if( !m_cbShowZeroPad->IsChecked() && nodes == 0 )
|
||||
continue;
|
||||
|
||||
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 )
|
||||
return;
|
||||
}
|
||||
else if( auto* i = dyn_cast<BOARD_CONNECTED_ITEM*>( aBoardItem ) )
|
||||
{
|
||||
auto r = findRow( i->GetNet() );
|
||||
if( r )
|
||||
{
|
||||
dataLine.push_back( wxVariant( wxString::Format( "%u", nodes ) ) );
|
||||
|
||||
int lenPadToDie = 0;
|
||||
int len = 0;
|
||||
int viaCount = 0;
|
||||
|
||||
for( auto item : connectivity->GetNetItems( netcode, types ) )
|
||||
// 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;
|
||||
|
||||
if( item->Type() == PCB_PAD_T )
|
||||
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 )
|
||||
{
|
||||
D_PAD *pad = dyn_cast<D_PAD*>( item );
|
||||
lenPadToDie += pad->GetPadToDieLength();
|
||||
r.by_row->m_via_count += 1;
|
||||
setValue( r, COLUMN_VIA_COUNT, formatCount( r.by_row->m_via_count ) );
|
||||
}
|
||||
else if( item->Type() == PCB_TRACE_T )
|
||||
|
||||
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 )
|
||||
{
|
||||
TRACK *track = dyn_cast<TRACK*>( item );
|
||||
len += track->GetLength();
|
||||
}
|
||||
else if( item->Type() == PCB_VIA_T )
|
||||
{
|
||||
viaCount++;
|
||||
r.by_row->m_via_count -= 1;
|
||||
setValue( r, COLUMN_VIA_COUNT, formatCount( r.by_row->m_via_count ) );
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
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 ) ) );
|
||||
// resort to generic slower net update otherwise.
|
||||
updateNet( i->GetNet() );
|
||||
}
|
||||
else // For the net 0 (unconnected pads), the pad count is not known
|
||||
}
|
||||
}
|
||||
|
||||
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 ) )
|
||||
{
|
||||
dataLine.push_back( wxVariant( "---" ) );
|
||||
dataLine.push_back( wxVariant( "---" ) ); // vias
|
||||
dataLine.push_back( wxVariant( "---" ) ); // board
|
||||
dataLine.push_back( wxVariant( "---" ) ); // die
|
||||
dataLine.push_back( wxVariant( "---" ) ); // length
|
||||
list_item.m_board_wire_length += track->GetLength();
|
||||
|
||||
if( item->Type() == PCB_VIA_T )
|
||||
list_item.m_via_count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
list_item.m_total_length = list_item.m_board_wire_length + list_item.m_chip_wire_length;
|
||||
|
||||
if( !cur_net_row )
|
||||
{
|
||||
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_wasSelected = false;
|
||||
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();
|
||||
}
|
||||
|
||||
KIGFX::RENDER_SETTINGS* render = m_frame->GetCanvas()->GetView()->GetPainter()->GetSettings();
|
||||
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 );
|
||||
|
||||
m_frame->GetCanvas()->GetView()->UpdateAllLayersColor();
|
||||
|
@ -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,20 +718,18 @@ 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 );
|
||||
}
|
||||
else
|
||||
{
|
||||
HighlightNet( "" );
|
||||
m_wasSelected = false;
|
||||
m_selection = net->GetNetname();
|
||||
m_wasSelected = true;
|
||||
highlightNetOnBoard( net );
|
||||
return;
|
||||
}
|
||||
|
||||
highlightNetOnBoard( nullptr );
|
||||
m_wasSelected = false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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,16 +826,15 @@ 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 );
|
||||
f.AddLine( txt );
|
||||
}
|
||||
|
||||
f.Write();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue