void PCB_EDIT_FRAME::StartMoveOneNodeOrSegment( TRACK* aTrack, wxDC* aDC, int aCommand )
{
    if( !aTrack )
        return;

    EraseDragList();

    // Change highlighted net: the new one will be highlighted
    GetBoard()->PushHighLight();

    if( GetBoard()->IsHighLightNetON() )
        HighLight( aDC );

    PosInit = GetCrossHairPosition();

    if( aTrack->Type() == PCB_VIA_T )
    {
        aTrack->SetFlags( IS_DRAGGED | STARTPOINT | ENDPOINT );
        AddSegmentToDragList( aTrack->GetFlags(), aTrack );

        if( aCommand != ID_POPUP_PCB_MOVE_TRACK_SEGMENT )
        {
            Collect_TrackSegmentsToDrag( GetBoard(), aTrack->GetStart(),
                                         aTrack->GetLayerSet(),
                                         aTrack->GetNetCode(), aTrack->GetWidth() / 2 );
        }

        PosInit = aTrack->GetStart();
    }
    else
    {
        STATUS_FLAGS diag = aTrack->IsPointOnEnds( GetCrossHairPosition(), -1 );
        wxPoint pos;

        switch( aCommand )
        {
        case ID_POPUP_PCB_MOVE_TRACK_SEGMENT:   // Move segment
            aTrack->SetFlags( IS_DRAGGED | ENDPOINT | STARTPOINT );
            AddSegmentToDragList( aTrack->GetFlags(), aTrack );
            break;

        case ID_POPUP_PCB_DRAG_TRACK_SEGMENT:   // drag a segment
            pos = aTrack->GetStart();
            Collect_TrackSegmentsToDrag( GetBoard(), pos, aTrack->GetLayerSet(),
                                         aTrack->GetNetCode(), aTrack->GetWidth() / 2 );
            pos = aTrack->GetEnd();
            aTrack->SetFlags( IS_DRAGGED | ENDPOINT | STARTPOINT );
            Collect_TrackSegmentsToDrag( GetBoard(), pos, aTrack->GetLayerSet(),
                                         aTrack->GetNetCode(), aTrack->GetWidth() / 2 );
            break;

        case ID_POPUP_PCB_MOVE_TRACK_NODE:  // Drag via or move node
            pos = (diag & STARTPOINT) ? aTrack->GetStart() : aTrack->GetEnd();
            Collect_TrackSegmentsToDrag( GetBoard(), pos, aTrack->GetLayerSet(),
                                         aTrack->GetNetCode(), aTrack->GetWidth() / 2 );
            PosInit = pos;
            break;
        }

        aTrack->SetFlags( IS_DRAGGED );
    }

    // Prepare the Undo command
    ITEM_PICKER picker( aTrack, UR_CHANGED );
    picker.SetLink( aTrack->Clone() );
    s_ItemsListPicker.PushItem( picker );

    for( unsigned ii = 0; ii < g_DragSegmentList.size(); ii++ )
    {
        TRACK* draggedtrack = g_DragSegmentList[ii].m_Track;
        picker.SetItem( draggedtrack );
        picker.SetLink( draggedtrack->Clone() );
        s_ItemsListPicker.PushItem( picker );
        draggedtrack = (TRACK*) picker.GetLink();
        draggedtrack->SetStatus( 0 );
        draggedtrack->ClearFlags();
    }

    s_LastPos = PosInit;
    m_canvas->SetMouseCapture( Show_MoveNode, Abort_MoveTrack );

    GetBoard()->SetHighLightNet( aTrack->GetNetCode() );
    GetBoard()->HighLightON();

    GetBoard()->DrawHighLight( m_canvas, aDC, GetBoard()->GetHighLightNetCode() );
    m_canvas->CallMouseCapture( aDC, wxDefaultPosition, true );

    UndrawAndMarkSegmentsToDrag( m_canvas, aDC );
}
void PCB_EDIT_FRAME::Start_DragTrackSegmentAndKeepSlope( TRACK* track, wxDC*  DC )
{
    TRACK* TrackToStartPoint = NULL;
    TRACK* TrackToEndPoint   = NULL;
    bool   error = false;

    if( !track )
        return;

    // TODO: Use clenup functions to merge collinear segments if track
    // is connected to a collinear segment.

    s_StartSegmentPresent = s_EndSegmentPresent = true;

    if( ( track->start == NULL ) || ( track->start->Type() == PCB_TRACE_T ) )
        TrackToStartPoint = track->GetTrack( GetBoard()->m_Track, NULL, ENDPOINT_START, true, false );

    //  Test if more than one segment is connected to this point
    if( TrackToStartPoint )
    {
        TrackToStartPoint->SetState( BUSY, true );

        if( ( TrackToStartPoint->Type() == PCB_VIA_T )
           || track->GetTrack( GetBoard()->m_Track, NULL, ENDPOINT_START, true, false ) )
            error = true;

        TrackToStartPoint->SetState( BUSY, false );
    }

    if( ( track->end == NULL ) || ( track->end->Type() == PCB_TRACE_T ) )
        TrackToEndPoint = track->GetTrack( GetBoard()->m_Track, NULL, ENDPOINT_END, true, false );

    //  Test if more than one segment is connected to this point
    if( TrackToEndPoint )
    {
        TrackToEndPoint->SetState( BUSY, true );

        if( (TrackToEndPoint->Type() == PCB_VIA_T)
           || track->GetTrack( GetBoard()->m_Track, NULL, ENDPOINT_END, true, false ) )
            error = true;

        TrackToEndPoint->SetState( BUSY, false );
    }

    if( error )
    {
        DisplayError( this,
                      _( "Unable to drag this segment: too many segments connected" ) );
        return;
    }

    if( !TrackToStartPoint || ( TrackToStartPoint->Type() != PCB_TRACE_T ) )
        s_StartSegmentPresent = false;

    if( !TrackToEndPoint || ( TrackToEndPoint->Type() != PCB_TRACE_T ) )
        s_EndSegmentPresent = false;

    // Change high light net: the new one will be highlighted
    GetBoard()->PushHighLight();

    if( GetBoard()->IsHighLightNetON() )
        HighLight( DC );

    EraseDragList();

    track->SetFlags( IS_DRAGGED );

    if( TrackToStartPoint )
    {
        STATUS_FLAGS flag = STARTPOINT;

        if( track->GetStart() != TrackToStartPoint->GetStart() )
            flag = ENDPOINT;

        AddSegmentToDragList( flag, TrackToStartPoint );
        track->SetFlags( STARTPOINT );
    }

    if( TrackToEndPoint )
    {
        STATUS_FLAGS flag = STARTPOINT;

        if( track->GetEnd() != TrackToEndPoint->GetStart() )
            flag = ENDPOINT;

        AddSegmentToDragList( flag, TrackToEndPoint );
        track->SetFlags( ENDPOINT );
    }

    AddSegmentToDragList( track->GetFlags(), track );

    UndrawAndMarkSegmentsToDrag( m_canvas, DC );


    PosInit   = GetCrossHairPosition();
    s_LastPos = GetCrossHairPosition();
    m_canvas->SetMouseCapture( Show_Drag_Track_Segment_With_Cte_Slope, Abort_MoveTrack );

    GetBoard()->SetHighLightNet( track->GetNetCode() );
    GetBoard()->HighLightON();
    GetBoard()->DrawHighLight( m_canvas, DC, GetBoard()->GetHighLightNetCode() );

    // Prepare the Undo command
    ITEM_PICKER picker( NULL, UR_CHANGED );

    for( unsigned ii = 0; ii < g_DragSegmentList.size(); ii++ )
    {
        TRACK* draggedtrack = g_DragSegmentList[ii].m_Track;
        picker.SetItem( draggedtrack);
        picker.SetLink ( draggedtrack->Clone() );
        s_ItemsListPicker.PushItem( picker );
        draggedtrack = (TRACK*) picker.GetLink();
        draggedtrack->SetStatus( 0 );
        draggedtrack->ClearFlags();
    }

    if( !InitialiseDragParameters() )
    {
        DisplayError( this, _( "Unable to drag this segment: two collinear segments" ) );
        m_canvas->SetMouseCaptureCallback( NULL );
        Abort_MoveTrack( m_canvas, DC );
        return;
    }
}
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;
}