Example #1
0
// Redraw the moved node according to the mouse cursor position
static void Show_MoveNode( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition,
                           bool aErase )
{
    auto displ_opts = (PCB_DISPLAY_OPTIONS*) aPanel->GetDisplayOptions();
    wxPoint      moveVector;
    int          tmp = displ_opts->m_DisplayPcbTrackFill;
    GR_DRAWMODE  draw_mode = GR_XOR | GR_HIGHLIGHT;

    displ_opts->m_DisplayPcbTrackFill = false;

#ifndef USE_WX_OVERLAY
    aErase = true;
#else
    aErase = false;
#endif

    // set the new track coordinates
    wxPoint Pos = aPanel->GetParent()->GetCrossHairPosition();

    moveVector = Pos - s_LastPos;
    s_LastPos  = Pos;

    TRACK *track = NULL;

    for( unsigned ii = 0; ii < g_DragSegmentList.size(); ii++ )
    {
        track = g_DragSegmentList[ii].m_Track;

        if( aErase )
            track->Draw( aPanel, aDC, draw_mode );

        if( track->GetFlags() & STARTPOINT )
            track->SetStart( track->GetStart() + moveVector );

        if( track->GetFlags() & ENDPOINT )
            track->SetEnd( track->GetEnd() + moveVector );

        if( track->Type() == PCB_VIA_T )
            track->SetEnd( track->GetStart() );

        track->Draw( aPanel, aDC, draw_mode );
    }

    displ_opts->m_DisplayPcbTrackFill = tmp;

    // Display track length
    if( track )
    {
        PCB_BASE_FRAME* frame = (PCB_BASE_FRAME*) aPanel->GetParent();
        frame->SetMsgPanel( track );
    }
}
/* Init variables (slope, Y intersect point, flags) for
 * Show_Drag_Track_Segment_With_Cte_Slope()
 *  return true if Ok, false if dragging is not possible
 *  (2 colinear segments)
 */
bool InitialiseDragParameters()
{
    double     tx1, tx2, ty1, ty2; // temporary storage of points
    TRACK*     Track;
    TRACK*     tSegmentToStart = NULL, * tSegmentToEnd = NULL;

    if( g_DragSegmentList.size() == 0 )
        return false;

    /* get the segments :
     * from last to first in list are:
     * the segment to move
     * the segment connected to its end point (if exists)
     * the segment connected to its start point (if exists)
     */
    int ii = g_DragSegmentList.size() - 1;
    Track = g_DragSegmentList[ii].m_Track;
    if( Track == NULL )
        return false;

    ii--;

    if( ii >= 0)
    {
        if( s_EndSegmentPresent )
        {
            tSegmentToEnd = g_DragSegmentList[ii].m_Track;  // Get the segment connected to
                                                           // the end point
            ii--;
        }

        if( s_StartSegmentPresent )
        {
            if( ii  >= 0 )
                tSegmentToStart = g_DragSegmentList[ii].m_Track;  // Get the segment connected to
                                                                 // the start point
        }
    }

    // would be nice to eliminate collinear segments here, so we don't
    // have to deal with that annoying "Unable to drag this segment: two
    // collinear segments"

    s_StartPointVertical = false;
    s_EndPointVertical   = false;
    s_MovingSegmentVertical   = false;
    s_StartPointHorizontal    = false;
    s_EndPointHorizontal      = false;
    s_MovingSegmentHorizontal = false;

    // Init parameters for the starting point of the moved segment
    if( tSegmentToStart )
    {
        if( tSegmentToStart->GetFlags() & ENDPOINT )
        {
            tx1 = (double) tSegmentToStart->GetStart().x;
            ty1 = (double) tSegmentToStart->GetStart().y;
            tx2 = (double) tSegmentToStart->GetEnd().x;
            ty2 = (double) tSegmentToStart->GetEnd().y;
        }
        else
        {
            tx1 = (double) tSegmentToStart->GetEnd().x;
            ty1 = (double) tSegmentToStart->GetEnd().y;
            tx2 = (double) tSegmentToStart->GetStart().x;
            ty2 = (double) tSegmentToStart->GetStart().y;
        }
    }
    else // move the start point on a line starting at Track->GetStart(), and perpendicular to Track
    {
        tx1 = (double) Track->GetStart().x;
        ty1 = (double) Track->GetStart().y;
        tx2 = (double) Track->GetEnd().x;
        ty2 = (double) Track->GetEnd().y;
        RotatePoint( &tx2, &ty2, tx1, ty1, 900 );
    }

    if( tx1 != tx2 )
    {
        s_StartSegmentSlope = ( ty2 - ty1 ) / ( tx2 - tx1 );
        s_StartSegment_Yorg = ty1 - ( ty2 - ty1 ) * tx1 / ( tx2 - tx1 );
    }
    else
    {
        s_StartPointVertical = true;            //signal first segment vertical
    }

    if( ty1 == ty2 )
    {
        s_StartPointHorizontal = true;
    }

    // Init parameters for the ending point of the moved segment
    if( tSegmentToEnd )
    {
        //check if second line is vertical
        if( tSegmentToEnd->GetFlags() & STARTPOINT )
        {
            tx1 = (double) tSegmentToEnd->GetStart().x;
            ty1 = (double) tSegmentToEnd->GetStart().y;
            tx2 = (double) tSegmentToEnd->GetEnd().x;
            ty2 = (double) tSegmentToEnd->GetEnd().y;
        }
        else
        {
            tx1 = (double) tSegmentToEnd->GetEnd().x;
            ty1 = (double) tSegmentToEnd->GetEnd().y;
            tx2 = (double) tSegmentToEnd->GetStart().x;
            ty2 = (double) tSegmentToEnd->GetStart().y;
        }
    }
    else // move the start point on a line starting at Track->GetEnd(), and perpendicular to Track
    {
        tx1 = (double) Track->GetEnd().x;
        ty1 = (double) Track->GetEnd().y;
        tx2 = (double) Track->GetStart().x;
        ty2 = (double) Track->GetStart().y;
        RotatePoint( &tx2, &ty2, tx1, ty1, -900 );
    }

    if( tx2 != tx1 )
    {
        s_EndSegmentSlope = ( ty2 - ty1 ) / ( tx2 - tx1 );
        s_EndSegment_Yorg = ty1 - ( ty2 - ty1 ) * tx1 / ( tx2 - tx1 );
    }
    else
    {
        s_EndPointVertical = true;      //signal second segment vertical
    }

    if( ty1 == ty2 )
    {
        s_EndPointHorizontal = true;
    }

    // Init parameters for the moved segment
    tx1 = (double) Track->GetStart().x;
    ty1 = (double) Track->GetStart().y;
    tx2 = (double) Track->GetEnd().x;
    ty2 = (double) Track->GetEnd().y;

    if( tx2 != tx1 )
    {
        s_MovingSegmentSlope = ( ty2 - ty1 ) / ( tx2 - tx1 );
    }
    else
    {
        s_MovingSegmentVertical = true;      // signal vertical line
    }

    if( ty1 == ty2 )
    {
        s_MovingSegmentHorizontal = true;
    }

    // Test if drag is possible:
    if( s_MovingSegmentVertical )
    {
        if( s_EndPointVertical || s_StartPointVertical )
            return false;
    }
    else
    {
        if( !s_EndPointVertical && ( s_MovingSegmentSlope == s_EndSegmentSlope ) )
            return false;

        if( !s_StartPointVertical && ( s_MovingSegmentSlope == s_StartSegmentSlope ) )
            return false;
    }

    return true;
}
/* drawing the track segment movement
 *  > s_MovingSegmentSlope slope = moving track segment slope
 *  > s_StartSegmentSlope slope = slope of the segment connected to the start
 * point of the moving segment
 *  > s_EndSegmentSlope slope = slope of the segment connected to the end point
 * of the moving segment
 *
 *  moved segment function :
 *      yt=s_MovingSegmentSlope * x + s_MovingSegment_Yorg
 *
 *  segment connected to moved segment's start:
 *      y1 = s_StartSegmentSlope * x + s_StartSegment_Yorg
 *
 *  segment connected to moved segment's end:
 *      y2=s_EndSegmentSlope * x + s_EndSegment_Yorg
 *
 *  first intersection point will be located at
 *      y1=yt ->
 *
 * xi1=(s_MovingSegment_Yorg-s_StartSegment_Yorg)/(s_StartSegmentSlope-s_MovingSegmentSlope)
 *      yi1=s_MovingSegmentSlope*xi1+s_MovingSegment_Yorg
 *      or yi1=s_StartSegmentSlope*xi1+s_MovingSegment_Yorg
 *
 *  second intersection point
 *      y2=yt ->
 *
 * xi2=(s_MovingSegment_Yorg-s_StartSegment_Yorg)/(s_MovingSegmentSlope-s_MovingSegmentSlope)
 *      yi2=s_MovingSegmentSlope*xi2+s_MovingSegment_Yorg
 *      or yi1=s_EndSegmentSlope*xi2+s_MovingSegment_Yorg
 *  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 *  !!!!!    special attention to vertical segments because
 *  !!!!!    their slope=infinite
 *  !!!!!    intersection point will be calculated using the
 *  !!!!!    segment intersecting it
 *  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 *
 *  Slope parameters are computed once, because they can become undetermined
 * when moving segments
 *  (i.e. when a segment length is 0) and we want keep them constant
 */
static void Show_Drag_Track_Segment_With_Cte_Slope( EDA_DRAW_PANEL* aPanel, wxDC* aDC,
                                                    const wxPoint& aPosition, bool aErase )
{
    double       xi1 = 0, yi1 = 0, xi2 = 0, yi2 = 0;    // calculated intersection points
    double       tx1, tx2, ty1, ty2;                    // temporary storage of points
    int          dx, dy;
    bool         update = true;
    TRACK*       Track;
    TRACK*       tSegmentToStart = NULL, * tSegmentToEnd = NULL;

    if( g_DragSegmentList.size() == 0 )
        return;

    /* get the segments :
     * from last to first in list are:
     * the segment to move
     * the segment connected to its end point (if exists)
     * the segment connected to its start point (if exists)
     */
    int ii = g_DragSegmentList.size() - 1;
    Track = g_DragSegmentList[ii].m_Track;

    if( Track == NULL )
        return;

    ii--;

    if( ii >= 0)
    {
        if( s_EndSegmentPresent )
        {
            // Get the segment connected to the end point
            tSegmentToEnd   = g_DragSegmentList[ii].m_Track;
            ii--;
        }

        if( s_StartSegmentPresent )
        {
            // Get the segment connected to the start point
            if( ii >= 0 )
                tSegmentToStart = g_DragSegmentList[ii].m_Track;
        }
    }

    GR_DRAWMODE draw_mode = GR_XOR | GR_HIGHLIGHT;

    // Undraw the current moved track segments before modification

#ifndef USE_WX_OVERLAY
//  if( erase )
    {
        Track->Draw( aPanel, aDC, draw_mode );

        if( tSegmentToStart )
            tSegmentToStart->Draw( aPanel, aDC, draw_mode );

        if( tSegmentToEnd )
            tSegmentToEnd->Draw( aPanel, aDC, draw_mode );
    }
#endif

    // Compute the new track segment position
    wxPoint Pos = aPanel->GetParent()->GetCrossHairPosition();

    dx = Pos.x - s_LastPos.x;
    dy = Pos.y - s_LastPos.y;

    // move the line by dx and dy
    tx1 = (double) ( Track->GetStart().x + dx );
    ty1 = (double) ( Track->GetStart().y + dy );
    tx2 = (double) ( Track->GetEnd().x + dx );
    ty2 = (double) ( Track->GetEnd().y + dy );

    // recalculate the segments new parameters and intersection points
    // only the intercept will change, segment slopes does not change
    // because we are moving parallel with is initial state
    if( !s_MovingSegmentVertical )
    {
        s_MovingSegment_Yorg = ty1 - ( s_MovingSegmentSlope * tx1 );
    }

    if( ( !s_EndPointVertical ) && ( !s_MovingSegmentVertical ) )
    {
        xi2 = ( s_MovingSegment_Yorg - s_EndSegment_Yorg )
            / ( s_EndSegmentSlope - s_MovingSegmentSlope );
    }
    else
    {
        if( !s_EndPointVertical )
        {
            xi2 = tx2;
        }
        else
        {
            //P1=P2
            if( !s_EndPointHorizontal )
            {
                xi2 = tx2 - dx;
            }
            else
            {
                update = false;
            }
        }
    }

    if( !s_MovingSegmentVertical )
    {
        yi2 = s_MovingSegmentSlope * ( xi2 ) + s_MovingSegment_Yorg;
    }
    else
    {
        if( !s_EndPointVertical )
        {
            yi2 = s_EndSegmentSlope * ( xi2 ) + s_EndSegment_Yorg;
        }
        else
        {
            if( !s_EndPointHorizontal )
            {
                update = false;
            }
            else
            {
                yi2 = s_MovingSegmentSlope * ( xi2 ) + s_MovingSegment_Yorg;
            }
        }
    }

    if( ( !s_StartPointVertical ) && ( !s_MovingSegmentVertical ) )
    {
        xi1 = ( s_MovingSegment_Yorg - s_StartSegment_Yorg )
            / ( s_StartSegmentSlope - s_MovingSegmentSlope );
    }
    else
    {
        if( !s_StartPointVertical )
        {
            xi1 = tx1;
        }
        else
        {
            //P1=P2
            if( !s_StartPointHorizontal )
            {
                xi1 = tx1 - dx;
            }
            else
            {
                if( !s_StartPointHorizontal )
                {
                    update = false;
                }
            }
        }
    }

    if( !s_MovingSegmentVertical )
    {
        yi1 = s_MovingSegmentSlope * ( xi1 ) + s_MovingSegment_Yorg;
    }
    else
    {
        if( !s_StartPointVertical )
        {
            yi1 = s_StartSegmentSlope * ( xi1 ) + s_StartSegment_Yorg;
        }
        else
        {
            if( !s_StartPointHorizontal )
            {
                update = false;
            }
            else
            {
                yi2 = s_MovingSegmentSlope * ( xi1 ) + s_MovingSegment_Yorg;
            }
        }
    }

    // update the segment coordinates (if possible)
    if( tSegmentToStart == NULL )
    {
        xi1 = tx1;
        yi1 = ty1;
    }

    if( tSegmentToEnd == NULL )
    {
        xi2 = tx2;
        yi2 = ty2;
    }

    if( update )
    {
        s_LastPos = Pos;
        Track->SetStart( wxPoint( KiROUND( xi1 ), KiROUND( yi1 ) ) );
        Track->SetEnd( wxPoint( KiROUND( xi2 ), KiROUND( yi2 ) ) );

        if( tSegmentToEnd )
        {
            if( tSegmentToEnd->GetFlags() & STARTPOINT )
                tSegmentToEnd->SetStart( Track->GetEnd() );
            else
                tSegmentToEnd->SetEnd( Track->GetEnd() );
        }

        if( tSegmentToStart )
        {
            if( tSegmentToStart->GetFlags() & STARTPOINT )
                tSegmentToStart->SetStart( Track->GetStart() );
            else
                tSegmentToStart->SetEnd( Track->GetStart() );
        }
    }

    Track->Draw( aPanel, aDC, draw_mode );

    if( tSegmentToStart )
        tSegmentToStart->Draw( aPanel, aDC, draw_mode );

    if( tSegmentToEnd )
        tSegmentToEnd->Draw( aPanel, aDC, draw_mode );

    // Display track length
    PCB_BASE_FRAME* frame = (PCB_BASE_FRAME*) aPanel->GetParent();
    frame->SetMsgPanel( Track );
}
int PCBNEW_CONTROL::AppendBoard( const TOOL_EVENT& aEvent )
{
    int open_ctl;
    wxString fileName;
    PICKED_ITEMS_LIST undoListPicker;
    ITEM_PICKER picker( NULL, UR_NEW );

    PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame );
    BOARD* board = getModel<BOARD>();
    KIGFX::VIEW* view = getView();

    if( !editFrame )
        return 0;

    // Pick a file to append
    if( !AskLoadBoardFileName( editFrame, &open_ctl, &fileName, true ) )
        return 0;

    IO_MGR::PCB_FILE_T pluginType = plugin_type( fileName, open_ctl );
    PLUGIN::RELEASER pi( IO_MGR::PluginFind( pluginType ) );

    // keep track of existing items, in order to know what are the new items
    // (for undo command for instance)

    // Tracks are inserted, not appended, so mark the existing tracks to know what are the new tracks
    for( TRACK* track = board->m_Track; track; track = track->Next() )
        track->SetFlags( FLAG0 );

    // Other items are appended to the item list, so keep trace to the last existing item is enough
    MODULE* module = board->m_Modules.GetLast();
    BOARD_ITEM* drawing = board->m_Drawings.GetLast();
    int zonescount = board->GetAreaCount();

    // Keep also the count of copper layers, to adjust if necessary
    int initialCopperLayerCount = board->GetCopperLayerCount();
    LSET initialEnabledLayers = board->GetEnabledLayers();

    // Load the data
    try
    {
        PROPERTIES  props;
        char        xbuf[30];
        char        ybuf[30];

        // EAGLE_PLUGIN can use this info to center the BOARD, but it does not yet.
        sprintf( xbuf, "%d", editFrame->GetPageSizeIU().x );
        sprintf( ybuf, "%d", editFrame->GetPageSizeIU().y );

        props["page_width"]  = xbuf;
        props["page_height"] = ybuf;

        editFrame->GetDesignSettings().m_NetClasses.Clear();
        pi->Load( fileName, board, &props );
    }
    catch( const IO_ERROR& ioe )
    {
        wxString msg = wxString::Format( _( "Error loading board.\n%s" ), GetChars( ioe.errorText ));
        DisplayError( editFrame, msg );

        return 0;
    }

    m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true );

    // Process the new items
    for( TRACK* track = board->m_Track; track; track = track->Next() )
    {
        if( track->GetFlags() & FLAG0 )
        {
            track->ClearFlags( FLAG0 );
            continue;
        }

        picker.SetItem( track );
        undoListPicker.PushItem( picker );
        view->Add( track );
        m_toolMgr->RunAction( COMMON_ACTIONS::selectItem, true, track );
    }

    module = module ? module->Next() : board->m_Modules;

    for( ; module; module = module->Next() )
    {
        picker.SetItem( module );
        undoListPicker.PushItem( picker );

        module->RunOnChildren( boost::bind( &KIGFX::VIEW::Add, view, _1 ) );
        view->Add( module );
        m_toolMgr->RunAction( COMMON_ACTIONS::selectItem, true, module );
    }

    drawing = drawing ? drawing->Next() : board->m_Drawings;

    for( ; drawing; drawing = drawing->Next() )
    {
        picker.SetItem( drawing );
        undoListPicker.PushItem( picker );
        view->Add( drawing );
        m_toolMgr->RunAction( COMMON_ACTIONS::selectItem, true, drawing );
    }

    for( ZONE_CONTAINER* zone = board->GetArea( zonescount ); zone;
         zone = board->GetArea( zonescount ) )
    {
        picker.SetItem( zone );
        undoListPicker.PushItem( picker );
        zonescount++;
        view->Add( zone );
        m_toolMgr->RunAction( COMMON_ACTIONS::selectItem, true, zone );
    }

    if( undoListPicker.GetCount() == 0 )
        return 0;

    editFrame->SaveCopyInUndoList( undoListPicker, UR_NEW );

    // Synchronize layers
    // we should not ask PLUGINs to do these items:
    int copperLayerCount = board->GetCopperLayerCount();

    if( copperLayerCount > initialCopperLayerCount )
        board->SetCopperLayerCount( copperLayerCount );

    // Enable all used layers, and make them visible:
    LSET enabledLayers = board->GetEnabledLayers();
    enabledLayers |= initialEnabledLayers;
    board->SetEnabledLayers( enabledLayers );
    board->SetVisibleLayers( enabledLayers );
    editFrame->ReCreateLayerBox();
    editFrame->ReFillLayerWidget();
    static_cast<PCB_DRAW_PANEL_GAL*>( editFrame->GetGalCanvas() )->SyncLayersVisibility( board );

    // Ratsnest
    board->BuildListOfNets();
    board->SynchronizeNetsAndNetClasses();
    board->GetRatsnest()->Recalculate();

    // Start dragging the appended board
    VECTOR2D v( static_cast<BOARD_ITEM*>( undoListPicker.GetPickedItem( 0 ) )->GetPosition() );
    getViewControls()->WarpCursor( v, true, true );
    m_toolMgr->InvokeTool( "pcbnew.InteractiveEdit" );

    return 0;
}
bool PCB_EDIT_FRAME::AppendBoardFile( const wxString& aFullFileName, int aCtl )
{
    IO_MGR::PCB_FILE_T  pluginType = plugin_type( aFullFileName, aCtl );
    PLUGIN::RELEASER pi( IO_MGR::PluginFind( pluginType ) );

    // keep trace of existing items, in order to know what are the new items
    // (for undo command for instance)

    // Tracks are inserted, not append, so mark existing tracks to know what are
    // the new tracks
    for( TRACK* track = GetBoard()->m_Track; track; track = track->Next() )
        track->SetFlags( FLAG0 );

    // Other items are append to the item list, so keep trace to the
    // last existing item is enough
    MODULE* module = GetBoard()->m_Modules.GetLast();
    BOARD_ITEM* drawing = GetBoard()->m_Drawings.GetLast();
    int zonescount = GetBoard()->GetAreaCount();

    // Keep also the count of copper layers, because we can happen boards
    // with different copper layers counts,
    // and the enabled layers
    int initialCopperLayerCount = GetBoard()->GetCopperLayerCount();
    LSET initialEnabledLayers = GetBoard()->GetEnabledLayers();

    try
    {
        PROPERTIES  props;
        char        xbuf[30];
        char        ybuf[30];

        // EAGLE_PLUGIN can use this info to center the BOARD, but it does not yet.
        sprintf( xbuf, "%d", GetPageSizeIU().x );
        sprintf( ybuf, "%d", GetPageSizeIU().y );

        props["page_width"]  = xbuf;
        props["page_height"] = ybuf;

        GetDesignSettings().m_NetClasses.Clear();
        pi->Load( aFullFileName, GetBoard(), &props );
    }
    catch( const IO_ERROR& ioe )
    {
        for( TRACK* track = GetBoard()->m_Track; track; track = track->Next() )
            track->ClearFlags( FLAG0 );

        wxString msg = wxString::Format( _(
                "Error loading board.\n%s" ),
                GetChars( ioe.What() )
                );
        DisplayError( this, msg );

        return false;
    }

    // Now prepare a block move command to place the new items, and
    // prepare the undo command.
    BLOCK_SELECTOR& blockmove = GetScreen()->m_BlockLocate;
    HandleBlockBegin( NULL, BLOCK_PRESELECT_MOVE, wxPoint( 0, 0) );
    PICKED_ITEMS_LIST& blockitemsList = blockmove.GetItems();
    PICKED_ITEMS_LIST undoListPicker;
    ITEM_PICKER picker( NULL, UR_NEW );

    EDA_RECT bbox;          // the new items bounding box, for block move
    bool bboxInit = true;   // true until the bounding box is initialized

    for( TRACK* track = GetBoard()->m_Track; track; track = track->Next() )
    {
        if( track->GetFlags() & FLAG0  )
        {
            track->ClearFlags( FLAG0 );
            continue;
        }

        track->SetFlags( IS_MOVED );
        picker.SetItem( track );
        undoListPicker.PushItem( picker );
        blockitemsList.PushItem( picker );

        if( bboxInit )
            bbox = track->GetBoundingBox();
        else
            bbox.Merge( track->GetBoundingBox() );

        bboxInit = false;
    }

    if( module )
        module = module->Next();
    else
        module = GetBoard()->m_Modules;

    for( ; module; module = module->Next() )
    {
        module->SetFlags( IS_MOVED );
        picker.SetItem( module );
        undoListPicker.PushItem( picker );
        blockitemsList.PushItem( picker );

        if( bboxInit )
            bbox = module->GetBoundingBox();
        else
            bbox.Merge( module->GetBoundingBox() );

        bboxInit = false;
    }

    if( drawing )
        drawing = drawing->Next();
    else
        drawing = GetBoard()->m_Drawings;

    for( ; drawing; drawing = drawing->Next() )
    {
        drawing->SetFlags( IS_MOVED );
        picker.SetItem( drawing );
        undoListPicker.PushItem( picker );
        blockitemsList.PushItem( picker );

        if( bboxInit )
            bbox = drawing->GetBoundingBox();
        else
            bbox.Merge( drawing->GetBoundingBox() );

        bboxInit = false;
    }

    for( ZONE_CONTAINER* zone = GetBoard()->GetArea( zonescount ); zone;
         zone = GetBoard()->GetArea( zonescount ) )
    {
        zone->SetFlags( IS_MOVED );
        picker.SetItem( zone );
        undoListPicker.PushItem( picker );
        blockitemsList.PushItem( picker );
        zonescount++;

        if( bboxInit )
            bbox = zone->GetBoundingBox();
        else
            bbox.Merge( zone->GetBoundingBox() );

        bboxInit = false;
    }

    SaveCopyInUndoList( undoListPicker, UR_NEW );

    // we should not ask PLUGINs to do these items:
    int copperLayerCount = GetBoard()->GetCopperLayerCount();

    if( copperLayerCount > initialCopperLayerCount )
        GetBoard()->SetCopperLayerCount( copperLayerCount );

    // Enable all used layers, and make them visible:
    LSET enabledLayers = GetBoard()->GetEnabledLayers();
    enabledLayers |= initialEnabledLayers;
    GetBoard()->SetEnabledLayers( enabledLayers );
    GetBoard()->SetVisibleLayers( enabledLayers );
    ReCreateLayerBox();
    ReFillLayerWidget();

    if( IsGalCanvasActive() )
        static_cast<PCB_DRAW_PANEL_GAL*>( GetGalCanvas() )->SyncLayersVisibility( GetBoard() );

    GetBoard()->BuildListOfNets();
    GetBoard()->SynchronizeNetsAndNetClasses();

    SetStatusText( wxEmptyString );
    BestZoom();

    // Finish block move command:
    wxPoint cpos = GetNearestGridPosition( bbox.Centre() );
    blockmove.SetOrigin( bbox.GetOrigin() );
    blockmove.SetSize( bbox.GetSize() );
    blockmove.SetLastCursorPosition( cpos );
    HandleBlockEnd( NULL );

    return true;
}