Example #1
0
int ALIGN_DISTRIBUTE_TOOL::AlignCenterY( const TOOL_EVENT& aEvent )
{
    ALIGNMENT_RECTS itemsToAlign;
    ALIGNMENT_RECTS locked_items;

    if( !GetSelections( itemsToAlign, locked_items, []( const ALIGNMENT_RECT left, const ALIGNMENT_RECT right)
            { return ( left.second.GetCenter().y < right.second.GetCenter().y ); } ) )
        return 0;

    BOARD_COMMIT commit( m_frame );
    commit.StageItems( m_selectionTool->GetSelection(), CHT_MODIFY );
    auto targetY = selectTarget( itemsToAlign, locked_items, []( const ALIGNMENT_RECT& aVal )
            { return aVal.second.GetCenter().y; } );

    // Move the selected items
    for( auto& i : itemsToAlign )
    {
        int difference = targetY - i.second.GetCenter().y;
        BOARD_ITEM* item = i.first;

        // Don't move a pad by itself unless editing the footprint
        if( item->Type() == PCB_PAD_T && m_frame->IsType( FRAME_PCB ) )
            item = item->GetParent();

        item->Move( wxPoint( 0, difference ) );
    }

    commit.Push( _( "Align to center" ) );

    return 0;
}
int PLACEMENT_TOOL::AlignTop( const TOOL_EVENT& aEvent )
{
    const SELECTION& selection = m_selectionTool->GetSelection();

    if( selection.Size() <= 1 )
        return 0;

    BOARD_COMMIT commit( getEditFrame<PCB_BASE_FRAME>() );
    commit.Stage( selection.items, UR_CHANGED );

    // Compute the highest point of selection - it will be the edge of alignment
    int top = selection.Item<BOARD_ITEM>( 0 )->GetBoundingBox().GetY();

    for( int i = 1; i < selection.Size(); ++i )
    {
        int currentTop = selection.Item<BOARD_ITEM>( i )->GetBoundingBox().GetY();

        if( top > currentTop )      // Y decreases when going up
            top = currentTop;
    }

    // Move the selected items
    for( int i = 0; i < selection.Size(); ++i )
    {
        BOARD_ITEM* item = selection.Item<BOARD_ITEM>( i );
        int difference = top - item->GetBoundingBox().GetY();

        item->Move( wxPoint( 0, difference ) );
    }

    commit.Push( _( "Align to top" ) );

    return 0;
}
int PLACEMENT_TOOL::AlignRight( const TOOL_EVENT& aEvent )
{
    const SELECTION& selection = m_selectionTool->GetSelection();

    if( selection.Size() <= 1 )
        return 0;

    BOARD_COMMIT commit( getEditFrame<PCB_BASE_FRAME>() );
    commit.Stage( selection.items, UR_CHANGED );

    // Compute the rightmost point of selection - it will be the edge of alignment
    int right = selection.Item<BOARD_ITEM>( 0 )->GetBoundingBox().GetRight();

    for( int i = 1; i < selection.Size(); ++i )
    {
        int currentRight = selection.Item<BOARD_ITEM>( i )->GetBoundingBox().GetRight();

        if( right < currentRight )      // X increases when going right
            right = currentRight;
    }

    // Move the selected items
    for( int i = 0; i < selection.Size(); ++i )
    {
        BOARD_ITEM* item = selection.Item<BOARD_ITEM>( i );
        int difference = right - item->GetBoundingBox().GetRight();

        item->Move( wxPoint( difference, 0 ) );
    }

    commit.Push( _( "Align to right" ) );

    return 0;
}
Example #4
0
int EDIT_TOOL::MoveExact( const TOOL_EVENT& aEvent )
{
    const SELECTION& selection = m_selectionTool->GetSelection();

    // Shall the selection be cleared at the end?
    bool unselect = selection.Empty();

    if( !hoverSelection( selection ) )
        return 0;

    wxPoint translation;
    double rotation = 0;

    PCB_BASE_FRAME* editFrame = getEditFrame<PCB_BASE_FRAME>();

    DIALOG_MOVE_EXACT dialog( editFrame, translation, rotation );
    int ret = dialog.ShowModal();

    if( ret == wxID_OK )
    {
        if( !isUndoInhibited() )
        {
            editFrame->OnModify();
            // Record an action of move and rotate
            editFrame->SaveCopyInUndoList( selection.items, UR_CHANGED );
        }

        VECTOR2I rp = selection.GetCenter();
        wxPoint rotPoint( rp.x, rp.y );

        for( unsigned int i = 0; i < selection.items.GetCount(); ++i )
        {
            BOARD_ITEM* item = selection.Item<BOARD_ITEM>( i );

            item->Move( translation );
            item->Rotate( rotPoint, rotation );

            if( !m_dragging )
                item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
        }

        updateRatsnest( m_dragging );

        if( m_dragging )
            selection.group->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
        else
            getModel<BOARD>()->GetRatsnest()->Recalculate();

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

        m_toolMgr->RunAction( COMMON_ACTIONS::pointEditorUpdate, true );
    }

    return 0;
}
Example #5
0
void PCB_EDIT_FRAME::Block_Move()
{
    OnModify();

    wxPoint            MoveVector = GetScreen()->m_BlockLocate.GetMoveVector();

    PICKED_ITEMS_LIST* itemsList = &GetScreen()->m_BlockLocate.GetItems();
    itemsList->m_Status = UR_MOVED;

    for( unsigned ii = 0; ii < itemsList->GetCount(); ii++ )
    {
        BOARD_ITEM* item = (BOARD_ITEM*) itemsList->GetPickedItem( ii );
        itemsList->SetPickedItemStatus( UR_MOVED, ii );
        item->Move( MoveVector );
        GetBoard()->GetConnectivity()->Update( item );
        item->ClearFlags( IS_MOVED );

        switch( item->Type() )
        {
        case PCB_MODULE_T:
            m_Pcb->m_Status_Pcb = 0;
            item->ClearFlags();
            break;

        // Move track segments
        case PCB_TRACE_T:       // a track segment (segment on a copper layer)
        case PCB_VIA_T:         // a via (like a track segment on a copper layer)
            m_Pcb->m_Status_Pcb = 0;
            break;

        case PCB_ZONE_AREA_T:
        case PCB_LINE_T:
        case PCB_TEXT_T:
        case PCB_TARGET_T:
        case PCB_DIMENSION_T:
            break;

        // This item is not put in undo list
        case PCB_ZONE_T:        // SEG_ZONE items are now deprecated
            itemsList->RemovePicker( ii );
            ii--;
            break;

        default:
            wxMessageBox( wxT( "PCB_EDIT_FRAME::Block_Move( ) error: unexpected type" ) );
            break;
        }
    }

    SaveCopyInUndoList( *itemsList, UR_MOVED, MoveVector );

    Compile_Ratsnest( NULL, true );
    m_canvas->Refresh( true );
}
Example #6
0
void FOOTPRINT_EDIT_FRAME::moveExact()
{
    MOVE_PARAMETERS params;
    params.allowOverride = false;
    params.editingFootprint = true;

    DIALOG_MOVE_EXACT dialog( this, params );
    int ret = dialog.ShowModal();

    if( ret == wxID_OK )
    {
        SaveCopyInUndoList( GetBoard()->m_Modules, UR_CHANGED );

        BOARD_ITEM* item = GetScreen()->GetCurItem();

        wxPoint anchorPoint = item->GetPosition();
        wxPoint origin;

        switch( params.origin )
        {
        case RELATIVE_TO_USER_ORIGIN:
            origin = GetScreen()->m_O_Curseur;
            break;

        case RELATIVE_TO_GRID_ORIGIN:
            origin = GetGridOrigin();
            break;

        case RELATIVE_TO_DRILL_PLACE_ORIGIN:
            origin = GetAuxOrigin();
            break;

        case RELATIVE_TO_SHEET_ORIGIN:
            origin = wxPoint( 0, 0 );
            break;

        case RELATIVE_TO_CURRENT_POSITION:
            // relative movement means that only the translation values should be used:
            // -> set origin and anchor to zero
            origin = wxPoint( 0, 0 );
            anchorPoint = wxPoint( 0, 0 );
            break;
        }

        wxPoint finalMoveVector = params.translation + origin - anchorPoint;

        item->Move( finalMoveVector );
        item->Rotate( item->GetPosition(), params.rotation );
        m_canvas->Refresh();
    }

    m_canvas->MoveCursorToCrossHair();
}
Example #7
0
int EDIT_TOOL::MoveExact( const TOOL_EVENT& aEvent )
{
    const SELECTION& selection = m_selectionTool->GetSelection();

    // Shall the selection be cleared at the end?
    bool unselect = selection.Empty();

    if( !hoverSelection() || m_selectionTool->CheckLock() == SELECTION_LOCKED )
        return 0;

    wxPoint translation;
    double rotation = 0;

    PCB_BASE_FRAME* editFrame = getEditFrame<PCB_BASE_FRAME>();

    DIALOG_MOVE_EXACT dialog( editFrame, translation, rotation );
    int ret = dialog.ShowModal();

    if( ret == wxID_OK )
    {
        VECTOR2I rp = selection.GetCenter();
        wxPoint rotPoint( rp.x, rp.y );

        for( unsigned int i = 0; i < selection.items.GetCount(); ++i )
        {
            BOARD_ITEM* item = selection.Item<BOARD_ITEM>( i );

            m_commit->Modify( item );
            item->Move( translation );
            item->Rotate( rotPoint, rotation );

            if( !m_dragging )
                item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
        }

        m_commit->Push( _( "Move exact" ) );

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

        m_toolMgr->RunAction( COMMON_ACTIONS::editModifiedSelection, true );
    }

    return 0;
}
Example #8
0
void PCB_EDIT_FRAME::Block_Duplicate( bool aIncrement )
{
    wxPoint MoveVector = GetScreen()->m_BlockLocate.GetMoveVector();

    OnModify();

    PICKED_ITEMS_LIST* itemsList = &GetScreen()->m_BlockLocate.GetItems();

    PICKED_ITEMS_LIST newList;
    newList.m_Status = UR_NEW;

    ITEM_PICKER picker( NULL, UR_NEW );
    BOARD_ITEM* newitem;

    for( unsigned ii = 0; ii < itemsList->GetCount(); ii++ )
    {
        BOARD_ITEM* item = (BOARD_ITEM*) itemsList->GetPickedItem( ii );

        newitem = (BOARD_ITEM*)item->Clone();

        if( aIncrement )
            newitem->IncrementItemReference();

        if( item->Type() == PCB_MODULE_T )
            m_Pcb->m_Status_Pcb = 0;

        m_Pcb->Add( newitem );

        if( newitem )
        {
            newitem->Move( MoveVector );
            picker.SetItem ( newitem );
            newList.PushItem( picker );
        }
    }

    if( newList.GetCount() )
        SaveCopyInUndoList( newList, UR_NEW );

    Compile_Ratsnest( NULL, true );
    m_canvas->Refresh( true );
}
Example #9
0
void FOOTPRINT_EDIT_FRAME::moveExact()
{
    wxPoint translation;
    double rotation = 0;

    DIALOG_MOVE_EXACT dialog( this, translation, rotation );
    int ret = dialog.ShowModal();

    if( ret == wxID_OK )
    {
        SaveCopyInUndoList( GetBoard()->m_Modules, UR_MODEDIT );

        BOARD_ITEM* item = GetScreen()->GetCurItem();

        item->Move( translation );
        item->Rotate( item->GetPosition(), rotation );
        m_canvas->Refresh();
    }

    m_canvas->MoveCursorToCrossHair();
}
Example #10
0
void ALIGN_DISTRIBUTE_TOOL::doDistributeCentersVertically( ALIGNMENT_RECTS& itemsToDistribute ) const
{
    std::sort( itemsToDistribute.begin(), itemsToDistribute.end(),
        [] ( const ALIGNMENT_RECT left, const ALIGNMENT_RECT right)
        { return ( left.second.GetCenter().y < right.second.GetCenter().y ); } );
    const auto totalGap = ( itemsToDistribute.end()-1 )->second.GetCenter().y
                          - itemsToDistribute.begin()->second.GetCenter().y;
    const auto itemGap = totalGap / ( itemsToDistribute.size() - 1 );
    auto targetY = itemsToDistribute.begin()->second.GetCenter().y;

    for( auto& i : itemsToDistribute )
    {
        BOARD_ITEM* item = i.first;

        // Don't move a pad by itself unless editing the footprint
        if( item->Type() == PCB_PAD_T && m_frame->IsType( FRAME_PCB ) )
            item = item->GetParent();

        int difference = targetY - i.second.GetCenter().y;
        item->Move( wxPoint( 0, difference ) );
        targetY += ( itemGap );
    }
}
Example #11
0
void ALIGN_DISTRIBUTE_TOOL::doDistributeGapsHorizontally( ALIGNMENT_RECTS& itemsToDistribute,
                                                          const BOARD_ITEM* lastItem, int totalGap ) const
{
    const auto itemGap = totalGap / ( itemsToDistribute.size() - 1 );
    auto targetX = itemsToDistribute.begin()->second.GetX();

    for( auto& i : itemsToDistribute )
    {
        BOARD_ITEM* item = i.first;

        // cover the corner case where the last item is wider than the previous item and gap
        if( lastItem == item )
            continue;

        // Don't move a pad by itself unless editing the footprint
        if( item->Type() == PCB_PAD_T && m_frame->IsType( FRAME_PCB ) )
            item = item->GetParent();

        int difference = targetX - i.second.GetX();
        item->Move( wxPoint( difference, 0 ) );
        targetX += ( i.second.GetWidth() + itemGap );
    }
}
Example #12
0
void PCB_BASE_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRedoCommand,
                                             bool aRebuildRatsnet )
{
    BOARD_ITEM* item;
    bool        not_found = false;
    bool        reBuild_ratsnest = false;
    bool        deep_reBuild_ratsnest = false;  // true later if pointers must be rebuilt

    auto view = GetGalCanvas()->GetView();
    auto connectivity = GetBoard()->GetConnectivity();

    // Undo in the reverse order of list creation: (this can allow stacked changes
    // like the same item can be changes and deleted in the same complex command

    bool build_item_list = true;    // if true the list of existing items must be rebuilt

    // Restore changes in reverse order
    for( int ii = aList->GetCount() - 1; ii >= 0 ; ii-- )
    {
        item = (BOARD_ITEM*) aList->GetPickedItem( ii );
        wxASSERT( item );

        /* Test for existence of item on board.
         * It could be deleted, and no more on board:
         *   - if a call to SaveCopyInUndoList was forgotten in Pcbnew
         *   - in zones outlines, when a change in one zone merges this zone with an other
         * This test avoids a Pcbnew crash
         * Obviously, this test is not made for deleted items
         */
        UNDO_REDO_T status = aList->GetPickedItemStatus( ii );

        if( status != UR_DELETED
                && status != UR_DRILLORIGIN     // origin markers never on board
                && status != UR_GRIDORIGIN )    // origin markers never on board
        {
            if( build_item_list )
                // Build list of existing items, for integrity test
                TestForExistingItem( GetBoard(), NULL );

            build_item_list = false;

            if( !TestForExistingItem( GetBoard(), item ) )
            {
                // Checking if it ever happens
                wxASSERT_MSG( false, "Item in the undo buffer does not exist" );

                // Remove this non existent item
                aList->RemovePicker( ii );
                ii++;       // the current item was removed, ii points now the next item
                            // decrement it because it will be incremented later
                not_found = true;
                continue;
            }
        }

        item->ClearFlags();

        // see if we must rebuild ratsnets and pointers lists
        switch( item->Type() )
        {
        case PCB_MODULE_T:
            deep_reBuild_ratsnest = true;   // Pointers on pads can be invalid
            // Fall through
        case PCB_ZONE_AREA_T:
        case PCB_TRACE_T:
        case PCB_VIA_T:
            reBuild_ratsnest = true;
            break;

        case PCB_NETINFO_T:
            reBuild_ratsnest = true;
            deep_reBuild_ratsnest = true;
            break;

        default:
            break;
        }

        // It is possible that we are going to replace the selected item, so clear it
        SetCurItem( NULL );

        switch( aList->GetPickedItemStatus( ii ) )
        {
        case UR_CHANGED:    /* Exchange old and new data for each item */
        {
            BOARD_ITEM* image = (BOARD_ITEM*) aList->GetPickedItemLink( ii );

            // Remove all pads/drawings/texts, as they become invalid
            // for the VIEW after SwapData() called for modules
            view->Remove( item );
            connectivity->Remove( item );

            SwapItemData( item, image );

            // Update all pads/drawings/texts, as they become invalid
            // for the VIEW after SwapData() called for modules
            if( item->Type() == PCB_MODULE_T )
            {
                MODULE* newModule = static_cast<MODULE*>( item );
                newModule->RunOnChildren( std::bind( &BOARD_ITEM::ClearFlags, _1, EDA_ITEM_ALL_FLAGS ));
            }

            view->Add( item );
            connectivity->Add( item );
            item->ClearFlags();

        }
        break;

        case UR_NEW:        /* new items are deleted */
            aList->SetPickedItemStatus( UR_DELETED, ii );
            GetModel()->Remove( item );
            view->Remove( item );
            break;

        case UR_DELETED:    /* deleted items are put in List, as new items */
            aList->SetPickedItemStatus( UR_NEW, ii );
            GetModel()->Add( item );
            view->Add( item );
            build_item_list = true;
            break;

        case UR_MOVED:
            item->Move( aRedoCommand ? aList->m_TransformPoint : -aList->m_TransformPoint );
            view->Update( item, KIGFX::GEOMETRY );
            connectivity->Update( item );
            break;

        case UR_ROTATED:
            item->Rotate( aList->m_TransformPoint,
                          aRedoCommand ? m_rotationAngle : -m_rotationAngle );
            view->Update( item, KIGFX::GEOMETRY );
            connectivity->Update( item );
            break;

        case UR_ROTATED_CLOCKWISE:
            item->Rotate( aList->m_TransformPoint,
                          aRedoCommand ? -m_rotationAngle : m_rotationAngle );
            view->Update( item, KIGFX::GEOMETRY );
            connectivity->Update( item );
            break;

        case UR_FLIPPED:
            item->Flip( aList->m_TransformPoint );
            view->Update( item, KIGFX::LAYERS );
            connectivity->Update( item );
            break;

        case UR_DRILLORIGIN:
        case UR_GRIDORIGIN:
        {
            BOARD_ITEM* image = (BOARD_ITEM*) aList->GetPickedItemLink( ii );
            VECTOR2D origin = image->GetPosition();
            image->SetPosition( item->GetPosition() );

            if( aList->GetPickedItemStatus( ii ) == UR_DRILLORIGIN )
                PCB_EDITOR_CONTROL::DoSetDrillOrigin( view, this, item, origin );
            else
                PCBNEW_CONTROL::DoSetGridOrigin( view, this, item, origin );
        }
        break;

        default:
        {
            wxLogDebug( wxT( "PutDataInPreviousState() error (unknown code %X)" ),
                        aList->GetPickedItemStatus( ii ) );
        }
        break;
        }
    }

    if( not_found )
        wxMessageBox( _( "Incomplete undo/redo operation: some items not found" ) );
    
    // Rebuild pointers and connectivity that can be changed.
    // connectivity can be rebuilt only in the board editor frame
    if( IsType( FRAME_PCB ) && ( reBuild_ratsnest || deep_reBuild_ratsnest ) )
    {
        Compile_Ratsnest( NULL, false );
    }

    GetBoard()->SanitizeNetcodes();
}
void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRedoCommand,
                                             bool aRebuildRatsnet )
{
    BOARD_ITEM* item;
    bool        not_found = false;
    bool        reBuild_ratsnest = false;
    KIGFX::VIEW* view = GetGalCanvas()->GetView();
    RN_DATA* ratsnest = GetBoard()->GetRatsnest();

    // Undo in the reverse order of list creation: (this can allow stacked changes
    // like the same item can be changes and deleted in the same complex command

    bool build_item_list = true;    // if true the list of existing items must be rebuilt

    for( int ii = aList->GetCount() - 1; ii >= 0 ; ii-- )
    {
        item = (BOARD_ITEM*) aList->GetPickedItem( ii );
        wxASSERT( item );

        /* Test for existence of item on board.
         * It could be deleted, and no more on board:
         *   - if a call to SaveCopyInUndoList was forgotten in Pcbnew
         *   - in zones outlines, when a change in one zone merges this zone with an other
         * This test avoids a Pcbnew crash
         * Obviously, this test is not made for deleted items
         */
        UNDO_REDO_T status = aList->GetPickedItemStatus( ii );

        if( status != UR_DELETED )
        {
            if( build_item_list )
                // Build list of existing items, for integrity test
                TestForExistingItem( GetBoard(), NULL );

            build_item_list = false;

            if( !TestForExistingItem( GetBoard(), item ) )
            {
                // Remove this non existent item
                aList->RemovePicker( ii );
                ii++;       // the current item was removed, ii points now the next item
                            // decrement it because it will be incremented later
                not_found = true;
                continue;
            }
        }

        item->ClearFlags();

        // see if we must rebuild ratsnets and pointers lists
        switch( item->Type() )
        {
        case PCB_MODULE_T:
        case PCB_ZONE_AREA_T:
        case PCB_TRACE_T:
        case PCB_VIA_T:
            reBuild_ratsnest = true;
            break;

        default:
            break;
        }

        switch( aList->GetPickedItemStatus( ii ) )
        {
        case UR_CHANGED:    /* Exchange old and new data for each item */
        {
            BOARD_ITEM* image = (BOARD_ITEM*) aList->GetPickedItemLink( ii );

            // Remove all pads/drawings/texts, as they become invalid
            // for the VIEW after SwapData() called for modules
            if( item->Type() == PCB_MODULE_T )
            {
                MODULE* oldModule = static_cast<MODULE*>( item );
                oldModule->RunOnChildren( boost::bind( &KIGFX::VIEW::Remove, view, _1 ) );
            }
            ratsnest->Remove( item );

            item->SwapData( image );

            // Update all pads/drawings/texts, as they become invalid
            // for the VIEW after SwapData() called for modules
            if( item->Type() == PCB_MODULE_T )
            {
                MODULE* newModule = static_cast<MODULE*>( item );
                newModule->RunOnChildren( boost::bind( &KIGFX::VIEW::Add, view, _1 ) );
            }
            ratsnest->Add( item );

            item->ClearFlags( SELECTED );
            item->ViewUpdate( KIGFX::VIEW_ITEM::LAYERS );
        }
        break;

        case UR_NEW:        /* new items are deleted */
            aList->SetPickedItemStatus( UR_DELETED, ii );
            GetBoard()->Remove( item );

            if( item->Type() == PCB_MODULE_T )
            {
                MODULE* module = static_cast<MODULE*>( item );
                module->RunOnChildren( boost::bind( &KIGFX::VIEW::Remove, view, _1 ) );
            }
            view->Remove( item );

            item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
            break;

        case UR_DELETED:    /* deleted items are put in List, as new items */
            aList->SetPickedItemStatus( UR_NEW, ii );
            GetBoard()->Add( item );

            if( item->Type() == PCB_MODULE_T )
            {
                MODULE* module = static_cast<MODULE*>( item );
                module->RunOnChildren( boost::bind( &KIGFX::VIEW::Add, view, _1) );
            }
            view->Add( item );

            item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
            build_item_list = true;
            break;

        case UR_MOVED:
            item->Move( aRedoCommand ? aList->m_TransformPoint : -aList->m_TransformPoint );
            item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
            ratsnest->Update( item );
            break;

        case UR_ROTATED:
            item->Rotate( aList->m_TransformPoint,
                          aRedoCommand ? m_rotationAngle : -m_rotationAngle );
            item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
            ratsnest->Update( item );
            break;

        case UR_ROTATED_CLOCKWISE:
            item->Rotate( aList->m_TransformPoint,
                          aRedoCommand ? -m_rotationAngle : m_rotationAngle );
            item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
            ratsnest->Update( item );
            break;

        case UR_FLIPPED:
            item->Flip( aList->m_TransformPoint );
            item->ViewUpdate( KIGFX::VIEW_ITEM::LAYERS );
            ratsnest->Update( item );
            break;

        default:
        {
            wxString msg;
            msg.Printf( wxT( "PutDataInPreviousState() error (unknown code %X)" ),
                        aList->GetPickedItemStatus( ii ) );
            wxMessageBox( msg );
        }
        break;
        }
    }

    if( not_found )
        wxMessageBox( wxT( "Incomplete undo/redo operation: some items not found" ) );

    // Rebuild pointers and ratsnest that can be changed.
    if( reBuild_ratsnest && aRebuildRatsnet )
    {
        if( IsGalCanvasActive() )
            ratsnest->Recalculate();
        else
            Compile_Ratsnest( NULL, true );
    }
}
int DRAWING_TOOL::PlaceDXF( const TOOL_EVENT& aEvent )
{
    DIALOG_DXF_IMPORT dlg( m_frame );
    int dlgResult = dlg.ShowModal();

    const std::list<BOARD_ITEM*>& list = dlg.GetImportedItems();

    if( dlgResult != wxID_OK || m_board->m_Modules == NULL || list.empty() )
        return 0;

    VECTOR2I cursorPos = m_controls->GetCursorPosition();
    VECTOR2I delta = cursorPos - (*list.begin())->GetPosition();

    // Add a VIEW_GROUP that serves as a preview for the new item
    KIGFX::VIEW_GROUP preview( m_view );

    // Build the undo list & add items to the current view
    std::list<BOARD_ITEM*>::const_iterator it, itEnd;
    for( it = list.begin(), itEnd = list.end(); it != itEnd; ++it )
    {
        BOARD_ITEM* item = *it;
        BOARD_ITEM* converted = NULL;

        // Modules use different types for the same things,
        // so we need to convert imported items to appropriate classes.
        switch( item->Type() )
        {
        case PCB_LINE_T:
        {
            if( m_editModules )
            {
                converted = new EDGE_MODULE( m_board->m_Modules );
                *static_cast<DRAWSEGMENT*>( converted ) = *static_cast<DRAWSEGMENT*>( item );
                converted->Move( wxPoint( delta.x, delta.y ) );
                preview.Add( converted );
                delete item;
            }
            else
            {
                preview.Add( item );
            }

            break;
        }

        case PCB_TEXT_T:
        {
            if( m_editModules )
            {
                converted = new TEXTE_MODULE( m_board->m_Modules );
                *static_cast<TEXTE_PCB*>( converted ) = *static_cast<TEXTE_PCB*>( item );
                converted->Move( wxPoint( delta.x, delta.y ) );
                preview.Add( converted );
                delete item;
            }
            else
            {
                preview.Add( item );
            }
            break;
        }

        default:
            assert( false );    // there is a type that is currently not handled here
            break;
        }
    }

    BOARD_ITEM* firstItem = static_cast<BOARD_ITEM*>( *preview.Begin() );
    m_view->Add( &preview );

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

    Activate();

    // Main loop: keep receiving events
    while( OPT_TOOL_EVENT evt = Wait() )
    {
        cursorPos = m_controls->GetCursorPosition();

        if( evt->IsMotion() )
        {
            delta = cursorPos - firstItem->GetPosition();

            for( KIGFX::VIEW_GROUP::iter it = preview.Begin(), end = preview.End(); it != end; ++it )
                static_cast<BOARD_ITEM*>( *it )->Move( wxPoint( delta.x, delta.y ) );

            preview.ViewUpdate();
        }

        else if( evt->Category() == TC_COMMAND )
        {
            if( evt->IsAction( &COMMON_ACTIONS::rotate ) )
            {
                for( KIGFX::VIEW_GROUP::iter it = preview.Begin(), end = preview.End(); it != end; ++it )
                    static_cast<BOARD_ITEM*>( *it )->Rotate( wxPoint( cursorPos.x, cursorPos.y ),
                                                             m_frame->GetRotationAngle() );

                preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
            }
            else if( evt->IsAction( &COMMON_ACTIONS::flip ) )
            {
                for( KIGFX::VIEW_GROUP::iter it = preview.Begin(), end = preview.End(); it != end; ++it )
                    static_cast<BOARD_ITEM*>( *it )->Flip( wxPoint( cursorPos.x, cursorPos.y ) );

                preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
            }
            else if( evt->IsCancel() || evt->IsActivate() )
            {
                preview.FreeItems();
                break;
            }
        }

        else if( evt->IsClick( BUT_LEFT ) )
        {
            // Place the drawing
            if( m_editModules )
            {
                m_frame->SaveCopyInUndoList( m_board->m_Modules, UR_MODEDIT );
                m_board->m_Modules->SetLastEditTime();

                for( KIGFX::VIEW_GROUP::iter it = preview.Begin(), end = preview.End(); it != end; ++it )
                {
                    BOARD_ITEM* item = static_cast<BOARD_ITEM*>( *it );
                    m_board->m_Modules->Add( item );

                    switch( item->Type() )
                    {
                    case PCB_MODULE_TEXT_T:
                        static_cast<TEXTE_MODULE*>( item )->SetLocalCoord();
                        break;

                    case PCB_MODULE_EDGE_T:
                        static_cast<EDGE_MODULE*>( item )->SetLocalCoord();
                        break;

                    default:
                        assert( false );
                        break;
                    }

                    m_view->Add( item );
                }
            }
            else
            {
                PICKED_ITEMS_LIST picklist;

                for( KIGFX::VIEW_GROUP::iter it = preview.Begin(), end = preview.End(); it != end; ++it )
                {
                    BOARD_ITEM* item = static_cast<BOARD_ITEM*>( *it );
                    m_board->Add( item );

                    ITEM_PICKER itemWrapper( item, UR_NEW );
                    picklist.PushItem( itemWrapper );

                    m_view->Add( item );
                }

                m_frame->SaveCopyInUndoList( picklist, UR_NEW );
            }

            m_frame->OnModify();

            break;
        }
    }

    preview.Clear();

    m_controls->ShowCursor( false );
    m_controls->SetSnapping( false );
    m_controls->SetAutoPan( false );
    m_controls->CaptureCursor( false );
    m_view->Remove( &preview );

    return 0;
}
/**
 * Function PutDataInPreviousState
 * Used in undo or redo command.
 * Put data pointed by List in the previous state, i.e. the state memorised by List
 * @param aList = a PICKED_ITEMS_LIST pointer to the list of items to undo/redo
 * @param aRedoCommand = a bool: true for redo, false for undo
 * @param aRebuildRatsnet = a bool: true to rebuid ratsnet (normal use, and default), false
 * to just retrieve las state (used in abort commands that do not need to rebuild ratsnest)
 */
void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRedoCommand,
                                             bool aRebuildRatsnet )
{
    BOARD_ITEM* item;
    bool        not_found = false;
    bool        reBuild_ratsnest = false;

    // Undo in the reverse order of list creation: (this can allow stacked changes
    // like the same item can be changes and deleted in the same complex command

    bool build_item_list = true;    // if true the list of esiting items must be rebuilt
    for( int ii = aList->GetCount()-1; ii >= 0 ; ii--  )
    {
        item = (BOARD_ITEM*) aList->GetPickedItem( ii );
        wxASSERT( item );

        /* Test for existence of item on board.
         * It could be deleted, and no more on board:
         *   - if a call to SaveCopyInUndoList was forgotten in Pcbnew
         *   - in zones outlines, when a change in one zone merges this zone with an other
         * This test avoids a Pcbnew crash
         * Obviouly, this test is not made for deleted items
         */
        UNDO_REDO_T status = aList->GetPickedItemStatus( ii );
        if( status != UR_DELETED )
        {
            if( build_item_list )
                // Build list of existing items, for integrity test
                TestForExistingItem( GetBoard(), NULL );
            build_item_list = false;

            if( !TestForExistingItem( GetBoard(), item ) )
            {
                // Remove this non existant item
                aList->RemovePicker( ii );
                ii++;       // the current item was removed, ii points now the next item
                            // decrement it because it will be incremented later
                not_found = true;
                continue;
            }
        }

        item->ClearFlags();

        // see if we must rebuild ratsnets and pointers lists
        switch( item->Type() )
        {
        case PCB_MODULE_T:
        case PCB_ZONE_AREA_T:
        case PCB_TRACE_T:
        case PCB_VIA_T:
            reBuild_ratsnest = true;
            break;

        default:
            break;
        }

        switch( aList->GetPickedItemStatus( ii ) )
        {
        case UR_CHANGED:    /* Exchange old and new data for each item */
        {
            BOARD_ITEM* image = (BOARD_ITEM*) aList->GetPickedItemLink( ii );
            SwapData( item, image );
        }
        break;

        case UR_NEW:        /* new items are deleted */
            aList->SetPickedItemStatus( UR_DELETED, ii );
            GetBoard()->Remove( item );
            break;

        case UR_DELETED:    /* deleted items are put in List, as new items */
            aList->SetPickedItemStatus( UR_NEW, ii );
            GetBoard()->Add( item );
            build_item_list = true;
            break;

        case UR_MOVED:
            item->Move( aRedoCommand ? aList->m_TransformPoint : -aList->m_TransformPoint );
            break;

        case UR_ROTATED:
            item->Rotate( aList->m_TransformPoint, aRedoCommand ? 900 : -900 );
            break;

        case UR_ROTATED_CLOCKWISE:
            item->Rotate( aList->m_TransformPoint, aRedoCommand ? -900 : 900 );
            break;

        case UR_FLIPPED:
            item->Flip( aList->m_TransformPoint );
            break;

        default:
        {
            wxString msg;
            msg.Printf( wxT( "PutDataInPreviousState() error (unknown code %X)" ),
                        aList->GetPickedItemStatus( ii ) );
            wxMessageBox( msg );
        }
        break;
        }
    }

    if( not_found )
        wxMessageBox( wxT( "Incomplete undo/redo operation: some items not found" ) );

    // Rebuild pointers and rastnest that can be changed.
    if( reBuild_ratsnest && aRebuildRatsnet )
        Compile_Ratsnest( NULL, true );
}