int ROUTER_TOOL::DpDimensionsDialog( const TOOL_EVENT& aEvent )
{
    PNS::SIZES_SETTINGS sizes = m_router->Sizes();
    DIALOG_PNS_DIFF_PAIR_DIMENSIONS settingsDlg( frame(), sizes );

    if( settingsDlg.ShowModal() == wxID_OK )
    {
        m_router->UpdateSizes( sizes );
        m_savedSizes = sizes;

        BOARD_DESIGN_SETTINGS& bds = frame()->GetBoard()->GetDesignSettings();
        bds.SetCustomDiffPairWidth( sizes.DiffPairWidth() );
        bds.SetCustomDiffPairGap( sizes.DiffPairGap() );
        bds.SetCustomDiffPairViaGap( sizes.DiffPairViaGap() );
    }

    return 0;
}
int ROUTER_TOOL::onViaCommand( const TOOL_EVENT& aEvent )
{
    const int actViaFlags = aEvent.Parameter<intptr_t>();

    VIATYPE_T viaType = getViaTypeFromFlags( actViaFlags );
    const bool selectLayer = actViaFlags & VIA_ACTION_FLAGS::SELECT_LAYER;

    BOARD_DESIGN_SETTINGS& bds = board()->GetDesignSettings();

    const int layerCount = bds.GetCopperLayerCount();
    int currentLayer = m_router->GetCurrentLayer();
    PCB_LAYER_ID pairTop = frame()->GetScreen()->m_Route_Layer_TOP;
    PCB_LAYER_ID pairBottom = frame()->GetScreen()->m_Route_Layer_BOTTOM;

    PNS::SIZES_SETTINGS sizes = m_router->Sizes();

    // ask the user for a target layer
    PCB_LAYER_ID targetLayer = UNDEFINED_LAYER;

    if( selectLayer )
    {
        wxPoint dlgPosition = wxGetMousePosition();

        targetLayer = frame()->SelectLayer( static_cast<PCB_LAYER_ID>( currentLayer ),
                LSET::AllNonCuMask(), dlgPosition );
    }

    // fixme: P&S supports more than one fixed layer pair. Update the dialog?
    sizes.ClearLayerPairs();

    if( !m_router->IsPlacingVia() )
    {
        // Cannot place microvias or blind vias if not allowed (obvious)
        if( ( viaType == VIA_BLIND_BURIED ) && ( !bds.m_BlindBuriedViaAllowed ) )
        {
            DisplayError( frame(), _( "Blind/buried vias have to be enabled in the design settings." ) );
            return false;
        }

        if( ( viaType == VIA_MICROVIA ) && ( !bds.m_MicroViasAllowed ) )
        {
            DisplayError( frame(), _( "Microvias have to be enabled in the design settings." ) );
            return false;
        }

        // Can only place through vias on 2-layer boards
        if( ( viaType != VIA_THROUGH ) && ( layerCount <= 2 ) )
        {
            DisplayError( frame(), _( "Only through vias are allowed on 2 layer boards." ) );
            return false;
        }

        // Can only place microvias if we're on an outer layer, or directly adjacent to one
        if( ( viaType == VIA_MICROVIA ) && ( currentLayer > In1_Cu ) && ( currentLayer < layerCount - 2 ) )
        {
            DisplayError( frame(), _( "Microvias can be placed only between the outer layers " \
                                      "(F.Cu/B.Cu) and the ones directly adjacent to them." ) );
            return false;
        }
    }

    // Convert blind/buried via to a through hole one, if it goes through all layers
    if( viaType == VIA_BLIND_BURIED && ( ( currentLayer == B_Cu ) || ( currentLayer == F_Cu ) )
                                    && ( ( pairTop == B_Cu && pairBottom == F_Cu )
                                      || ( pairTop == F_Cu && pairBottom == B_Cu ) ) )
    {
        viaType = VIA_THROUGH;
    }

    switch( viaType )
    {
    case VIA_THROUGH:
        sizes.SetViaDiameter( bds.GetCurrentViaSize() );
        sizes.SetViaDrill( bds.GetCurrentViaDrill() );

        if( targetLayer != UNDEFINED_LAYER )
        {
            // go from the current layer to the chosen layer
            sizes.AddLayerPair( currentLayer, targetLayer );
        }
        else
        {
            // use the default layer pair
            sizes.AddLayerPair( pairTop, pairBottom );
        }
        break;

    case VIA_MICROVIA:
        sizes.SetViaDiameter( bds.GetCurrentMicroViaSize() );
        sizes.SetViaDrill( bds.GetCurrentMicroViaDrill() );

        wxASSERT_MSG( !selectLayer, "Unexpected select layer for microvia (microvia layers are implicit)" );

        if( currentLayer == F_Cu || currentLayer == In1_Cu )
        {
            // front-side microvia
            sizes.AddLayerPair( F_Cu, In1_Cu );
        }
        else if( currentLayer == B_Cu || currentLayer == layerCount - 2 )
        {
            // back-side microvia
            sizes.AddLayerPair( B_Cu, layerCount - 2 );
        }
        else
        {
            wxASSERT_MSG( false, "Invalid layer pair for microvia (must be on or adjacent to an outer layer)" );
        }
        break;

    case VIA_BLIND_BURIED:
        sizes.SetViaDiameter( bds.GetCurrentViaSize() );
        sizes.SetViaDrill( bds.GetCurrentViaDrill() );

        if( targetLayer != UNDEFINED_LAYER )
        {
            // go directly to the user specified layer
            sizes.AddLayerPair( currentLayer, targetLayer );
        }
        else
        {
            if( currentLayer == pairTop || currentLayer == pairBottom )
            {
                // the current layer is on the defined layer pair,
                // swap to the other side
                sizes.AddLayerPair( pairTop, pairBottom );
            }
            else
            {
                // the current layer is not part of the current layer pair,
                // so fallback and swap to the top layer of the pair by default
                sizes.AddLayerPair( pairTop, currentLayer );
            }
        }
        break;

    default:
        wxASSERT( false );
        break;
    }

    sizes.SetViaType( viaType );

    m_router->UpdateSizes( sizes );
    m_router->ToggleViaPlacement();

    if( m_router->RoutingInProgress() )
        updateEndItem( aEvent );
    else
        updateStartItem( aEvent );

    m_router->Move( m_endSnapPoint, m_endItem );        // refresh

    return 0;
}
bool ROUTER_TOOL::onViaCommand( TOOL_EVENT& aEvent, VIATYPE_T aType )
{
    BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();

    const int layerCount = bds.GetCopperLayerCount();
    int currentLayer = m_router->GetCurrentLayer();
    LAYER_ID pairTop = m_frame->GetScreen()->m_Route_Layer_TOP;
    LAYER_ID pairBottom = m_frame->GetScreen()->m_Route_Layer_BOTTOM;

    PNS::SIZES_SETTINGS sizes = m_router->Sizes();

    // fixme: P&S supports more than one fixed layer pair. Update the dialog?
    sizes.ClearLayerPairs();

    if( !m_router->IsPlacingVia() )
    {
        // Cannot place microvias or blind vias if not allowed (obvious)
        if( ( aType == VIA_BLIND_BURIED ) && ( !bds.m_BlindBuriedViaAllowed ) )
        {
            DisplayError( m_frame, _( "Blind/buried vias have to be enabled in the design settings." ) );
            return false;
        }

        if( ( aType == VIA_MICROVIA ) && ( !bds.m_MicroViasAllowed ) )
        {
            DisplayError( m_frame, _( "Microvias have to be enabled in the design settings." ) );
            return false;
        }

        // Can only place through vias on 2-layer boards
        if( ( aType != VIA_THROUGH ) && ( layerCount <= 2 ) )
        {
            DisplayError( m_frame, _( "Only through vias are allowed on 2 layer boards." ) );
            return false;
        }

        // Can only place microvias if we're on an outer layer, or directly adjacent to one
        if( ( aType == VIA_MICROVIA ) && ( currentLayer > In1_Cu ) && ( currentLayer < layerCount - 2 ) )
        {
            DisplayError( m_frame, _( "Microvias can be placed only between the outer layers " \
                                      "(F.Cu/B.Cu) and the ones directly adjacent to them." ) );
            return false;
        }
    }

    // Convert blind/buried via to a through hole one, if it goes through all layers
    if( aType == VIA_BLIND_BURIED && ( ( currentLayer == B_Cu ) || ( currentLayer == F_Cu ) )
                                    && ( ( pairTop == B_Cu && pairBottom == F_Cu )
                                      || ( pairTop == F_Cu && pairBottom == B_Cu ) ) )
    {
        aType = VIA_THROUGH;
    }

    switch( aType )
    {
    case VIA_THROUGH:
        sizes.SetViaDiameter( bds.GetCurrentViaSize() );
        sizes.SetViaDrill( bds.GetCurrentViaDrill() );
        sizes.AddLayerPair( pairTop, pairBottom );
        break;

    case VIA_MICROVIA:
        sizes.SetViaDiameter( bds.GetCurrentMicroViaSize() );
        sizes.SetViaDrill( bds.GetCurrentMicroViaDrill() );

        if( currentLayer == F_Cu || currentLayer == In1_Cu )
            sizes.AddLayerPair( F_Cu, In1_Cu );
        else if( currentLayer == B_Cu || currentLayer == layerCount - 2 )
            sizes.AddLayerPair( B_Cu, layerCount - 2 );
        else
            wxASSERT( false );
        break;

    case VIA_BLIND_BURIED:
        sizes.SetViaDiameter( bds.GetCurrentViaSize() );
        sizes.SetViaDrill( bds.GetCurrentViaDrill() );

        if( currentLayer == pairTop || currentLayer == pairBottom )
            sizes.AddLayerPair( pairTop, pairBottom );
        else
            sizes.AddLayerPair( pairTop, currentLayer );
        break;

    default:
        wxASSERT( false );
        break;
    }

    sizes.SetViaType( aType );

    m_router->UpdateSizes( sizes );
    m_router->ToggleViaPlacement();

    updateEndItem( aEvent );

    m_router->Move( m_endSnapPoint, m_endItem );        // refresh

    return false;
}