static void class2gridRow( wxGrid* grid, int row, NETCLASSPTR nc )
{
    wxString msg;

    // label is netclass name
    grid->SetRowLabelValue( row, nc->GetName() );

    msg = StringFromValue( g_UserUnit, nc->GetClearance() );
    grid->SetCellValue( row, GRID_CLEARANCE, msg );

    msg = StringFromValue( g_UserUnit, nc->GetTrackWidth() );
    grid->SetCellValue( row, GRID_TRACKSIZE, msg );

    msg = StringFromValue( g_UserUnit, nc->GetViaDiameter() );
    grid->SetCellValue( row, GRID_VIASIZE, msg );

    msg = StringFromValue( g_UserUnit, nc->GetViaDrill() );
    grid->SetCellValue( row, GRID_VIADRILL, msg );

    msg = StringFromValue( g_UserUnit, nc->GetuViaDiameter() );
    grid->SetCellValue( row, GRID_uVIASIZE, msg );

    msg = StringFromValue( g_UserUnit, nc->GetuViaDrill() );
    grid->SetCellValue( row, GRID_uVIADRILL, msg );
}
    void ReadParam( wxConfigBase* aConfig ) const override
    {
        if( !m_Pt_param || !aConfig )
            return;

        wxString oldPath = aConfig->GetPath();

        m_Pt_param->Clear();

        for( int index = 0; ; ++index )
        {
            wxString    path = "";
            NETCLASSPTR netclass;
            wxString    netclassName;

            if( index == 0 )
                path = "Default";
            else
                path << index;

            aConfig->SetPath( oldPath );
            aConfig->SetPath( m_Ident );
            aConfig->SetPath( path );

            if( !aConfig->Read( NetclassNameKey, &netclassName ) )
                break;

            if( index == 0 )
                netclass = m_Pt_param->GetDefault();
            else
                netclass = std::make_shared<NETCLASS>( netclassName );

#define READ_MM( aKey, aDefault ) Millimeter2iu( aConfig->ReadDouble( aKey, aDefault ) )
            netclass->SetClearance( READ_MM( ClearanceKey, netclass->GetClearance() ) );
            netclass->SetTrackWidth( READ_MM( TrackWidthKey, netclass->GetTrackWidth() ) );
            netclass->SetViaDiameter( READ_MM( ViaDiameterKey, netclass->GetViaDiameter() ) );
            netclass->SetViaDrill( READ_MM( ViaDrillKey, netclass->GetViaDrill() ) );
            netclass->SetuViaDiameter( READ_MM( uViaDiameterKey, netclass->GetuViaDiameter() ) );
            netclass->SetuViaDrill( READ_MM( uViaDrillKey, netclass->GetuViaDrill() ) );
            netclass->SetDiffPairWidth( READ_MM( dPairWidthKey, netclass->GetDiffPairWidth() ) );
            netclass->SetDiffPairGap( READ_MM( dPairGapKey, netclass->GetDiffPairGap() ) );
            netclass->SetDiffPairViaGap( READ_MM( dPairViaGapKey, netclass->GetDiffPairViaGap() ) );

            if( index > 0 )
                m_Pt_param->Add( netclass );
        }

        aConfig->SetPath( oldPath );
    }
    void SaveParam( wxConfigBase* aConfig ) const override
    {
        if( !m_Pt_param || !aConfig )
            return;

        wxString                   oldPath = aConfig->GetPath();
        NETCLASSES::const_iterator nc = m_Pt_param->begin();

        for( unsigned index = 0; index <= m_Pt_param->GetCount(); ++index )
        {
            wxString    path = "";
            NETCLASSPTR netclass;

            if( index == 0 )
                path = "Default";
            else
                path << index;

            aConfig->SetPath( oldPath );
            aConfig->SetPath( m_Ident );
            aConfig->SetPath( path );

            if( index == 0 )
            {
                netclass = m_Pt_param->GetDefault();
            }
            else
            {
                netclass = nc->second;
                ++nc;
            }

            aConfig->Write( NetclassNameKey, netclass->GetName() );

#define WRITE_MM( aKey, aValue ) aConfig->Write( aKey, Iu2Millimeter( aValue ) )
            WRITE_MM( ClearanceKey,    netclass->GetClearance() );
            WRITE_MM( TrackWidthKey,   netclass->GetTrackWidth() );
            WRITE_MM( ViaDiameterKey,  netclass->GetViaDiameter() );
            WRITE_MM( ViaDrillKey,     netclass->GetViaDrill() );
            WRITE_MM( uViaDiameterKey, netclass->GetuViaDiameter() );
            WRITE_MM( uViaDrillKey,    netclass->GetuViaDrill() );
            WRITE_MM( dPairWidthKey,   netclass->GetDiffPairWidth() );
            WRITE_MM( dPairGapKey,     netclass->GetDiffPairGap() );
            WRITE_MM( dPairViaGapKey,  netclass->GetDiffPairViaGap() );
        }

        aConfig->SetPath( oldPath );
    }
bool DRC::doNetClass( NETCLASSPTR nc, wxString& msg )
{
    bool ret = true;

    const BOARD_DESIGN_SETTINGS& g = m_pcb->GetDesignSettings();

#define FmtVal( x ) GetChars( StringFromValue( g_UserUnit, x ) )

#if 0   // set to 1 when (if...) BOARD_DESIGN_SETTINGS has a m_MinClearance value
    if( nc->GetClearance() < g.m_MinClearance )
    {
        msg.Printf( _( "NETCLASS: '%s' has Clearance:%s which is less than global:%s" ),
                    GetChars( nc->GetName() ),
                    FmtVal( nc->GetClearance() ),
                    FmtVal( g.m_TrackClearance )
                    );

        addMarkerToPcb( fillMarker( DRCE_NETCLASS_CLEARANCE, msg, m_currentMarker ) );
        m_currentMarker = nullptr;
        ret = false;
    }
#endif

    if( nc->GetTrackWidth() < g.m_TrackMinWidth )
    {
        msg.Printf( _( "NETCLASS: '%s' has TrackWidth:%s which is less than global:%s" ),
                    GetChars( nc->GetName() ),
                    FmtVal( nc->GetTrackWidth() ),
                    FmtVal( g.m_TrackMinWidth )
                    );

        addMarkerToPcb( fillMarker( DRCE_NETCLASS_TRACKWIDTH, msg, m_currentMarker ) );
        m_currentMarker = nullptr;
        ret = false;
    }

    if( nc->GetViaDiameter() < g.m_ViasMinSize )
    {
        msg.Printf( _( "NETCLASS: '%s' has Via Dia:%s which is less than global:%s" ),
                    GetChars( nc->GetName() ),
                    FmtVal( nc->GetViaDiameter() ),
                    FmtVal( g.m_ViasMinSize )
                    );

        addMarkerToPcb( fillMarker( DRCE_NETCLASS_VIASIZE, msg, m_currentMarker ) );
        m_currentMarker = nullptr;
        ret = false;
    }

    if( nc->GetViaDrill() < g.m_ViasMinDrill )
    {
        msg.Printf( _( "NETCLASS: '%s' has Via Drill:%s which is less than global:%s" ),
                    GetChars( nc->GetName() ),
                    FmtVal( nc->GetViaDrill() ),
                    FmtVal( g.m_ViasMinDrill )
                    );

        addMarkerToPcb( fillMarker( DRCE_NETCLASS_VIADRILLSIZE, msg, m_currentMarker ) );
        m_currentMarker = nullptr;
        ret = false;
    }

    if( nc->GetuViaDiameter() < g.m_MicroViasMinSize )
    {
        msg.Printf( _( "NETCLASS: '%s' has uVia Dia:%s which is less than global:%s" ),
                    GetChars( nc->GetName() ),
                    FmtVal( nc->GetuViaDiameter() ),
                    FmtVal( g.m_MicroViasMinSize )
                    );

        addMarkerToPcb( fillMarker( DRCE_NETCLASS_uVIASIZE, msg, m_currentMarker ) );
        m_currentMarker = nullptr;
        ret = false;
    }

    if( nc->GetuViaDrill() < g.m_MicroViasMinDrill )
    {
        msg.Printf( _( "NETCLASS: '%s' has uVia Drill:%s which is less than global:%s" ),
                    GetChars( nc->GetName() ),
                    FmtVal( nc->GetuViaDrill() ),
                    FmtVal( g.m_MicroViasMinDrill )
                    );

        addMarkerToPcb( fillMarker( DRCE_NETCLASS_uVIADRILLSIZE, msg, m_currentMarker ) );
        m_currentMarker = nullptr;
        ret = false;
    }

    return ret;
}
int BOARD_DESIGN_SETTINGS::GetCurrentMicroViaSize()
{
    NETCLASSPTR netclass = m_NetClasses.Find( m_currentNetClassName );

    return netclass->GetuViaDiameter();
}