/**
 * Function SetTrackSegmentWidth
 *  Modify one track segment width or one via diameter and drill (using DRC control).
 *  Basic routine used by other routines when editing tracks or vias
 * @param aTrackItem = the track segment or via to modify
 * @param aItemsListPicker = the list picker to use for an undo command (can be NULL)
 * @param aUseNetclassValue = true to use NetClass value, false to use BOARD::m_designSettings value
 * @return  true if done, false if no not change (because DRC error)
 */
bool PCB_EDIT_FRAME::SetTrackSegmentWidth( TRACK*             aTrackItem,
                                           PICKED_ITEMS_LIST* aItemsListPicker,
                                           bool               aUseNetclassValue )
{
    int           initial_width, new_width;
    int           initial_drill = -1,new_drill = -1;
    bool          change_ok = false;
    NETINFO_ITEM* net = NULL;

    if( aUseNetclassValue )
        net = aTrackItem->GetNet();

    initial_width = aTrackItem->GetWidth();

    if( net )
        new_width = net->GetTrackWidth();
    else
        new_width = GetDesignSettings().GetCurrentTrackWidth();

    if( aTrackItem->Type() == PCB_VIA_T )
    {
        const VIA *via = static_cast<const VIA *>( aTrackItem );

        if( !via->IsDrillDefault() )
            initial_drill = via->GetDrillValue();

        if( net )
        {
            new_width = net->GetViaSize();
        }
        else
        {
            new_width = GetDesignSettings().GetCurrentViaSize();
            new_drill = GetDesignSettings().GetCurrentViaDrill();
        }

        if( via->GetViaType() == VIA_MICROVIA )
        {
            if( net )
                new_width = net->GetMicroViaSize();
            else
                new_width = GetDesignSettings().GetCurrentMicroViaSize();
        }
    }

    aTrackItem->SetWidth( new_width );

    // make a DRC test because the new size is bigger than the old size
    if( initial_width < new_width )
    {
        int diagdrc = OK_DRC;

        if( g_Drc_On )
            diagdrc = m_drc->Drc( aTrackItem, GetBoard()->m_Track );

        if( diagdrc == OK_DRC )
            change_ok = true;
    }
    else if( initial_width > new_width )
    {
        change_ok = true;
    }
    else if( (aTrackItem->Type() == PCB_VIA_T) && (initial_drill != new_drill) )
    {
        // if new width == initial_width: do nothing, unless a via has its drill value changed
        change_ok = true;
    }

    if( change_ok )
    {
        OnModify();

        if( aItemsListPicker )
        {
            aTrackItem->SetWidth( initial_width );
            ITEM_PICKER picker( aTrackItem, UR_CHANGED );
            picker.SetLink( aTrackItem->Clone() );
            aItemsListPicker->PushItem( picker );
            aTrackItem->SetWidth( new_width );

            if( aTrackItem->Type() == PCB_VIA_T )
            {
                // Set new drill value. Note: currently microvias have only a default drill value
                VIA *via = static_cast<VIA *>( aTrackItem );
                if( new_drill > 0 )
                    via->SetDrill( new_drill );
                else
                    via->SetDrillDefault();
            }
        }
    }
    else
    {
        aTrackItem->SetWidth( initial_width );
    }

    return change_ok;
}
int PCB_EDIT_FRAME::SetTrackSegmentWidth( TRACK*             aTrackItem,
                                          PICKED_ITEMS_LIST* aItemsListPicker,
                                          bool               aUseNetclassValue )
{
    int           return_code = TRACK_ACTION_NONE;
    int           initial_width;
    int           new_width;
    int           initial_drill = -1;
    int           new_drill = -1;
    NETINFO_ITEM* net = NULL;

    if( aUseNetclassValue )
        net = aTrackItem->GetNet();

    initial_width = aTrackItem->GetWidth();

    if( net )
        new_width = net->GetTrackWidth();
    else
        new_width = GetDesignSettings().GetCurrentTrackWidth();

    if( aTrackItem->Type() == PCB_VIA_T )
    {
        const VIA *via = static_cast<const VIA *>( aTrackItem );

        // Micro vias have a size only defined in their netclass
        // (no specific values defined by a table of specific value)
        // Ensure the netclass is accessible:
        if( via->GetViaType() == VIA_MICROVIA && net == NULL )
            net = aTrackItem->GetNet();

        // Get the draill value, regardless it is default or specific
        initial_drill = via->GetDrillValue();

        if( net )
        {
            new_width = net->GetViaSize();
            new_drill = net->GetViaDrillSize();
        }
        else
        {
            new_width = GetDesignSettings().GetCurrentViaSize();
            new_drill = GetDesignSettings().GetCurrentViaDrill();
        }

        if( via->GetViaType() == VIA_MICROVIA )
        {
            if( net )
            {
                new_width = net->GetMicroViaSize();
                new_drill = net->GetMicroViaDrillSize();
            }
            else
            {
                // Should not occur
            }
        }

        // Old versions set a drill value <= 0, when the default netclass it used
        // but it could be better to set the drill value to the actual value
        // to avoid issues for existing vias, if the default drill value is modified
        // in the netclass, and not in current vias.
        if( via->GetDrill() <= 0 )      // means default netclass drill value used
        {
            initial_drill  = -1;        // Force drill vias re-initialization
        }
    }

    aTrackItem->SetWidth( new_width );

    // make a DRC test because the new size is bigger than the old size
    if( initial_width < new_width )
    {
        int diagdrc = OK_DRC;
        return_code = TRACK_ACTION_SUCCESS;

        if( Settings().m_legacyDrcOn )
            diagdrc = m_drc->DrcOnCreatingTrack( aTrackItem, GetBoard()->m_Track );

        if( diagdrc != OK_DRC )
            return_code = TRACK_ACTION_DRC_ERROR;
    }
    else if( initial_width > new_width )
    {
        return_code = TRACK_ACTION_SUCCESS;
    }
    else if( (aTrackItem->Type() == PCB_VIA_T) )
    {
        // if a via has its drill value changed, force change
        if( initial_drill != new_drill )
            return_code = TRACK_ACTION_SUCCESS;
    }

    if( return_code == TRACK_ACTION_SUCCESS )
    {
        OnModify();

        if( aItemsListPicker )
        {
            aTrackItem->SetWidth( initial_width );
            ITEM_PICKER picker( aTrackItem, UR_CHANGED );
            picker.SetLink( aTrackItem->Clone() );
            aItemsListPicker->PushItem( picker );
            aTrackItem->SetWidth( new_width );

            if( aTrackItem->Type() == PCB_VIA_T )
            {
                // Set new drill value. Note: currently microvias have only a default drill value
                VIA *via = static_cast<VIA *>( aTrackItem );
                if( new_drill > 0 )
                    via->SetDrill( new_drill );
                else
                    via->SetDrillDefault();
            }
        }
    }
    else
    {
        aTrackItem->SetWidth( initial_width );
    }

    return return_code;
}
bool PCB_EDIT_FRAME::Other_Layer_Route( TRACK* aTrack, wxDC* DC )
{
    unsigned    itmp;

    if( aTrack == NULL )
    {
        if( GetActiveLayer() != GetScreen()->m_Route_Layer_TOP )
            SetActiveLayer( GetScreen()->m_Route_Layer_TOP );
        else
            SetActiveLayer( GetScreen()->m_Route_Layer_BOTTOM );

        UpdateStatusBar();
        return true;
    }

    // Avoid more than one via on the current location:
    if( GetBoard()->GetViaByPosition( g_CurrentTrackSegment->GetEnd(),
                                      g_CurrentTrackSegment->GetLayer() ) )
        return false;

    for( TRACK* segm = g_FirstTrackSegment;  segm;  segm = segm->Next() )
    {
        if( segm->Type() == PCB_VIA_T && g_CurrentTrackSegment->GetEnd() == segm->GetStart() )
            return false;
    }

    // Is the current segment Ok (no DRC error) ?
    if( g_Drc_On )
    {
        if( BAD_DRC==m_drc->Drc( g_CurrentTrackSegment, GetBoard()->m_Track ) )
            // DRC error, the change layer is not made
            return false;

        // Handle 2 segments.
        if( g_TwoSegmentTrackBuild && g_CurrentTrackSegment->Back() )
        {
            if( BAD_DRC == m_drc->Drc( g_CurrentTrackSegment->Back(), GetBoard()->m_Track ) )
                return false;
        }
    }

    /* Save current state before placing a via.
     * If the via cannot be placed this current state will be reused
     */
    itmp = g_CurrentTrackList.GetCount();
    Begin_Route( g_CurrentTrackSegment, DC );

    m_canvas->CallMouseCapture( DC, wxDefaultPosition, false );

    // create the via
    VIA* via = new VIA( GetBoard() );
    via->SetFlags( IS_NEW );
    via->SetViaType( GetDesignSettings().m_CurrentViaType );
    via->SetNetCode( GetBoard()->GetHighLightNetCode() );
    via->SetPosition( g_CurrentTrackSegment->GetEnd() );

    // for microvias, the size and hole will be changed later.
    via->SetWidth( GetDesignSettings().GetCurrentViaSize());
    via->SetDrill( GetDesignSettings().GetCurrentViaDrill() );

    // Usual via is from copper to component.
    // layer pair is B_Cu and F_Cu.
    via->SetLayerPair( B_Cu, F_Cu );

    LAYER_ID first_layer = GetActiveLayer();
    LAYER_ID last_layer;

    // prepare switch to new active layer:
    if( first_layer != GetScreen()->m_Route_Layer_TOP )
        last_layer = GetScreen()->m_Route_Layer_TOP;
    else
        last_layer = GetScreen()->m_Route_Layer_BOTTOM;

    // Adjust the actual via layer pair
    switch( via->GetViaType() )
    {
    case VIA_BLIND_BURIED:
        via->SetLayerPair( first_layer, last_layer );
        break;

    case VIA_MICROVIA:  // from external to the near neighbor inner layer
        {
            LAYER_ID last_inner_layer = ToLAYER_ID( ( GetBoard()->GetCopperLayerCount() - 2 ) );

            if( first_layer == B_Cu )
                last_layer = last_inner_layer;
            else if( first_layer == F_Cu )
                last_layer = In1_Cu;
            else if( first_layer == last_inner_layer )
                last_layer = B_Cu;
            else if( first_layer == In1_Cu )
                last_layer = F_Cu;
            // else error: will be removed later
            via->SetLayerPair( first_layer, last_layer );

            // Update diameter and hole size, which where set previously
            // for normal vias
            NETINFO_ITEM* net = via->GetNet();
            via->SetWidth( net->GetMicroViaSize() );
            via->SetDrill( net->GetMicroViaDrillSize() );
        }
        break;

    default:
        break;
    }

    if( g_Drc_On && BAD_DRC == m_drc->Drc( via, GetBoard()->m_Track ) )
    {
        // DRC fault: the Via cannot be placed here ...
        delete via;

        m_canvas->CallMouseCapture( DC, wxDefaultPosition, false );

        // delete the track(s) added in Begin_Route()
        while( g_CurrentTrackList.GetCount() > itmp )
        {
            Delete_Segment( DC, g_CurrentTrackSegment );
        }

         SetCurItem( g_CurrentTrackSegment, false );

        // Refresh DRC diag, erased by previous calls
        if( m_drc->GetCurrentMarker() )
            SetMsgPanel( m_drc->GetCurrentMarker() );

        return false;
    }

    SetActiveLayer( last_layer );

    TRACK*  lastNonVia = g_CurrentTrackSegment;

    /* A new via was created. It was Ok.
     */
    g_CurrentTrackList.PushBack( via );

    /* The via is now in linked list and we need a new track segment
     * after the via, starting at via location.
     * it will become the new current segment (from via to the mouse cursor)
     */

    TRACK* track = (TRACK*)lastNonVia->Clone();

    /* the above creates a new segment from the last entered segment, with the
     * current width, flags, netcode, etc... values.
     * layer, start and end point are not correct,
     * and will be modified next
     */

    // set the layer to the new value
    track->SetLayer( GetActiveLayer() );

    /* the start point is the via position and the end point is the cursor
     * which also is on the via (will change when moving mouse)
     */
    track->SetEnd( via->GetStart() );
    track->SetStart( via->GetStart() );

    g_CurrentTrackList.PushBack( track );

    if( g_TwoSegmentTrackBuild )
    {
        // Create a second segment (we must have 2 track segments to adjust)
        g_CurrentTrackList.PushBack( (TRACK*)g_CurrentTrackSegment->Clone() );
    }

    m_canvas->CallMouseCapture( DC, wxDefaultPosition, false );
    SetMsgPanel( via );
    UpdateStatusBar();

    return true;
}
bool PCB_EDIT_FRAME::SetTrackSegmentWidth( TRACK*             aTrackItem,
                                           PICKED_ITEMS_LIST* aItemsListPicker,
                                           bool               aUseNetclassValue )
{
    /* Modify one track segment width or one via diameter and drill (using DRC control).
     * Basic function used by other routines when editing tracks or vias
     * aTrackItem = the track segment or via to modify
     * aItemsListPicker = the list picker to use for an undo command (can be NULL)
     * aUseNetclassValue = true to use NetClass value, false to use BOARD::m_designSettings value
     * return  true if done, false if no not change (due to DRC error)
     */
    int           initial_width, new_width;
    int           initial_drill = -1,new_drill = -1;
    bool          change_ok = false;
    NETINFO_ITEM* net = NULL;

    if( aUseNetclassValue )
        net = aTrackItem->GetNet();

    initial_width = aTrackItem->GetWidth();

    if( net )
        new_width = net->GetTrackWidth();
    else
        new_width = GetDesignSettings().GetCurrentTrackWidth();

    if( aTrackItem->Type() == PCB_VIA_T )
    {
        const VIA *via = static_cast<const VIA *>( aTrackItem );

        // Micro vias have a size only defined in their netclass
        // (no specific values defined by a table of specific value)
        // Ensure the netclass is accessible:
        if( via->GetViaType() == VIA_MICROVIA && net == NULL )
            net = aTrackItem->GetNet();

        // Get the draill value, regardless it is default or specific
        initial_drill = via->GetDrillValue();

        if( net )
        {
            new_width = net->GetViaSize();
            new_drill = net->GetViaDrillSize();
        }
        else
        {
            new_width = GetDesignSettings().GetCurrentViaSize();
            new_drill = GetDesignSettings().GetCurrentViaDrill();
        }

        if( via->GetViaType() == VIA_MICROVIA )
        {
            if( net )
            {
                new_width = net->GetMicroViaSize();
                new_drill = net->GetMicroViaDrillSize();
            }
            else
            {
                // Should not occur
            }
        }

        // Old versions set a drill value <= 0, when the default netclass it used
        // but it could be better to set the drill value to the actual value
        // to avoid issues for existing vias, if the default drill value is modified
        // in the netclass, and not in current vias.
        if( via->GetDrill() <= 0 )      // means default netclass drill value used
        {
            initial_drill  = -1;        // Force drill vias re-initialization
        }
    }

    aTrackItem->SetWidth( new_width );

    // make a DRC test because the new size is bigger than the old size
    if( initial_width < new_width )
    {
        int diagdrc = OK_DRC;

        if( g_Drc_On )
            diagdrc = m_drc->Drc( aTrackItem, GetBoard()->m_Track );

        if( diagdrc == OK_DRC )
            change_ok = true;
    }
    else if( initial_width > new_width )
    {
        change_ok = true;
    }
    else if( (aTrackItem->Type() == PCB_VIA_T) )
    {
        // if a via has its drill value changed, force change
        if( initial_drill != new_drill )
            change_ok = true;
    }

    if( change_ok )
    {
        OnModify();

        if( aItemsListPicker )
        {
            aTrackItem->SetWidth( initial_width );
            ITEM_PICKER picker( aTrackItem, UR_CHANGED );
            picker.SetLink( aTrackItem->Clone() );
            aItemsListPicker->PushItem( picker );
            aTrackItem->SetWidth( new_width );

            if( aTrackItem->Type() == PCB_VIA_T )
            {
                // Set new drill value. Note: currently microvias have only a default drill value
                VIA *via = static_cast<VIA *>( aTrackItem );
                if( new_drill > 0 )
                    via->SetDrill( new_drill );
                else
                    via->SetDrillDefault();
            }
        }
    }
    else
    {
        aTrackItem->SetWidth( initial_width );
    }

    return change_ok;
}